1/*
2 * Copyright (c) 2002, Intel Corporation. All rights reserved.
3 * This file is licensed under the GPL license.  For the full content
4 * of this license, see the COPYING file at the top level of this
5 * source tree.
6 * adam li
7 *
8 * Test that CLOCK_PROCESS_CPUTIME_ID is supported by timer_create().
9 *
10 * Same test as 1-1.c.
11 */
12
13#define _XOPEN_SOURCE 600
14
15#include <time.h>
16#include <signal.h>
17#include <stdio.h>
18#include <unistd.h>
19#include <stdlib.h>
20#include "posixtest.h"
21
22#define SIGTOTEST SIGALRM
23#define TIMERSEC 2
24#define SLEEPDELTA 3
25#define ACCEPTABLEDELTA 1
26#define CLOCK_TO_TEST CLOCK_PROCESS_CPUTIME_ID
27
28static int handlerInvoked = 0;
29
30static void sub_timespec(const struct timespec *a, const struct timespec *b,
31	struct timespec *result)
32{
33	result->tv_sec = a->tv_sec - b->tv_sec;
34	result->tv_nsec = a->tv_nsec - b->tv_nsec;
35	if (result->tv_nsec < 0 && result->tv_sec > 0) {
36		result->tv_sec--;
37		result->tv_nsec += 1000000000;
38	} else if (result->tv_nsec >= 1000000000) {
39		result->tv_sec++;
40		result->tv_nsec -= 1000000000;
41	}
42}
43
44static int cmp_timespec(const struct timespec *a, const struct timespec *b)
45{
46	if (a->tv_sec < b->tv_sec)
47		return -1;
48	if (a->tv_sec > b->tv_sec)
49		return 1;
50
51	if (a->tv_nsec < b->tv_nsec)
52		return -1;
53	if (a->tv_nsec > b->tv_nsec)
54		return 1;
55
56	return 0;
57}
58
59static int spin(const struct timespec *time, struct timespec *timeLeft)
60{
61	struct timespec startTime;
62
63	if (clock_gettime(CLOCK_TO_TEST, &startTime) != 0) {
64		perror("clock_gettime() failed");
65		exit(PTS_UNRESOLVED);
66	}
67
68	for (;;) {
69		struct timespec tempTime;
70		if (clock_gettime(CLOCK_TO_TEST, &tempTime) != 0) {
71			perror("clock_gettime() failed");
72			exit(PTS_UNRESOLVED);
73		}
74
75
76		sub_timespec(&tempTime, &startTime, &tempTime);
77		if (cmp_timespec(time, &tempTime) <= 0)
78			return 0;
79
80		if (handlerInvoked) {
81			if (timeLeft)
82				sub_timespec(time, &tempTime, timeLeft);
83			return -1;
84		}
85	}
86}
87
88void handler(int signo)
89{
90	printf("Caught signal\n");
91	handlerInvoked = 1;
92}
93
94int main(int argc, char *argv[])
95{
96#if _POSIX_CPUTIME == -1
97	printf("_POSIX_CPUTIME not defined\n");
98	return PTS_UNSUPPORTED;
99#else
100	struct sigevent ev;
101	struct sigaction act;
102	timer_t tid;
103	struct itimerspec its;
104	struct timespec ts, tsleft;
105	int rc;
106
107	rc = sysconf(_SC_CPUTIME);
108	printf("sysconf(_SC_CPUTIME) returns: %d\n", rc);
109	if (rc <= 0) {
110		return PTS_UNRESOLVED;
111	}
112
113	ev.sigev_notify = SIGEV_SIGNAL;
114	ev.sigev_signo = SIGTOTEST;
115
116	act.sa_handler=handler;
117	act.sa_flags=0;
118
119	its.it_interval.tv_sec = 0;
120	its.it_interval.tv_nsec = 0;
121	its.it_value.tv_sec = TIMERSEC;
122	its.it_value.tv_nsec = 0;
123
124	ts.tv_sec=TIMERSEC+SLEEPDELTA;
125	ts.tv_nsec=0;
126
127	if (sigemptyset(&act.sa_mask) == -1) {
128		perror("Error calling sigemptyset");
129		return PTS_UNRESOLVED;
130	}
131	if (sigaction(SIGTOTEST, &act, 0) == -1) {
132		perror("Error calling sigaction");
133		return PTS_UNRESOLVED;
134	}
135
136	if (timer_create(CLOCK_TO_TEST, &ev, &tid) != 0) {
137		perror("timer_create() did not return success");
138		return PTS_UNRESOLVED;
139	}
140
141	if (timer_settime(tid, 0, &its, NULL) != 0) {
142		perror("timer_settime() did not return success");
143		return PTS_UNRESOLVED;
144	}
145
146	if (spin(&ts, &tsleft) != -1) {
147		perror("spin() not interrupted");
148		return PTS_FAIL;
149	}
150
151	if ( abs(tsleft.tv_sec-SLEEPDELTA) <= ACCEPTABLEDELTA) {
152		printf("Test PASSED");
153		return PTS_PASS;
154	} else {
155		printf("Timer did not last for correct amount of time\n");
156		printf("timer: %d != correct %d\n",
157				(int) ts.tv_sec- (int) tsleft.tv_sec,
158				TIMERSEC);
159		return PTS_FAIL;
160	}
161
162	return PTS_UNRESOLVED;
163#endif
164}
165