1 /* alarmtimer suspend test 2 * John Stultz (john.stultz@linaro.org) 3 * (C) Copyright Linaro 2013 4 * Licensed under the GPLv2 5 * 6 * This test makes sure the alarmtimer & RTC wakeup code is 7 * functioning. 8 * 9 * To build: 10 * $ gcc alarmtimer-suspend.c -o alarmtimer-suspend -lrt 11 * 12 * This program is free software: you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation, either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 * This program is distributed in the hope that it will be useful, 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * GNU General Public License for more details. 21 */ 22 23 24 #include <stdio.h> 25 #include <unistd.h> 26 #include <time.h> 27 #include <string.h> 28 #include <signal.h> 29 #include <stdlib.h> 30 #include <pthread.h> 31 #include <errno.h> 32 #include "clock-helpers.h" 33 #include "kselftest.h" 34 35 #define UNREASONABLE_LAT (NSEC_PER_SEC * 5) /* hopefully we resume in 5 secs */ 36 37 #define SUSPEND_SECS 15 38 int alarmcount; 39 int alarm_clock_id; 40 struct timespec start_time; 41 42 long long timespec_sub(struct timespec a, struct timespec b) 43 { 44 long long ret = NSEC_PER_SEC * b.tv_sec + b.tv_nsec; 45 46 ret -= NSEC_PER_SEC * a.tv_sec + a.tv_nsec; 47 return ret; 48 } 49 50 int final_ret; 51 52 void sigalarm(int signo) 53 { 54 long long delta_ns; 55 struct timespec ts; 56 57 clock_gettime(alarm_clock_id, &ts); 58 alarmcount++; 59 60 delta_ns = timespec_sub(start_time, ts); 61 delta_ns -= NSEC_PER_SEC * SUSPEND_SECS * alarmcount; 62 63 printf("ALARM(%i): %ld:%ld latency: %lld ns ", alarmcount, ts.tv_sec, 64 ts.tv_nsec, delta_ns); 65 66 if (delta_ns > UNREASONABLE_LAT) { 67 printf("[FAIL]\n"); 68 final_ret = -1; 69 } else 70 printf("[OK]\n"); 71 72 } 73 74 int main(void) 75 { 76 timer_t tm1; 77 struct itimerspec its1, its2; 78 struct sigevent se; 79 struct sigaction act; 80 int signum = SIGRTMAX; 81 82 /* Set up signal handler: */ 83 sigfillset(&act.sa_mask); 84 act.sa_flags = 0; 85 act.sa_handler = sigalarm; 86 sigaction(signum, &act, NULL); 87 88 /* Set up timer: */ 89 memset(&se, 0, sizeof(se)); 90 se.sigev_notify = SIGEV_SIGNAL; 91 se.sigev_signo = signum; 92 se.sigev_value.sival_int = 0; 93 94 for (alarm_clock_id = CLOCK_REALTIME_ALARM; 95 alarm_clock_id <= CLOCK_BOOTTIME_ALARM; 96 alarm_clock_id++) { 97 98 alarmcount = 0; 99 if (timer_create(alarm_clock_id, &se, &tm1) == -1) { 100 printf("timer_create failed, %s unsupported?: %s\n", 101 clock_name(alarm_clock_id), strerror(errno)); 102 break; 103 } 104 105 clock_gettime(alarm_clock_id, &start_time); 106 printf("Start time (%s): %ld:%ld\n", clock_name(alarm_clock_id), 107 start_time.tv_sec, start_time.tv_nsec); 108 printf("Setting alarm for every %i seconds\n", SUSPEND_SECS); 109 its1.it_value = start_time; 110 its1.it_value.tv_sec += SUSPEND_SECS; 111 its1.it_interval.tv_sec = SUSPEND_SECS; 112 its1.it_interval.tv_nsec = 0; 113 114 timer_settime(tm1, TIMER_ABSTIME, &its1, &its2); 115 116 while (alarmcount < 5) 117 sleep(1); /* First 5 alarms, do nothing */ 118 119 printf("Starting suspend loops\n"); 120 while (alarmcount < 10) { 121 int ret; 122 123 sleep(3); 124 ret = system("echo mem > /sys/power/state"); 125 if (ret) 126 break; 127 } 128 timer_delete(tm1); 129 } 130 if (final_ret) 131 ksft_exit_fail(); 132 ksft_exit_pass(); 133 } 134