headers/bsd: Add sys/queue.h.
[haiku.git] / src / system / libroot / posix / time / timer_support.cpp
blob74e835837d6b96f659ee3e25de9c83a382a7e449
1 /*
2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <time.h>
9 #include <errno.h>
11 #include <new>
13 #include <AutoDeleter.h>
14 #include <syscall_utils.h>
16 #include <errno_private.h>
17 #include <syscalls.h>
18 #include <thread_defs.h>
19 #include <user_timer_defs.h>
21 #include <libroot_private.h>
22 #include <pthread_private.h>
23 #include <time_private.h>
24 #include <user_thread.h>
27 static void
28 info_to_itimerspec(const user_timer_info& info, itimerspec& spec)
30 bigtime_to_timespec(info.interval, spec.it_interval);
32 // A remaining_time of B_INFINITE_TIMEOUT means the timer isn't scheduled.
33 if (info.remaining_time != B_INFINITE_TIMEOUT) {
34 bigtime_to_timespec(info.remaining_time, spec.it_value);
35 } else {
36 spec.it_value.tv_sec = 0;
37 spec.it_value.tv_nsec = 0;
42 static bool
43 itimerspec_to_bigtimes(const itimerspec& spec, bigtime_t& _nextTime,
44 bigtime_t& _interval)
46 if (!timespec_to_bigtime(spec.it_interval, _interval)
47 || !timespec_to_bigtime(spec.it_value, _nextTime)) {
48 return false;
51 if (_nextTime == 0)
52 _nextTime = B_INFINITE_TIMEOUT;
54 return true;
58 static status_t
59 timer_thread_entry(void* _entry, void* _value)
61 // init a pthread
62 pthread_thread thread;
63 __init_pthread(&thread, NULL, NULL);
64 thread.flags |= THREAD_DETACHED;
66 get_user_thread()->pthread = &thread;
68 // we have been started with deferred signals -- undefer them
69 undefer_signals();
71 // prepare the arguments
72 union sigval value;
73 value.sival_ptr = _value;
74 void (*entry)(union sigval) = (void (*)(union sigval))_entry;
76 // call the entry function
77 entry(value);
79 return B_OK;
83 // #pragma mark -
86 int
87 timer_create(clockid_t clockID, struct sigevent* event, timer_t* _timer)
89 // create a timer object
90 __timer_t* timer = new(std::nothrow) __timer_t;
91 if (timer == NULL)
92 RETURN_AND_SET_ERRNO(ENOMEM);
93 ObjectDeleter<__timer_t> timerDeleter(timer);
95 // If the notification method is SIGEV_THREAD, initialize thread creation
96 // attributes.
97 bool isThreadEvent = event != NULL && event->sigev_notify == SIGEV_THREAD;
98 thread_creation_attributes threadAttributes;
99 if (isThreadEvent) {
100 status_t error = __pthread_init_creation_attributes(
101 event->sigev_notify_attributes, NULL, &timer_thread_entry,
102 (void*)event->sigev_notify_function, event->sigev_value.sival_ptr,
103 "timer notify", &threadAttributes);
104 if (error != B_OK)
105 RETURN_AND_SET_ERRNO(error);
107 threadAttributes.flags |= THREAD_CREATION_FLAG_DEFER_SIGNALS;
110 // create the timer
111 int32 timerID = _kern_create_timer(clockID, -1, 0, event,
112 isThreadEvent ? &threadAttributes : NULL);
113 if (timerID < 0)
114 RETURN_AND_SET_ERRNO(timerID);
116 // init the object members
117 timer->SetTo(timerID, -1);
119 *_timer = timerDeleter.Detach();
120 return 0;
125 timer_delete(timer_t timer)
127 status_t error = _kern_delete_timer(timer->id, timer->thread);
128 if (error != B_OK)
129 RETURN_AND_SET_ERRNO(error);
131 delete timer;
132 return 0;
137 timer_gettime(timer_t timer, struct itimerspec* value)
139 user_timer_info info;
140 status_t error = _kern_get_timer(timer->id, timer->thread, &info);
141 if (error != B_OK)
142 RETURN_AND_SET_ERRNO(error);
144 info_to_itimerspec(info, *value);
146 return 0;
151 timer_settime(timer_t timer, int flags, const struct itimerspec* value,
152 struct itimerspec* oldValue)
154 // translate new value
155 bigtime_t nextTime;
156 bigtime_t interval;
157 if (!itimerspec_to_bigtimes(*value, nextTime, interval))
158 RETURN_AND_SET_ERRNO(EINVAL);
160 uint32 timeoutFlags = (flags & TIMER_ABSTIME) != 0
161 ? B_ABSOLUTE_TIMEOUT : B_RELATIVE_TIMEOUT;
163 // set the timer
164 user_timer_info oldInfo;
165 status_t error = _kern_set_timer(timer->id, timer->thread, nextTime,
166 interval, timeoutFlags, oldValue != NULL ? &oldInfo : NULL);
167 if (error != B_OK)
168 RETURN_AND_SET_ERRNO(error);
170 // translate old info back
171 if (oldValue != NULL)
172 info_to_itimerspec(oldInfo, *oldValue);
174 return 0;
179 timer_getoverrun(timer_t timer)
181 user_timer_info info;
182 status_t error = _kern_get_timer(timer->id, timer->thread, &info);
183 if (error != B_OK)
184 RETURN_AND_SET_ERRNO(error);
186 return info.overrun_count;