xref: /haiku/src/system/libroot/posix/time/clock_support.cpp (revision 344ded80d400028c8f561b4b876257b94c12db4a)
1 /*
2  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <time.h>
8 
9 #include <errno.h>
10 #include <pthread.h>
11 #include <sys/resource.h>
12 #include <unistd.h>
13 
14 #include <OS.h>
15 
16 #include <errno_private.h>
17 #include <time_private.h>
18 #include <syscall_utils.h>
19 
20 #include <syscalls.h>
21 
22 
23 int
24 clock_getres(clockid_t clockID, struct timespec* resolution)
25 {
26 	// check the clock ID
27 	switch (clockID) {
28 		case CLOCK_MONOTONIC:
29 		case CLOCK_REALTIME:
30 		case CLOCK_PROCESS_CPUTIME_ID:
31 		case CLOCK_THREAD_CPUTIME_ID:
32 			break;
33 		default:
34 			if (clockID < 0)
35 				RETURN_AND_SET_ERRNO(EINVAL);
36 
37 			// For clock IDs we can't otherwise verify, try to get the time.
38 			if (clockID != getpid()) {
39 				timespec dummy;
40 				if (clock_gettime(clockID, &dummy) != 0)
41 					return -1;
42 			}
43 	}
44 
45 	// currently resolution is always 1us
46 	if (resolution != NULL) {
47 		resolution->tv_sec = 0;
48 		resolution->tv_nsec = 1000;
49 	}
50 
51 	return 0;
52 }
53 
54 
55 int
56 clock_gettime(clockid_t clockID, struct timespec* time)
57 {
58 	bigtime_t microSeconds;
59 	switch (clockID) {
60 		case CLOCK_MONOTONIC:
61 			microSeconds = system_time();
62 			break;
63 		case CLOCK_REALTIME:
64 			microSeconds = real_time_clock_usecs();
65 			break;
66 		case CLOCK_PROCESS_CPUTIME_ID:
67 		case CLOCK_THREAD_CPUTIME_ID:
68 		default:
69 		{
70 			status_t error = _kern_get_clock(clockID, &microSeconds);
71 			if (error != B_OK)
72 				RETURN_AND_SET_ERRNO(error);
73 		}
74 	}
75 
76 	bigtime_to_timespec(microSeconds, *time);
77 	return 0;
78 }
79 
80 
81 int
82 clock_settime(clockid_t clockID, const struct timespec* time)
83 {
84 	// can't set the monotonic clock
85 	if (clockID == CLOCK_MONOTONIC)
86 		RETURN_AND_SET_ERRNO(EINVAL);
87 
88 	bigtime_t microSeconds;
89 	if (!timespec_to_bigtime(*time, microSeconds))
90 		RETURN_AND_SET_ERRNO(EINVAL);
91 
92 	RETURN_AND_SET_ERRNO(_kern_set_clock(clockID, microSeconds));
93 }
94 
95 
96 int
97 clock_nanosleep(clockid_t clockID, int flags, const struct timespec* time,
98 	struct timespec* remainingTime)
99 {
100 	// convert time to microseconds (round up)
101 	bigtime_t microSeconds;
102 	if (!timespec_to_bigtime(*time, microSeconds))
103 		RETURN_AND_TEST_CANCEL(EINVAL);
104 
105 	// get timeout flags
106 	uint32 timeoutFlags;
107 	if ((flags & TIMER_ABSTIME) != 0) {
108 		timeoutFlags = B_ABSOLUTE_TIMEOUT;
109 
110 		// ignore remainingTime for absolute waits
111 		remainingTime = NULL;
112 	} else
113 		timeoutFlags = B_RELATIVE_TIMEOUT;
114 
115 	// wait
116 	bigtime_t remainingMicroSeconds;
117 	status_t error = _kern_snooze_etc(microSeconds, clockID, timeoutFlags,
118 		remainingTime != NULL ? &remainingMicroSeconds : NULL);
119 
120 	// If interrupted and this is a relative wait, compute and return the
121 	// remaining wait time.
122 	if (error == B_INTERRUPTED && remainingTime != NULL) {
123 		if (remainingMicroSeconds > 0) {
124 			bigtime_to_timespec(remainingMicroSeconds, *remainingTime);
125 		} else {
126 			// We were slow enough that the wait time passed anyway.
127 			error = B_OK;
128 		}
129 	}
130 
131 	RETURN_AND_TEST_CANCEL(error);
132 }
133 
134 
135 int
136 clock_getcpuclockid(pid_t pid, clockid_t* _clockID)
137 {
138 	if (pid < 0)
139 		return ESRCH;
140 
141 	// The CPU clock ID for a process is simply the team ID. For pid == 0 we're
142 	// supposed to return the current process' clock.
143 	if (pid == 0) {
144 		*_clockID = getpid();
145 		return 0;
146 	}
147 
148 	// test-get the time to verify the team exists and we have permission
149 	bigtime_t microSeconds;
150 	status_t error = _kern_get_clock(pid, &microSeconds);
151 	if (error != B_OK) {
152 		// Since pid is > 0, B_BAD_VALUE always means a team with that ID
153 		// doesn't exist. Translate the error code accordingly.
154 		if (error == B_BAD_VALUE)
155 			return ESRCH;
156 		return error;
157 	}
158 
159 	*_clockID = pid;
160 	return 0;
161 }
162