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
  50int 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 KSFT_FAIL;
  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 KSFT_FAIL;
  67        }
  68        if (!WIFSTOPPED(status)) {
  69                ksft_print_msg("child did not stop: %s\n", strerror(errno));
  70                return KSFT_FAIL;
  71        }
  72        if (WSTOPSIG(status) != SIGSTOP) {
  73                ksft_print_msg("child did not stop with SIGSTOP: %s\n",
  74                        strerror(errno));
  75                return KSFT_FAIL;
  76        }
  77
  78        if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) {
  79                if (errno == EIO) {
  80                        ksft_print_msg(
  81                                "ptrace(PTRACE_SINGLESTEP) not supported on this architecture: %s\n",
  82                                strerror(errno));
  83                        return KSFT_SKIP;
  84                }
  85                ksft_print_msg("ptrace(PTRACE_SINGLESTEP) failed: %s\n",
  86                        strerror(errno));
  87                return KSFT_FAIL;
  88        }
  89
  90        wpid = waitpid(pid, &status, __WALL);
  91        if (wpid != pid) {
  92                ksft_print_msg("waitpid() failed: $s\n", strerror(errno));
  93                return KSFT_FAIL;
  94        }
  95        if (WIFEXITED(status)) {
  96                ksft_print_msg("child did not single-step: %s\n",
  97                        strerror(errno));
  98                return KSFT_FAIL;
  99        }
 100        if (!WIFSTOPPED(status)) {
 101                ksft_print_msg("child did not stop: %s\n", strerror(errno));
 102                return KSFT_FAIL;
 103        }
 104        if (WSTOPSIG(status) != SIGTRAP) {
 105                ksft_print_msg("child did not stop with SIGTRAP: %s\n",
 106                        strerror(errno));
 107                return KSFT_FAIL;
 108        }
 109
 110        if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
 111                ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n",
 112                        strerror(errno));
 113                return KSFT_FAIL;
 114        }
 115
 116        wpid = waitpid(pid, &status, __WALL);
 117        if (wpid != pid) {
 118                ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
 119                return KSFT_FAIL;
 120        }
 121        if (!WIFEXITED(status)) {
 122                ksft_print_msg("child did not exit after PTRACE_CONT: %s\n",
 123                        strerror(errno));
 124                return KSFT_FAIL;
 125        }
 126
 127        return KSFT_PASS;
 128}
 129
 130void suspend(void)
 131{
 132        int power_state_fd;
 133        struct sigevent event = {};
 134        int timerfd;
 135        int err;
 136        struct itimerspec spec = {};
 137
 138        if (getuid() != 0)
 139                ksft_exit_skip("Please run the test as root - Exiting.\n");
 140
 141        power_state_fd = open("/sys/power/state", O_RDWR);
 142        if (power_state_fd < 0)
 143                ksft_exit_fail_msg(
 144                        "open(\"/sys/power/state\") failed %s)\n",
 145                        strerror(errno));
 146
 147        timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);
 148        if (timerfd < 0)
 149                ksft_exit_fail_msg("timerfd_create() failed\n");
 150
 151        spec.it_value.tv_sec = 5;
 152        err = timerfd_settime(timerfd, 0, &spec, NULL);
 153        if (err < 0)
 154                ksft_exit_fail_msg("timerfd_settime() failed\n");
 155
 156        if (write(power_state_fd, "mem", strlen("mem")) != strlen("mem"))
 157                ksft_exit_fail_msg("Failed to enter Suspend state\n");
 158
 159        close(timerfd);
 160        close(power_state_fd);
 161}
 162
 163int main(int argc, char **argv)
 164{
 165        int opt;
 166        bool do_suspend = true;
 167        bool succeeded = true;
 168        unsigned int tests = 0;
 169        cpu_set_t available_cpus;
 170        int err;
 171        int cpu;
 172
 173        ksft_print_header();
 174
 175        while ((opt = getopt(argc, argv, "n")) != -1) {
 176                switch (opt) {
 177                case 'n':
 178                        do_suspend = false;
 179                        break;
 180                default:
 181                        printf("Usage: %s [-n]\n", argv[0]);
 182                        printf("        -n: do not trigger a suspend/resume cycle before the test\n");
 183                        return -1;
 184                }
 185        }
 186
 187        err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus);
 188        if (err < 0)
 189                ksft_exit_fail_msg("sched_getaffinity() failed\n");
 190
 191        for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
 192                if (!CPU_ISSET(cpu, &available_cpus))
 193                        continue;
 194                tests++;
 195        }
 196
 197        if (do_suspend)
 198                suspend();
 199
 200        ksft_set_plan(tests);
 201        for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
 202                int test_success;
 203
 204                if (!CPU_ISSET(cpu, &available_cpus))
 205                        continue;
 206
 207                test_success = run_test(cpu);
 208                switch (test_success) {
 209                case KSFT_PASS:
 210                        ksft_test_result_pass("CPU %d\n", cpu);
 211                        break;
 212                case KSFT_SKIP:
 213                        ksft_test_result_skip("CPU %d\n", cpu);
 214                        break;
 215                case KSFT_FAIL:
 216                        ksft_test_result_fail("CPU %d\n", cpu);
 217                        succeeded = false;
 218                        break;
 219                }
 220        }
 221
 222        if (succeeded)
 223                ksft_exit_pass();
 224        else
 225                ksft_exit_fail();
 226}
 227