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
clock_getres(clockid_t clockID,struct timespec * resolution)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
clock_gettime(clockid_t clockID,struct timespec * time)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, µSeconds);
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
clock_settime(clockid_t clockID,const struct timespec * time)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
clock_nanosleep(clockid_t clockID,int flags,const struct timespec * time,struct timespec * remainingTime)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
clock_getcpuclockid(pid_t pid,clockid_t * _clockID)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, µSeconds);
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