Path: blob/master/tools/testing/selftests/breakpoints/step_after_suspend_test.c
26285 views
// SPDX-License-Identifier: GPL-2.0-only1/*2* Copyright (C) 2016 Google, Inc.3*/45#define _GNU_SOURCE67#include <errno.h>8#include <fcntl.h>9#include <sched.h>10#include <signal.h>11#include <stdbool.h>12#include <stdio.h>13#include <string.h>14#include <unistd.h>15#include <sys/ptrace.h>16#include <sys/stat.h>17#include <sys/timerfd.h>18#include <sys/types.h>19#include <sys/wait.h>2021#include "../kselftest.h"2223void child(int cpu)24{25cpu_set_t set;2627CPU_ZERO(&set);28CPU_SET(cpu, &set);29if (sched_setaffinity(0, sizeof(set), &set) != 0) {30ksft_print_msg("sched_setaffinity() failed: %s\n",31strerror(errno));32_exit(1);33}3435if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) {36ksft_print_msg("ptrace(PTRACE_TRACEME) failed: %s\n",37strerror(errno));38_exit(1);39}4041if (raise(SIGSTOP) != 0) {42ksft_print_msg("raise(SIGSTOP) failed: %s\n", strerror(errno));43_exit(1);44}4546_exit(0);47}4849int run_test(int cpu)50{51int status;52pid_t pid = fork();53pid_t wpid;5455if (pid < 0) {56ksft_print_msg("fork() failed: %s\n", strerror(errno));57return KSFT_FAIL;58}59if (pid == 0)60child(cpu);6162wpid = waitpid(pid, &status, __WALL);63if (wpid != pid) {64ksft_print_msg("waitpid() failed: %s\n", strerror(errno));65return KSFT_FAIL;66}67if (!WIFSTOPPED(status)) {68ksft_print_msg("child did not stop: %s\n", strerror(errno));69return KSFT_FAIL;70}71if (WSTOPSIG(status) != SIGSTOP) {72ksft_print_msg("child did not stop with SIGSTOP: %s\n",73strerror(errno));74return KSFT_FAIL;75}7677if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) {78if (errno == EIO) {79ksft_print_msg(80"ptrace(PTRACE_SINGLESTEP) not supported on this architecture: %s\n",81strerror(errno));82return KSFT_SKIP;83}84ksft_print_msg("ptrace(PTRACE_SINGLESTEP) failed: %s\n",85strerror(errno));86return KSFT_FAIL;87}8889wpid = waitpid(pid, &status, __WALL);90if (wpid != pid) {91ksft_print_msg("waitpid() failed: %s\n", strerror(errno));92return KSFT_FAIL;93}94if (WIFEXITED(status)) {95ksft_print_msg("child did not single-step: %s\n",96strerror(errno));97return KSFT_FAIL;98}99if (!WIFSTOPPED(status)) {100ksft_print_msg("child did not stop: %s\n", strerror(errno));101return KSFT_FAIL;102}103if (WSTOPSIG(status) != SIGTRAP) {104ksft_print_msg("child did not stop with SIGTRAP: %s\n",105strerror(errno));106return KSFT_FAIL;107}108109if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {110ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n",111strerror(errno));112return KSFT_FAIL;113}114115wpid = waitpid(pid, &status, __WALL);116if (wpid != pid) {117ksft_print_msg("waitpid() failed: %s\n", strerror(errno));118return KSFT_FAIL;119}120if (!WIFEXITED(status)) {121ksft_print_msg("child did not exit after PTRACE_CONT: %s\n",122strerror(errno));123return KSFT_FAIL;124}125126return KSFT_PASS;127}128129/*130* Reads the suspend success count from sysfs.131* Returns the count on success or exits on failure.132*/133static int get_suspend_success_count_or_fail(void)134{135FILE *fp;136int val;137138fp = fopen("/sys/power/suspend_stats/success", "r");139if (!fp)140ksft_exit_fail_msg(141"Failed to open suspend_stats/success: %s\n",142strerror(errno));143144if (fscanf(fp, "%d", &val) != 1) {145fclose(fp);146ksft_exit_fail_msg(147"Failed to read suspend success count\n");148}149150fclose(fp);151return val;152}153154void suspend(void)155{156int timerfd;157int err;158int count_before;159int count_after;160struct itimerspec spec = {};161162if (getuid() != 0)163ksft_exit_skip("Please run the test as root - Exiting.\n");164165timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);166if (timerfd < 0)167ksft_exit_fail_msg("timerfd_create() failed\n");168169spec.it_value.tv_sec = 5;170err = timerfd_settime(timerfd, 0, &spec, NULL);171if (err < 0)172ksft_exit_fail_msg("timerfd_settime() failed\n");173174count_before = get_suspend_success_count_or_fail();175176system("(echo mem > /sys/power/state) 2> /dev/null");177178count_after = get_suspend_success_count_or_fail();179if (count_after <= count_before)180ksft_exit_fail_msg("Failed to enter Suspend state\n");181182close(timerfd);183}184185int main(int argc, char **argv)186{187int opt;188bool do_suspend = true;189bool succeeded = true;190unsigned int tests = 0;191cpu_set_t available_cpus;192int err;193int cpu;194195ksft_print_header();196197while ((opt = getopt(argc, argv, "n")) != -1) {198switch (opt) {199case 'n':200do_suspend = false;201break;202default:203printf("Usage: %s [-n]\n", argv[0]);204printf(" -n: do not trigger a suspend/resume cycle before the test\n");205return -1;206}207}208209err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus);210if (err < 0)211ksft_exit_fail_msg("sched_getaffinity() failed\n");212213for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {214if (!CPU_ISSET(cpu, &available_cpus))215continue;216tests++;217}218219if (do_suspend)220suspend();221222ksft_set_plan(tests);223for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {224int test_success;225226if (!CPU_ISSET(cpu, &available_cpus))227continue;228229test_success = run_test(cpu);230switch (test_success) {231case KSFT_PASS:232ksft_test_result_pass("CPU %d\n", cpu);233break;234case KSFT_SKIP:235ksft_test_result_skip("CPU %d\n", cpu);236break;237case KSFT_FAIL:238ksft_test_result_fail("CPU %d\n", cpu);239succeeded = false;240break;241}242}243244if (succeeded)245ksft_exit_pass();246else247ksft_exit_fail();248}249250251