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 <syscall_utils.h> 18 19 #include <syscalls.h> 20 21 22 int 23 clock_getres(clockid_t clockID, struct timespec* resolution) 24 { 25 // check the clock ID 26 switch (clockID) { 27 case CLOCK_MONOTONIC: 28 case CLOCK_REALTIME: 29 case CLOCK_PROCESS_CPUTIME_ID: 30 case CLOCK_THREAD_CPUTIME_ID: 31 break; 32 default: 33 if (clockID < 0) 34 RETURN_AND_SET_ERRNO(EINVAL); 35 36 // For clock IDs we can't otherwise verify, try to get the time. 37 if (clockID != getpid()) { 38 timespec dummy; 39 if (clock_gettime(clockID, &dummy) != 0) 40 return -1; 41 } 42 } 43 44 // currently resolution is always 1us 45 if (resolution != NULL) { 46 resolution->tv_sec = 0; 47 resolution->tv_nsec = 1000; 48 } 49 50 return 0; 51 } 52 53 54 int 55 clock_gettime(clockid_t clockID, struct timespec* time) 56 { 57 // get the time in microseconds 58 bigtime_t microSeconds; 59 60 switch (clockID) { 61 case CLOCK_MONOTONIC: 62 microSeconds = system_time(); 63 break; 64 case CLOCK_REALTIME: 65 microSeconds = real_time_clock_usecs(); 66 break; 67 case CLOCK_PROCESS_CPUTIME_ID: 68 case CLOCK_THREAD_CPUTIME_ID: 69 default: 70 { 71 status_t error = _kern_get_clock(clockID, µSeconds); 72 if (error != B_OK) 73 RETURN_AND_SET_ERRNO(error); 74 } 75 } 76 77 // set the result 78 time->tv_sec = microSeconds / 1000000; 79 time->tv_nsec = (microSeconds % 1000000) * 1000; 80 81 return 0; 82 } 83 84 85 int 86 clock_settime(clockid_t clockID, const struct timespec* time) 87 { 88 // can't set the monotonic clock 89 if (clockID == CLOCK_MONOTONIC) 90 RETURN_AND_SET_ERRNO(EINVAL); 91 92 // check timespec validity 93 if (time->tv_sec < 0 || time->tv_nsec < 0 || time->tv_nsec >= 1000000000) 94 RETURN_AND_SET_ERRNO(EINVAL); 95 96 // convert to microseconds and set the clock 97 bigtime_t microSeconds = (bigtime_t)time->tv_sec * 1000000 98 + time->tv_nsec / 1000; 99 100 RETURN_AND_SET_ERRNO(_kern_set_clock(clockID, microSeconds)); 101 } 102 103 104 int 105 clock_nanosleep(clockid_t clockID, int flags, const struct timespec* time, 106 struct timespec* remainingTime) 107 { 108 // convert time to microseconds (round up) 109 if (time->tv_sec < 0 || time->tv_nsec < 0 || time->tv_nsec >= 1000000000) 110 RETURN_AND_TEST_CANCEL(EINVAL); 111 112 bigtime_t microSeconds = (bigtime_t)time->tv_sec * 1000000 113 + (time->tv_nsec + 999) / 1000; 114 115 // get timeout flags 116 uint32 timeoutFlags; 117 if ((flags & TIMER_ABSTIME) != 0) { 118 timeoutFlags = B_ABSOLUTE_TIMEOUT; 119 120 // ignore remainingTime for absolute waits 121 remainingTime = NULL; 122 } else 123 timeoutFlags = B_RELATIVE_TIMEOUT; 124 125 // wait 126 bigtime_t remainingMicroSeconds; 127 status_t error = _kern_snooze_etc(microSeconds, clockID, timeoutFlags, 128 remainingTime != NULL ? &remainingMicroSeconds : NULL); 129 130 // If interrupted and this is a relative wait, compute and return the 131 // remaining wait time. 132 if (error == B_INTERRUPTED && remainingTime != NULL) { 133 if (remainingMicroSeconds > 0) { 134 remainingTime->tv_sec = remainingMicroSeconds / 1000000; 135 remainingTime->tv_nsec = (remainingMicroSeconds % 1000000) * 1000; 136 } else { 137 // We were slow enough that the wait time passed anyway. 138 error = B_OK; 139 } 140 } 141 142 RETURN_AND_TEST_CANCEL(error); 143 } 144 145 146 int 147 clock_getcpuclockid(pid_t pid, clockid_t* _clockID) 148 { 149 if (pid < 0) 150 return ESRCH; 151 152 // The CPU clock ID for a process is simply the team ID. For pid == 0 we're 153 // supposed to return the current process' clock. 154 if (pid == 0) { 155 *_clockID = getpid(); 156 return 0; 157 } 158 159 // test-get the time to verify the team exists and we have permission 160 bigtime_t microSeconds; 161 status_t error = _kern_get_clock(pid, µSeconds); 162 if (error != B_OK) { 163 // Since pid is > 0, B_BAD_VALUE always means a team with that ID 164 // doesn't exist. Translate the error code accordingly. 165 if (error == B_BAD_VALUE) 166 return ESRCH; 167 return error; 168 } 169 170 *_clockID = pid; 171 return 0; 172 } 173