linux/tools/testing/selftests/breakpoints/step_after_suspend_test.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2016 Google, Inc.
   3 *
   4 * This software is licensed under the terms of the GNU General Public
   5 * License version 2, as published by the Free Software Foundation, and
   6 * may be copied, distributed, and modified under those terms.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 *
  13 */
  14
  15#define _GNU_SOURCE
  16
  17#include <errno.h>
  18#include <fcntl.h>
  19#include <sched.h>
  20#include <signal.h>
  21#include <stdbool.h>
  22#include <stdio.h>
  23#include <string.h>
  24#include <unistd.h>
  25#include <sys/ptrace.h>
  26#include <sys/stat.h>
  27#include <sys/timerfd.h>
  28#include <sys/types.h>
  29#include <sys/wait.h>
  30
  31#include "../kselftest.h"
  32
  33void child(int cpu)
  34{
  35        cpu_set_t set;
  36
  37        CPU_ZERO(&set);
  38        CPU_SET(cpu, &set);
  39        if (sched_setaffinity(0, sizeof(set), &set) != 0) {
  40                ksft_print_msg("sched_setaffinity() failed: %s\n",
  41                        strerror(errno));
  42                _exit(1);
  43        }
  44
  45        if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) {
  46                ksft_print_msg("ptrace(PTRACE_TRACEME) failed: %s\n",
  47                        strerror(errno));
  48                _exit(1);
  49        }
  50
  51        if (raise(SIGSTOP) != 0) {
  52                ksft_print_msg("raise(SIGSTOP) failed: %s\n", strerror(errno));
  53                _exit(1);
  54        }
  55
  56        _exit(0);
  57}
  58
  59bool run_test(int cpu)
  60{
  61        int status;
  62        pid_t pid = fork();
  63        pid_t wpid;
  64
  65        if (pid < 0) {
  66                ksft_print_msg("fork() failed: %s\n", strerror(errno));
  67                return false;
  68        }
  69        if (pid == 0)
  70                child(cpu);
  71
  72        wpid = waitpid(pid, &status, __WALL);
  73        if (wpid != pid) {
  74                ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
  75                return false;
  76        }
  77        if (!WIFSTOPPED(status)) {
  78                ksft_print_msg("child did not stop: %s\n", strerror(errno));
  79                return false;
  80        }
  81        if (WSTOPSIG(status) != SIGSTOP) {
  82                ksft_print_msg("child did not stop with SIGSTOP: %s\n",
  83                        strerror(errno));
  84                return false;
  85        }
  86
  87        if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) {
  88                if (errno == EIO) {
  89                        ksft_exit_skip(
  90                                "ptrace(PTRACE_SINGLESTEP) not supported on this architecture: %s\n",
  91                                strerror(errno));
  92                }
  93                ksft_print_msg("ptrace(PTRACE_SINGLESTEP) failed: %s\n",
  94                        strerror(errno));
  95                return false;
  96        }
  97
  98        wpid = waitpid(pid, &status, __WALL);
  99        if (wpid != pid) {
 100                ksft_print_msg("waitpid() failed: $s\n", strerror(errno));
 101                return false;
 102        }
 103        if (WIFEXITED(status)) {
 104                ksft_print_msg("child did not single-step: %s\n",
 105                        strerror(errno));
 106                return false;
 107        }
 108        if (!WIFSTOPPED(status)) {
 109                ksft_print_msg("child did not stop: %s\n", strerror(errno));
 110                return false;
 111        }
 112        if (WSTOPSIG(status) != SIGTRAP) {
 113                ksft_print_msg("child did not stop with SIGTRAP: %s\n",
 114                        strerror(errno));
 115                return false;
 116        }
 117
 118        if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
 119                ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n",
 120                        strerror(errno));
 121                return false;
 122        }
 123
 124        wpid = waitpid(pid, &status, __WALL);
 125        if (wpid != pid) {
 126                ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
 127                return false;
 128        }
 129        if (!WIFEXITED(status)) {
 130                ksft_print_msg("child did not exit after PTRACE_CONT: %s\n",
 131                        strerror(errno));
 132                return false;
 133        }
 134
 135        return true;
 136}
 137
 138void suspend(void)
 139{
 140        int power_state_fd;
 141        struct sigevent event = {};
 142        int timerfd;
 143        int err;
 144        struct itimerspec spec = {};
 145
 146        power_state_fd = open("/sys/power/state", O_RDWR);
 147        if (power_state_fd < 0)
 148                ksft_exit_fail_msg(
 149                        "open(\"/sys/power/state\") failed (is this test running as root?)\n");
 150
 151        timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);
 152        if (timerfd < 0)
 153                ksft_exit_fail_msg("timerfd_create() failed\n");
 154
 155        spec.it_value.tv_sec = 5;
 156        err = timerfd_settime(timerfd, 0, &spec, NULL);
 157        if (err < 0)
 158                ksft_exit_fail_msg("timerfd_settime() failed\n");
 159
 160        if (write(power_state_fd, "mem", strlen("mem")) != strlen("mem"))
 161                ksft_exit_fail_msg("Failed to enter Suspend state\n");
 162
 163        close(timerfd);
 164        close(power_state_fd);
 165}
 166
 167int main(int argc, char **argv)
 168{
 169        int opt;
 170        bool do_suspend = true;
 171        bool succeeded = true;
 172        cpu_set_t available_cpus;
 173        int err;
 174        int cpu;
 175
 176        ksft_print_header();
 177
 178        while ((opt = getopt(argc, argv, "n")) != -1) {
 179                switch (opt) {
 180                case 'n':
 181                        do_suspend = false;
 182                        break;
 183                default:
 184                        printf("Usage: %s [-n]\n", argv[0]);
 185                        printf("        -n: do not trigger a suspend/resume cycle before the test\n");
 186                        return -1;
 187                }
 188        }
 189
 190        if (do_suspend)
 191                suspend();
 192
 193        err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus);
 194        if (err < 0)
 195                ksft_exit_fail_msg("sched_getaffinity() failed\n");
 196
 197        for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
 198                bool test_success;
 199
 200                if (!CPU_ISSET(cpu, &available_cpus))
 201                        continue;
 202
 203                test_success = run_test(cpu);
 204                if (test_success) {
 205                        ksft_test_result_pass("CPU %d\n", cpu);
 206                } else {
 207                        ksft_test_result_fail("CPU %d\n", cpu);
 208                        succeeded = false;
 209                }
 210        }
 211
 212        if (succeeded)
 213                ksft_exit_pass();
 214        else
 215                ksft_exit_fail();
 216}
 217