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