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 11 #include <new> 12 13 #include <AutoDeleter.h> 14 #include <syscall_utils.h> 15 16 #include <syscalls.h> 17 #include <thread_defs.h> 18 #include <user_timer_defs.h> 19 20 #include <libroot_private.h> 21 #include <pthread_private.h> 22 #include <time_private.h> 23 #include <user_thread.h> 24 25 26 static void 27 info_to_itimerspec(const user_timer_info& info, itimerspec& spec) 28 { 29 bigtime_to_timespec(info.interval, spec.it_interval); 30 31 // A remaining_time of B_INFINITE_TIMEOUT means the timer isn't scheduled. 32 if (info.remaining_time != B_INFINITE_TIMEOUT) { 33 bigtime_to_timespec(info.remaining_time, spec.it_value); 34 } else { 35 spec.it_value.tv_sec = 0; 36 spec.it_value.tv_nsec = 0; 37 } 38 } 39 40 41 static bool 42 itimerspec_to_bigtimes(const itimerspec& spec, bigtime_t& _nextTime, 43 bigtime_t& _interval) 44 { 45 if (!timespec_to_bigtime(spec.it_interval, _interval) 46 || !timespec_to_bigtime(spec.it_value, _nextTime)) { 47 return false; 48 } 49 50 if (_nextTime == 0) 51 _nextTime = B_INFINITE_TIMEOUT; 52 53 return true; 54 } 55 56 57 static status_t 58 timer_thread_entry(void* _entry, void* _value) 59 { 60 // init a pthread 61 pthread_thread thread; 62 __init_pthread(&thread, NULL, NULL); 63 thread.flags |= THREAD_DETACHED; 64 65 get_user_thread()->pthread = &thread; 66 67 // we have been started with deferred signals -- undefer them 68 undefer_signals(); 69 70 // prepare the arguments 71 union sigval value; 72 value.sival_ptr = _value; 73 void (*entry)(union sigval) = (void (*)(union sigval))_entry; 74 75 // call the entry function 76 entry(value); 77 78 return B_OK; 79 } 80 81 82 // #pragma mark - 83 84 85 int 86 timer_create(clockid_t clockID, struct sigevent* event, timer_t* _timer) 87 { 88 // create a timer object 89 __timer_t* timer = new(std::nothrow) __timer_t; 90 if (timer == NULL) 91 RETURN_AND_SET_ERRNO(ENOMEM); 92 ObjectDeleter<__timer_t> timerDeleter(timer); 93 94 // If the notification method is SIGEV_THREAD, initialize thread creation 95 // attributes. 96 bool isThreadEvent = event != NULL && event->sigev_notify == SIGEV_THREAD; 97 thread_creation_attributes threadAttributes; 98 if (isThreadEvent) { 99 status_t error = __pthread_init_creation_attributes( 100 event->sigev_notify_attributes, NULL, &timer_thread_entry, 101 (void*)event->sigev_notify_function, event->sigev_value.sival_ptr, 102 "timer notify", &threadAttributes); 103 if (error != B_OK) 104 RETURN_AND_SET_ERRNO(error); 105 106 threadAttributes.flags |= THREAD_CREATION_FLAG_DEFER_SIGNALS; 107 } 108 109 // create the timer 110 int32 timerID = _kern_create_timer(clockID, -1, 0, event, 111 isThreadEvent ? &threadAttributes : NULL); 112 if (timerID < 0) 113 RETURN_AND_SET_ERRNO(timerID); 114 115 // init the object members 116 timer->SetTo(timerID, -1); 117 118 *_timer = timerDeleter.Detach(); 119 return 0; 120 } 121 122 123 int 124 timer_delete(timer_t timer) 125 { 126 status_t error = _kern_delete_timer(timer->id, timer->thread); 127 if (error != B_OK) 128 RETURN_AND_SET_ERRNO(error); 129 130 delete timer; 131 return 0; 132 } 133 134 135 int 136 timer_gettime(timer_t timer, struct itimerspec* value) 137 { 138 user_timer_info info; 139 status_t error = _kern_get_timer(timer->id, timer->thread, &info); 140 if (error != B_OK) 141 RETURN_AND_SET_ERRNO(error); 142 143 info_to_itimerspec(info, *value); 144 145 return 0; 146 } 147 148 149 int 150 timer_settime(timer_t timer, int flags, const struct itimerspec* value, 151 struct itimerspec* oldValue) 152 { 153 // translate new value 154 bigtime_t nextTime; 155 bigtime_t interval; 156 if (!itimerspec_to_bigtimes(*value, nextTime, interval)) 157 RETURN_AND_SET_ERRNO(EINVAL); 158 159 uint32 timeoutFlags = (flags & TIMER_ABSTIME) != 0 160 ? B_ABSOLUTE_TIMEOUT : B_RELATIVE_TIMEOUT; 161 162 // set the timer 163 user_timer_info oldInfo; 164 status_t error = _kern_set_timer(timer->id, timer->thread, nextTime, 165 interval, timeoutFlags, oldValue != NULL ? &oldInfo : NULL); 166 if (error != B_OK) 167 RETURN_AND_SET_ERRNO(error); 168 169 // translate old info back 170 if (oldValue != NULL) 171 info_to_itimerspec(oldInfo, *oldValue); 172 173 return 0; 174 } 175 176 177 int 178 timer_getoverrun(timer_t timer) 179 { 180 user_timer_info info; 181 status_t error = _kern_get_timer(timer->id, timer->thread, &info); 182 if (error != B_OK) 183 RETURN_AND_SET_ERRNO(error); 184 185 return info.overrun_count; 186 } 187