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 <syscall_utils.h> 17 18 #include <syscalls.h> 19 20 21 int 22 clock_getres(clockid_t clockID, struct timespec* resolution) 23 { 24 // check the clock ID 25 switch (clockID) { 26 case CLOCK_MONOTONIC: 27 case CLOCK_REALTIME: 28 case CLOCK_PROCESS_CPUTIME_ID: 29 case CLOCK_THREAD_CPUTIME_ID: 30 break; 31 default: 32 if (clockID < 0) 33 RETURN_AND_SET_ERRNO(EINVAL); 34 35 // For clock IDs we can't otherwise verify, try to get the time. 36 if (clockID != getpid()) { 37 timespec dummy; 38 if (clock_gettime(clockID, &dummy) != 0) 39 return -1; 40 } 41 } 42 43 // currently resolution is always 1us 44 if (resolution != NULL) { 45 resolution->tv_sec = 0; 46 resolution->tv_nsec = 1000; 47 } 48 49 return 0; 50 } 51 52 53 int 54 clock_gettime(clockid_t clockID, struct timespec* time) 55 { 56 // get the time in microseconds 57 bigtime_t microSeconds; 58 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 // set the result 77 time->tv_sec = microSeconds / 1000000; 78 time->tv_nsec = (microSeconds % 1000000) * 1000; 79 80 return 0; 81 } 82 83 84 int 85 clock_settime(clockid_t clockID, const struct timespec* time) 86 { 87 // can't set the monotonic clock 88 if (clockID == CLOCK_MONOTONIC) 89 RETURN_AND_SET_ERRNO(EINVAL); 90 91 // check timespec validity 92 if (time->tv_sec < 0 || time->tv_nsec < 0 || time->tv_nsec >= 1000000000) 93 RETURN_AND_SET_ERRNO(EINVAL); 94 95 // convert to microseconds and set the clock 96 bigtime_t microSeconds = (bigtime_t)time->tv_sec * 1000000 97 + time->tv_nsec / 1000; 98 99 RETURN_AND_SET_ERRNO(_kern_set_clock(clockID, microSeconds)); 100 } 101 102 103 int 104 clock_nanosleep(clockid_t clockID, int flags, const struct timespec* time, 105 struct timespec* remainingTime) 106 { 107 // convert time to microseconds (round up) 108 if (time->tv_sec < 0 || time->tv_nsec < 0 || time->tv_nsec >= 1000000000) 109 RETURN_AND_TEST_CANCEL(EINVAL); 110 111 bigtime_t microSeconds = (bigtime_t)time->tv_sec * 1000000 112 + (time->tv_nsec + 999) / 1000; 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