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, µ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 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, µ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