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
20 #define TT_MAGIC 0x513e4a1c
29 long long interval_us;
32 struct timer_tracker *next;
33 int settime (int, const itimerspec *, itimerspec *);
34 void gettime (itimerspec *);
35 timer_tracker (clockid_t, const sigevent *);
37 friend void fixup_timers_after_fork ();
40 timer_tracker NO_COPY ttstart (CLOCK_REALTIME, NULL);
42 class lock_timer_tracker
46 lock_timer_tracker ();
47 ~lock_timer_tracker ();
50 muto NO_COPY lock_timer_tracker::protect;
52 lock_timer_tracker::lock_timer_tracker ()
54 protect.init ("timer_protect")->acquire ();
57 lock_timer_tracker::~lock_timer_tracker ()
63 timer_tracker::cancel ()
69 if (WaitForSingleObject (syncthread, INFINITE) != WAIT_OBJECT_0)
70 api_fatal ("WFSO failed waiting for timer thread, %E");
74 timer_tracker::~timer_tracker ()
78 CloseHandle (hcancel);
84 CloseHandle (syncthread);
88 timer_tracker::timer_tracker (clockid_t c, const sigevent *e)
94 evp.sigev_notify = SIGEV_SIGNAL;
95 evp.sigev_signo = SIGALRM;
96 evp.sigev_value.sival_ptr = this;
101 if (this != &ttstart)
103 lock_timer_tracker here;
110 to_us (const timespec& ts)
112 long long res = ts.tv_sec;
114 res += ts.tv_nsec / 1000 + ((ts.tv_nsec % 1000) ? 1 : 0);
119 timer_thread (VOID *x)
121 timer_tracker *tt = ((timer_tracker *) x);
123 long long sleepto_us = tt->sleepto_us;
128 /* Account for delays in starting thread
129 and sending the signal */
131 sleep_us = sleepto_us - now;
134 tt->sleepto_us = sleepto_us;
135 sleep_ms = (sleep_us + 999) / 1000;
139 tt->sleepto_us = now;
143 debug_printf ("%p waiting for %u ms", x, sleep_ms);
144 switch (WaitForSingleObject (tt->hcancel, sleep_ms))
147 debug_printf ("timed out");
150 debug_printf ("%p cancelled", x);
153 debug_printf ("%p wait failed, %E", x);
157 switch (tt->evp.sigev_notify)
162 si.si_signo = tt->evp.sigev_signo;
163 si.si_sigval.sival_ptr = tt->evp.sigev_value.sival_ptr;
164 si.si_code = SI_TIMER;
165 debug_printf ("%p sending sig %d", x, tt->evp.sigev_signo);
166 sig_send (myself_nowait, si);
171 pthread_t notify_thread;
172 debug_printf ("%p starting thread", x);
173 pthread_attr_t *attr;
174 pthread_attr_t default_attr;
175 if (tt->evp.sigev_notify_attributes)
176 attr = tt->evp.sigev_notify_attributes;
179 pthread_attr_init(attr = &default_attr);
180 pthread_attr_setdetachstate (attr, PTHREAD_CREATE_DETACHED);
183 int rc = pthread_create (¬ify_thread, attr,
184 (void * (*) (void *)) tt->evp.sigev_notify_function,
185 tt->evp.sigev_value.sival_ptr);
188 debug_printf ("thread creation failed, %E");
191 // FIXME: pthread_join?
195 if (!tt->interval_us)
198 sleepto_us = tt->sleepto_us + tt->interval_us;
199 debug_printf ("looping");
203 _my_tls._ctinfo->auto_release (); /* automatically return the cygthread to the cygthread pool */
208 it_bad (const timespec& t)
210 if (t.tv_nsec < 0 || t.tv_nsec >= 1000000000 || t.tv_sec < 0)
219 timer_tracker::settime (int in_flags, const itimerspec *value, itimerspec *ovalue)
228 if (efault.faulted (EFAULT)
229 || it_bad (value->it_value)
230 || it_bad (value->it_interval))
233 long long now = in_flags & TIMER_ABSTIME ? 0 : gtod.usecs ();
235 lock_timer_tracker here;
241 if (!value->it_value.tv_sec && !value->it_value.tv_nsec)
242 interval_us = sleepto_us = 0;
245 sleepto_us = now + to_us (value->it_value);
246 interval_us = to_us (value->it_interval);
247 it_interval = value->it_interval;
249 hcancel = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
251 ResetEvent (hcancel);
253 syncthread = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL);
255 ResetEvent (syncthread);
256 new cygthread (timer_thread, this, "itimer", syncthread);
263 timer_tracker::gettime (itimerspec *ovalue)
266 memset (ovalue, 0, sizeof (*ovalue));
269 ovalue->it_interval = it_interval;
270 long long now = gtod.usecs ();
271 long long left_us = sleepto_us - now;
274 ovalue->it_value.tv_sec = left_us / 1000000;
275 ovalue->it_value.tv_nsec = (left_us % 1000000) * 1000;
280 timer_gettime (timer_t timerid, struct itimerspec *ovalue)
283 if (efault.faulted (EFAULT))
286 timer_tracker *tt = (timer_tracker *) timerid;
287 if (tt->magic != TT_MAGIC)
293 tt->gettime (ovalue);
298 timer_create (clockid_t clock_id, struct sigevent *evp, timer_t *timerid)
301 if (efault.faulted (EFAULT))
303 if (clock_id != CLOCK_REALTIME)
309 *timerid = (timer_t) new timer_tracker (clock_id, evp);
314 timer_settime (timer_t timerid, int flags, const struct itimerspec *value,
315 struct itimerspec *ovalue)
317 timer_tracker *tt = (timer_tracker *) timerid;
319 if (efault.faulted (EFAULT))
321 if (tt->magic != TT_MAGIC)
327 return tt->settime (flags, value, ovalue);
331 timer_delete (timer_t timerid)
333 timer_tracker *in_tt = (timer_tracker *) timerid;
335 if (efault.faulted (EFAULT))
337 if (in_tt->magic != TT_MAGIC)
343 lock_timer_tracker here;
344 for (timer_tracker *tt = &ttstart; tt->next != NULL; tt = tt->next)
345 if (tt->next == in_tt)
347 tt->next = in_tt->next;
356 fixup_timers_after_fork ()
358 ttstart.hcancel = ttstart.syncthread = NULL;
359 for (timer_tracker *tt = &ttstart; tt->next != NULL; /* nothing */)
361 timer_tracker *deleteme = tt->next;
362 tt->next = deleteme->next;
363 deleteme->hcancel = deleteme->syncthread = NULL;
370 setitimer (int which, const struct itimerval *value, struct itimerval *ovalue)
372 if (which != ITIMER_REAL)
377 struct itimerspec spec_value, spec_ovalue;
379 spec_value.it_interval.tv_sec = value->it_interval.tv_sec;
380 spec_value.it_interval.tv_nsec = value->it_interval.tv_usec * 1000;
381 spec_value.it_value.tv_sec = value->it_value.tv_sec;
382 spec_value.it_value.tv_nsec = value->it_value.tv_usec * 1000;
383 ret = timer_settime ((timer_t) &ttstart, 0, &spec_value, &spec_ovalue);
386 ovalue->it_interval.tv_sec = spec_ovalue.it_interval.tv_sec;
387 ovalue->it_interval.tv_usec = spec_ovalue.it_interval.tv_nsec / 1000;
388 ovalue->it_value.tv_sec = spec_ovalue.it_value.tv_sec;
389 ovalue->it_value.tv_usec = spec_ovalue.it_value.tv_nsec / 1000;
391 syscall_printf ("%d = setitimer ()", ret);
397 getitimer (int which, struct itimerval *ovalue)
399 if (which != ITIMER_REAL)
405 if (efault.faulted (EFAULT))
407 struct itimerspec spec_ovalue;
408 int ret = timer_gettime ((timer_t) &ttstart, &spec_ovalue);
411 ovalue->it_interval.tv_sec = spec_ovalue.it_interval.tv_sec;
412 ovalue->it_interval.tv_usec = spec_ovalue.it_interval.tv_nsec / 1000;
413 ovalue->it_value.tv_sec = spec_ovalue.it_value.tv_sec;
414 ovalue->it_value.tv_usec = spec_ovalue.it_value.tv_nsec / 1000;
416 syscall_printf ("%d = getitimer ()", ret);
420 /* FIXME: POSIX - alarm survives exec */
421 extern "C" unsigned int
422 alarm (unsigned int seconds)
424 struct itimerspec newt = {}, oldt;
425 /* alarm cannot fail, but only needs not be
426 correct for arguments < 64k. Truncate */
427 if (seconds > (HIRES_DELAY_MAX / 1000 - 1))
428 seconds = (HIRES_DELAY_MAX / 1000 - 1);
429 newt.it_value.tv_sec = seconds;
430 timer_settime ((timer_t) &ttstart, 0, &newt, &oldt);
431 int ret = oldt.it_value.tv_sec + (oldt.it_value.tv_nsec > 0);
432 syscall_printf ("%d = alarm (%d)", ret, seconds);
436 extern "C" useconds_t
437 ualarm (useconds_t value, useconds_t interval)
439 struct itimerspec timer = {}, otimer;
440 /* ualarm cannot fail.
441 Interpret negative arguments as zero */
444 timer.it_value.tv_sec = (unsigned int) value / 1000000;
445 timer.it_value.tv_nsec = ((unsigned int) value % 1000000) * 1000;
449 timer.it_interval.tv_sec = (unsigned int) interval / 1000000;
450 timer.it_interval.tv_nsec = ((unsigned int) interval % 1000000) * 1000;
452 timer_settime ((timer_t) &ttstart, 0, &timer, &otimer);
453 useconds_t ret = otimer.it_value.tv_sec * 1000000 + (otimer.it_value.tv_nsec + 999) / 1000;
454 syscall_printf ("%d = ualarm (%d , %d)", ret, value, interval);