3 Copyright 2004, 2005 Red Hat, Inc.
5 This file is part of Cygwin.
7 This software is a copyrighted work licensed under the terms of the
8 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
26 #define TT_MAGIC 0x513e4a1c
35 long long interval_us;
38 struct timer_tracker *next;
39 int settime (int, const itimerspec *, itimerspec *);
40 void gettime (itimerspec *);
41 timer_tracker (clockid_t, const sigevent *);
43 friend void fixup_timers_after_fork ();
46 timer_tracker NO_COPY ttstart (CLOCK_REALTIME, NULL);
48 class lock_timer_tracker
52 lock_timer_tracker ();
53 ~lock_timer_tracker ();
56 muto NO_COPY lock_timer_tracker::protect;
58 lock_timer_tracker::lock_timer_tracker ()
60 protect.init ("timer_protect")->acquire ();
63 lock_timer_tracker::~lock_timer_tracker ()
69 timer_tracker::cancel ()
75 if (WaitForSingleObject (syncthread, INFINITE) != WAIT_OBJECT_0)
76 api_fatal ("WFSO failed waiting for timer thread, %E");
80 timer_tracker::~timer_tracker ()
84 CloseHandle (hcancel);
90 CloseHandle (syncthread);
94 timer_tracker::timer_tracker (clockid_t c, const sigevent *e)
100 evp.sigev_notify = SIGEV_SIGNAL;
101 evp.sigev_signo = SIGALRM;
102 evp.sigev_value.sival_ptr = this;
107 if (this != &ttstart)
109 lock_timer_tracker here;
116 to_us (const timespec& ts)
118 long long res = ts.tv_sec;
120 res += ts.tv_nsec / 1000 + ((ts.tv_nsec % 1000) ? 1 : 0);
125 timer_thread (VOID *x)
127 timer_tracker *tt = ((timer_tracker *) x);
129 long long sleepto_us = tt->sleepto_us;
134 /* Account for delays in starting thread
135 and sending the signal */
137 sleep_us = sleepto_us - now;
140 tt->sleepto_us = sleepto_us;
141 sleep_ms = (sleep_us + 999) / 1000;
145 tt->sleepto_us = now;
149 debug_printf ("%p waiting for %u ms", x, sleep_ms);
150 switch (WaitForSingleObject (tt->hcancel, sleep_ms))
153 debug_printf ("timed out");
156 debug_printf ("%p cancelled", x);
159 debug_printf ("%p wait failed, %E", x);
163 switch (tt->evp.sigev_notify)
168 memset (&si, 0, sizeof (si));
169 si.si_signo = tt->evp.sigev_signo;
170 si.si_sigval.sival_ptr = tt->evp.sigev_value.sival_ptr;
171 debug_printf ("%p sending sig %d", x, tt->evp.sigev_signo);
172 sig_send (myself_nowait, si);
177 pthread_t notify_thread;
178 debug_printf ("%p starting thread", x);
179 int rc = pthread_create (¬ify_thread, tt->evp.sigev_notify_attributes,
180 (void * (*) (void *)) tt->evp.sigev_notify_function,
181 tt->evp.sigev_value.sival_ptr);
184 debug_printf ("thread creation failed, %E");
187 // FIXME: pthread_join?
191 if (!tt->interval_us)
194 sleepto_us = tt->sleepto_us + tt->interval_us;
195 debug_printf ("looping");
199 _my_tls._ctinfo->auto_release (); /* automatically return the cygthread to the cygthread pool */
204 it_bad (const timespec& t)
206 if (t.tv_nsec < 0 || t.tv_nsec >= 1000000000 || t.tv_sec < 0)
215 timer_tracker::settime (int in_flags, const itimerspec *value, itimerspec *ovalue)
224 if (efault.faulted (EFAULT)
225 || it_bad (value->it_value)
226 || it_bad (value->it_interval))
229 long long now = in_flags & TIMER_ABSTIME ? 0 : gtod.usecs ();
231 lock_timer_tracker here;
237 if (!value->it_value.tv_sec && !value->it_value.tv_nsec)
238 interval_us = sleepto_us = 0;
241 sleepto_us = now + to_us (value->it_value);
242 interval_us = to_us (value->it_interval);
243 it_interval = value->it_interval;
245 hcancel = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
247 ResetEvent (hcancel);
249 syncthread = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
251 ResetEvent (syncthread);
252 new cygthread (timer_thread, 0, this, "itimer", syncthread);
259 timer_tracker::gettime (itimerspec *ovalue)
262 memset (ovalue, 0, sizeof (*ovalue));
265 ovalue->it_interval = it_interval;
266 long long now = gtod.usecs ();
267 long long left_us = sleepto_us - now;
270 ovalue->it_value.tv_sec = left_us / 1000000;
271 ovalue->it_value.tv_nsec = (left_us % 1000000) * 1000;
276 timer_gettime (timer_t timerid, struct itimerspec *ovalue)
279 if (efault.faulted (EFAULT))
282 timer_tracker *tt = (timer_tracker *) timerid;
283 if (tt->magic != TT_MAGIC)
289 tt->gettime (ovalue);
294 timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
297 if (efault.faulted (EFAULT))
299 if (clock_id != CLOCK_REALTIME)
305 *timerid = (timer_t) new timer_tracker (clock_id, evp);
310 timer_settime (timer_t timerid, int flags, const struct itimerspec *value,
311 struct itimerspec *ovalue)
313 timer_tracker *tt = (timer_tracker *) timerid;
315 if (efault.faulted (EFAULT))
317 if (tt->magic != TT_MAGIC)
323 return tt->settime (flags, value, ovalue);
327 timer_delete (timer_t timerid)
329 timer_tracker *in_tt = (timer_tracker *) timerid;
331 if (efault.faulted (EFAULT))
333 if (in_tt->magic != TT_MAGIC)
339 lock_timer_tracker here;
340 for (timer_tracker *tt = &ttstart; tt->next != NULL; tt = tt->next)
341 if (tt->next == in_tt)
343 tt->next = in_tt->next;
352 fixup_timers_after_fork ()
354 ttstart.hcancel = ttstart.syncthread = NULL;
355 for (timer_tracker *tt = &ttstart; tt->next != NULL; /* nothing */)
357 timer_tracker *deleteme = tt->next;
358 tt->next = deleteme->next;
359 deleteme->hcancel = deleteme->syncthread = NULL;
366 setitimer (int which, const struct itimerval *value, struct itimerval *ovalue)
368 if (which != ITIMER_REAL)
373 struct itimerspec spec_value, spec_ovalue;
375 spec_value.it_interval.tv_sec = value->it_interval.tv_sec;
376 spec_value.it_interval.tv_nsec = value->it_interval.tv_usec * 1000;
377 spec_value.it_value.tv_sec = value->it_value.tv_sec;
378 spec_value.it_value.tv_nsec = value->it_value.tv_usec * 1000;
379 ret = timer_settime ((timer_t) &ttstart, 0, &spec_value, &spec_ovalue);
382 ovalue->it_interval.tv_sec = spec_ovalue.it_interval.tv_sec;
383 ovalue->it_interval.tv_usec = spec_ovalue.it_interval.tv_nsec / 1000;
384 ovalue->it_value.tv_sec = spec_ovalue.it_value.tv_sec;
385 ovalue->it_value.tv_usec = spec_ovalue.it_value.tv_nsec / 1000;
387 syscall_printf ("%d = setitimer ()", ret);
393 getitimer (int which, struct itimerval *ovalue)
395 if (which != ITIMER_REAL)
401 if (efault.faulted (EFAULT))
403 struct itimerspec spec_ovalue;
404 int ret = timer_gettime ((timer_t) &ttstart, &spec_ovalue);
407 ovalue->it_interval.tv_sec = spec_ovalue.it_interval.tv_sec;
408 ovalue->it_interval.tv_usec = spec_ovalue.it_interval.tv_nsec / 1000;
409 ovalue->it_value.tv_sec = spec_ovalue.it_value.tv_sec;
410 ovalue->it_value.tv_usec = spec_ovalue.it_value.tv_nsec / 1000;
412 syscall_printf ("%d = getitimer ()", ret);
416 /* FIXME: POSIX - alarm survives exec */
417 extern "C" unsigned int
418 alarm (unsigned int seconds)
420 struct itimerspec newt = {}, oldt;
421 /* alarm cannot fail, but only needs not be
422 correct for arguments < 64k. Truncate */
423 if (seconds > (HIRES_DELAY_MAX / 1000 - 1))
424 seconds = (HIRES_DELAY_MAX / 1000 - 1);
425 newt.it_value.tv_sec = seconds;
426 timer_settime ((timer_t) &ttstart, 0, &newt, &oldt);
427 int ret = oldt.it_value.tv_sec + (oldt.it_value.tv_nsec > 0);
428 syscall_printf ("%d = alarm (%d)", ret, seconds);
432 extern "C" useconds_t
433 ualarm (useconds_t value, useconds_t interval)
435 struct itimerspec timer = {}, otimer;
436 /* ualarm cannot fail.
437 Interpret negative arguments as zero */
440 timer.it_value.tv_sec = (unsigned int) value / 1000000;
441 timer.it_value.tv_nsec = ((unsigned int) value % 1000000) * 1000;
445 timer.it_interval.tv_sec = (unsigned int) interval / 1000000;
446 timer.it_interval.tv_nsec = ((unsigned int) interval % 1000000) * 1000;
448 timer_settime ((timer_t) &ttstart, 0, &timer, &otimer);
449 useconds_t ret = otimer.it_value.tv_sec * 1000000 + (otimer.it_value.tv_nsec + 999) / 1000;
450 syscall_printf ("%d = ualarm (%d , %d)", ret, value, interval);