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