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