Home | History | Annotate | Download | only in timers
      1 /* alarmtimer suspend test
      2  *		John Stultz (john.stultz (at) 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 "../kselftest.h"
     32 
     33 #define CLOCK_REALTIME			0
     34 #define CLOCK_MONOTONIC			1
     35 #define CLOCK_PROCESS_CPUTIME_ID	2
     36 #define CLOCK_THREAD_CPUTIME_ID		3
     37 #define CLOCK_MONOTONIC_RAW		4
     38 #define CLOCK_REALTIME_COARSE		5
     39 #define CLOCK_MONOTONIC_COARSE		6
     40 #define CLOCK_BOOTTIME			7
     41 #define CLOCK_REALTIME_ALARM		8
     42 #define CLOCK_BOOTTIME_ALARM		9
     43 #define CLOCK_HWSPECIFIC		10
     44 #define CLOCK_TAI			11
     45 #define NR_CLOCKIDS			12
     46 
     47 
     48 #define NSEC_PER_SEC 1000000000ULL
     49 #define UNREASONABLE_LAT (NSEC_PER_SEC * 5) /* hopefully we resume in 5 secs */
     50 
     51 #define SUSPEND_SECS 15
     52 int alarmcount;
     53 int alarm_clock_id;
     54 struct timespec start_time;
     55 
     56 
     57 char *clockstring(int clockid)
     58 {
     59 	switch (clockid) {
     60 	case CLOCK_REALTIME:
     61 		return "CLOCK_REALTIME";
     62 	case CLOCK_MONOTONIC:
     63 		return "CLOCK_MONOTONIC";
     64 	case CLOCK_PROCESS_CPUTIME_ID:
     65 		return "CLOCK_PROCESS_CPUTIME_ID";
     66 	case CLOCK_THREAD_CPUTIME_ID:
     67 		return "CLOCK_THREAD_CPUTIME_ID";
     68 	case CLOCK_MONOTONIC_RAW:
     69 		return "CLOCK_MONOTONIC_RAW";
     70 	case CLOCK_REALTIME_COARSE:
     71 		return "CLOCK_REALTIME_COARSE";
     72 	case CLOCK_MONOTONIC_COARSE:
     73 		return "CLOCK_MONOTONIC_COARSE";
     74 	case CLOCK_BOOTTIME:
     75 		return "CLOCK_BOOTTIME";
     76 	case CLOCK_REALTIME_ALARM:
     77 		return "CLOCK_REALTIME_ALARM";
     78 	case CLOCK_BOOTTIME_ALARM:
     79 		return "CLOCK_BOOTTIME_ALARM";
     80 	case CLOCK_TAI:
     81 		return "CLOCK_TAI";
     82 	};
     83 	return "UNKNOWN_CLOCKID";
     84 }
     85 
     86 
     87 long long timespec_sub(struct timespec a, struct timespec b)
     88 {
     89 	long long ret = NSEC_PER_SEC * b.tv_sec + b.tv_nsec;
     90 
     91 	ret -= NSEC_PER_SEC * a.tv_sec + a.tv_nsec;
     92 	return ret;
     93 }
     94 
     95 int final_ret = 0;
     96 
     97 void sigalarm(int signo)
     98 {
     99 	long long delta_ns;
    100 	struct timespec ts;
    101 
    102 	clock_gettime(alarm_clock_id, &ts);
    103 	alarmcount++;
    104 
    105 	delta_ns = timespec_sub(start_time, ts);
    106 	delta_ns -= NSEC_PER_SEC * SUSPEND_SECS * alarmcount;
    107 
    108 	printf("ALARM(%i): %ld:%ld latency: %lld ns ", alarmcount, ts.tv_sec,
    109 							ts.tv_nsec, delta_ns);
    110 
    111 	if (delta_ns > UNREASONABLE_LAT) {
    112 		printf("[FAIL]\n");
    113 		final_ret = -1;
    114 	} else
    115 		printf("[OK]\n");
    116 
    117 }
    118 
    119 int main(void)
    120 {
    121 	timer_t tm1;
    122 	struct itimerspec its1, its2;
    123 	struct sigevent se;
    124 	struct sigaction act;
    125 	int signum = SIGRTMAX;
    126 
    127 	/* Set up signal handler: */
    128 	sigfillset(&act.sa_mask);
    129 	act.sa_flags = 0;
    130 	act.sa_handler = sigalarm;
    131 	sigaction(signum, &act, NULL);
    132 
    133 	/* Set up timer: */
    134 	memset(&se, 0, sizeof(se));
    135 	se.sigev_notify = SIGEV_SIGNAL;
    136 	se.sigev_signo = signum;
    137 	se.sigev_value.sival_int = 0;
    138 
    139 	for (alarm_clock_id = CLOCK_REALTIME_ALARM;
    140 			alarm_clock_id <= CLOCK_BOOTTIME_ALARM;
    141 			alarm_clock_id++) {
    142 
    143 		alarmcount = 0;
    144 		if (timer_create(alarm_clock_id, &se, &tm1) == -1) {
    145 			printf("timer_create failed, %s unsupported?\n",
    146 					clockstring(alarm_clock_id));
    147 			break;
    148 		}
    149 
    150 		clock_gettime(alarm_clock_id, &start_time);
    151 		printf("Start time (%s): %ld:%ld\n", clockstring(alarm_clock_id),
    152 				start_time.tv_sec, start_time.tv_nsec);
    153 		printf("Setting alarm for every %i seconds\n", SUSPEND_SECS);
    154 		its1.it_value = start_time;
    155 		its1.it_value.tv_sec += SUSPEND_SECS;
    156 		its1.it_interval.tv_sec = SUSPEND_SECS;
    157 		its1.it_interval.tv_nsec = 0;
    158 
    159 		timer_settime(tm1, TIMER_ABSTIME, &its1, &its2);
    160 
    161 		while (alarmcount < 5)
    162 			sleep(1); /* First 5 alarms, do nothing */
    163 
    164 		printf("Starting suspend loops\n");
    165 		while (alarmcount < 10) {
    166 			int ret;
    167 
    168 			sleep(3);
    169 			ret = system("echo mem > /sys/power/state");
    170 			if (ret)
    171 				break;
    172 		}
    173 		timer_delete(tm1);
    174 	}
    175 	if (final_ret)
    176 		return ksft_exit_fail();
    177 	return ksft_exit_pass();
    178 }
    179