18c2ecf20Sopenharmony_ci/* alarmtimer suspend test 28c2ecf20Sopenharmony_ci * John Stultz (john.stultz@linaro.org) 38c2ecf20Sopenharmony_ci * (C) Copyright Linaro 2013 48c2ecf20Sopenharmony_ci * Licensed under the GPLv2 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This test makes sure the alarmtimer & RTC wakeup code is 78c2ecf20Sopenharmony_ci * functioning. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * To build: 108c2ecf20Sopenharmony_ci * $ gcc alarmtimer-suspend.c -o alarmtimer-suspend -lrt 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This program is free software: you can redistribute it and/or modify 138c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 148c2ecf20Sopenharmony_ci * the Free Software Foundation, either version 2 of the License, or 158c2ecf20Sopenharmony_ci * (at your option) any later version. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, 188c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 198c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 208c2ecf20Sopenharmony_ci * GNU General Public License for more details. 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include <stdio.h> 258c2ecf20Sopenharmony_ci#include <unistd.h> 268c2ecf20Sopenharmony_ci#include <time.h> 278c2ecf20Sopenharmony_ci#include <string.h> 288c2ecf20Sopenharmony_ci#include <signal.h> 298c2ecf20Sopenharmony_ci#include <stdlib.h> 308c2ecf20Sopenharmony_ci#include <pthread.h> 318c2ecf20Sopenharmony_ci#include "../kselftest.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define CLOCK_REALTIME 0 348c2ecf20Sopenharmony_ci#define CLOCK_MONOTONIC 1 358c2ecf20Sopenharmony_ci#define CLOCK_PROCESS_CPUTIME_ID 2 368c2ecf20Sopenharmony_ci#define CLOCK_THREAD_CPUTIME_ID 3 378c2ecf20Sopenharmony_ci#define CLOCK_MONOTONIC_RAW 4 388c2ecf20Sopenharmony_ci#define CLOCK_REALTIME_COARSE 5 398c2ecf20Sopenharmony_ci#define CLOCK_MONOTONIC_COARSE 6 408c2ecf20Sopenharmony_ci#define CLOCK_BOOTTIME 7 418c2ecf20Sopenharmony_ci#define CLOCK_REALTIME_ALARM 8 428c2ecf20Sopenharmony_ci#define CLOCK_BOOTTIME_ALARM 9 438c2ecf20Sopenharmony_ci#define CLOCK_HWSPECIFIC 10 448c2ecf20Sopenharmony_ci#define CLOCK_TAI 11 458c2ecf20Sopenharmony_ci#define NR_CLOCKIDS 12 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define NSEC_PER_SEC 1000000000ULL 498c2ecf20Sopenharmony_ci#define UNREASONABLE_LAT (NSEC_PER_SEC * 5) /* hopefully we resume in 5 secs */ 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define SUSPEND_SECS 15 528c2ecf20Sopenharmony_ciint alarmcount; 538c2ecf20Sopenharmony_ciint alarm_clock_id; 548c2ecf20Sopenharmony_cistruct timespec start_time; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cichar *clockstring(int clockid) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci switch (clockid) { 608c2ecf20Sopenharmony_ci case CLOCK_REALTIME: 618c2ecf20Sopenharmony_ci return "CLOCK_REALTIME"; 628c2ecf20Sopenharmony_ci case CLOCK_MONOTONIC: 638c2ecf20Sopenharmony_ci return "CLOCK_MONOTONIC"; 648c2ecf20Sopenharmony_ci case CLOCK_PROCESS_CPUTIME_ID: 658c2ecf20Sopenharmony_ci return "CLOCK_PROCESS_CPUTIME_ID"; 668c2ecf20Sopenharmony_ci case CLOCK_THREAD_CPUTIME_ID: 678c2ecf20Sopenharmony_ci return "CLOCK_THREAD_CPUTIME_ID"; 688c2ecf20Sopenharmony_ci case CLOCK_MONOTONIC_RAW: 698c2ecf20Sopenharmony_ci return "CLOCK_MONOTONIC_RAW"; 708c2ecf20Sopenharmony_ci case CLOCK_REALTIME_COARSE: 718c2ecf20Sopenharmony_ci return "CLOCK_REALTIME_COARSE"; 728c2ecf20Sopenharmony_ci case CLOCK_MONOTONIC_COARSE: 738c2ecf20Sopenharmony_ci return "CLOCK_MONOTONIC_COARSE"; 748c2ecf20Sopenharmony_ci case CLOCK_BOOTTIME: 758c2ecf20Sopenharmony_ci return "CLOCK_BOOTTIME"; 768c2ecf20Sopenharmony_ci case CLOCK_REALTIME_ALARM: 778c2ecf20Sopenharmony_ci return "CLOCK_REALTIME_ALARM"; 788c2ecf20Sopenharmony_ci case CLOCK_BOOTTIME_ALARM: 798c2ecf20Sopenharmony_ci return "CLOCK_BOOTTIME_ALARM"; 808c2ecf20Sopenharmony_ci case CLOCK_TAI: 818c2ecf20Sopenharmony_ci return "CLOCK_TAI"; 828c2ecf20Sopenharmony_ci }; 838c2ecf20Sopenharmony_ci return "UNKNOWN_CLOCKID"; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cilong long timespec_sub(struct timespec a, struct timespec b) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci long long ret = NSEC_PER_SEC * b.tv_sec + b.tv_nsec; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci ret -= NSEC_PER_SEC * a.tv_sec + a.tv_nsec; 928c2ecf20Sopenharmony_ci return ret; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ciint final_ret = 0; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_civoid sigalarm(int signo) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci long long delta_ns; 1008c2ecf20Sopenharmony_ci struct timespec ts; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci clock_gettime(alarm_clock_id, &ts); 1038c2ecf20Sopenharmony_ci alarmcount++; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci delta_ns = timespec_sub(start_time, ts); 1068c2ecf20Sopenharmony_ci delta_ns -= NSEC_PER_SEC * SUSPEND_SECS * alarmcount; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci printf("ALARM(%i): %ld:%ld latency: %lld ns ", alarmcount, ts.tv_sec, 1098c2ecf20Sopenharmony_ci ts.tv_nsec, delta_ns); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (delta_ns > UNREASONABLE_LAT) { 1128c2ecf20Sopenharmony_ci printf("[FAIL]\n"); 1138c2ecf20Sopenharmony_ci final_ret = -1; 1148c2ecf20Sopenharmony_ci } else 1158c2ecf20Sopenharmony_ci printf("[OK]\n"); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ciint main(void) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci timer_t tm1; 1228c2ecf20Sopenharmony_ci struct itimerspec its1, its2; 1238c2ecf20Sopenharmony_ci struct sigevent se; 1248c2ecf20Sopenharmony_ci struct sigaction act; 1258c2ecf20Sopenharmony_ci int signum = SIGRTMAX; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* Set up signal handler: */ 1288c2ecf20Sopenharmony_ci sigfillset(&act.sa_mask); 1298c2ecf20Sopenharmony_ci act.sa_flags = 0; 1308c2ecf20Sopenharmony_ci act.sa_handler = sigalarm; 1318c2ecf20Sopenharmony_ci sigaction(signum, &act, NULL); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci /* Set up timer: */ 1348c2ecf20Sopenharmony_ci memset(&se, 0, sizeof(se)); 1358c2ecf20Sopenharmony_ci se.sigev_notify = SIGEV_SIGNAL; 1368c2ecf20Sopenharmony_ci se.sigev_signo = signum; 1378c2ecf20Sopenharmony_ci se.sigev_value.sival_int = 0; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci for (alarm_clock_id = CLOCK_REALTIME_ALARM; 1408c2ecf20Sopenharmony_ci alarm_clock_id <= CLOCK_BOOTTIME_ALARM; 1418c2ecf20Sopenharmony_ci alarm_clock_id++) { 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci alarmcount = 0; 1448c2ecf20Sopenharmony_ci if (timer_create(alarm_clock_id, &se, &tm1) == -1) { 1458c2ecf20Sopenharmony_ci printf("timer_create failed, %s unsupported?\n", 1468c2ecf20Sopenharmony_ci clockstring(alarm_clock_id)); 1478c2ecf20Sopenharmony_ci break; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci clock_gettime(alarm_clock_id, &start_time); 1518c2ecf20Sopenharmony_ci printf("Start time (%s): %ld:%ld\n", clockstring(alarm_clock_id), 1528c2ecf20Sopenharmony_ci start_time.tv_sec, start_time.tv_nsec); 1538c2ecf20Sopenharmony_ci printf("Setting alarm for every %i seconds\n", SUSPEND_SECS); 1548c2ecf20Sopenharmony_ci its1.it_value = start_time; 1558c2ecf20Sopenharmony_ci its1.it_value.tv_sec += SUSPEND_SECS; 1568c2ecf20Sopenharmony_ci its1.it_interval.tv_sec = SUSPEND_SECS; 1578c2ecf20Sopenharmony_ci its1.it_interval.tv_nsec = 0; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci timer_settime(tm1, TIMER_ABSTIME, &its1, &its2); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci while (alarmcount < 5) 1628c2ecf20Sopenharmony_ci sleep(1); /* First 5 alarms, do nothing */ 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci printf("Starting suspend loops\n"); 1658c2ecf20Sopenharmony_ci while (alarmcount < 10) { 1668c2ecf20Sopenharmony_ci int ret; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci sleep(3); 1698c2ecf20Sopenharmony_ci ret = system("echo mem > /sys/power/state"); 1708c2ecf20Sopenharmony_ci if (ret) 1718c2ecf20Sopenharmony_ci break; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci timer_delete(tm1); 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci if (final_ret) 1768c2ecf20Sopenharmony_ci return ksft_exit_fail(); 1778c2ecf20Sopenharmony_ci return ksft_exit_pass(); 1788c2ecf20Sopenharmony_ci} 179