-/*--------------------------------------------------------------------*/
-/* Async timers */
-/*--------------------------------------------------------------------*/
-
-/* We emulate two timers, one for SIGALRM, another for SIGPROF.
-
- itimerproc() function has an implementation limitation: it does
- not allow to set *both* interval and period. If an attempt is
- made to set both, and then they are unequal, the function
- asserts.
-
- Minimum timer resolution on Win32 systems varies, and is greater
- than or equal than 1 ms. The resolution is always wrapped not to
- attempt to get below the system defined limit.
- */
-
-/* Timer precision, denominator of one fraction: for 100 ms
- interval, request 10 ms precision
- */
-const int timer_prec = 10;
-
-/* Last itimervals, as set by calls to setitimer */
-static struct itimerval it_alarm;
-static struct itimerval it_prof;
-
-/* Timer IDs as returned by MM */
-MMRESULT tid_alarm = 0;
-MMRESULT tid_prof = 0;
-
-static void CALLBACK timer_proc (UINT uID, UINT uMsg, DWORD dwUser,
- DWORD dw1, DWORD dw2)
-{
- /* Just raise a signal indicated by dwUser parameter */
- mswindows_raise (dwUser);
-}
-
-/* Divide time in ms specified by IT by DENOM. Return 1 ms
- if division results in zero */
-static UINT period (const struct itimerval* it, UINT denom)
-{
- static TIMECAPS time_caps;
-
- UINT res;
- const struct timeval* tv =
- (it->it_value.tv_sec == 0 && it->it_value.tv_usec == 0)
- ? &it->it_interval : &it->it_value;
-
- /* Zero means stop timer */
- if (tv->tv_sec == 0 && tv->tv_usec == 0)
- return 0;
-
- /* Convert to ms and divide by denom */
- res = (tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) / denom;
-
- /* Converge to minimum timer resolution */
- if (time_caps.wPeriodMin == 0)
- timeGetDevCaps (&time_caps, sizeof(time_caps));
-
- if (res < time_caps.wPeriodMin)
- res = time_caps.wPeriodMin;
-
- return res;
-}
-
-static int setitimer_helper (const struct itimerval* itnew,
- struct itimerval* itold, struct itimerval* itcurrent,
- MMRESULT* tid, DWORD sigkind)
-{
- UINT delay, resolution, event_type;
-
- /* First stop the old timer */
- if (*tid)
- {
- timeKillEvent (*tid);
- timeEndPeriod (period (itcurrent, timer_prec));
- *tid = 0;
- }
-
- /* Return old itimerval if requested */
- if (itold)
- *itold = *itcurrent;
-
- *itcurrent = *itnew;
-
- /* Determine if to start new timer */
- delay = period (itnew, 1);
- if (delay)
- {
- resolution = period (itnew, timer_prec);
- event_type = (itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
- ? TIME_ONESHOT : TIME_PERIODIC;
- timeBeginPeriod (resolution);
- *tid = timeSetEvent (delay, resolution, timer_proc, sigkind, event_type);
- }
-
- return !delay || *tid;
-}
-
-int setitimer (int kind, const struct itimerval* itnew,
- struct itimerval* itold)
-{
- /* In this version, both interval and value are allowed
- only if they are equal. */
- assert ((itnew->it_value.tv_sec == 0 && itnew->it_value.tv_usec == 0)
- || (itnew->it_interval.tv_sec == 0 && itnew->it_interval.tv_usec == 0)
- || (itnew->it_value.tv_sec == itnew->it_interval.tv_sec &&
- itnew->it_value.tv_usec == itnew->it_interval.tv_usec));
-
- if (kind == ITIMER_REAL)
- return setitimer_helper (itnew, itold, &it_alarm, &tid_alarm, SIGALRM);
- else if (kind == ITIMER_PROF)
- return setitimer_helper (itnew, itold, &it_prof, &tid_prof, SIGPROF);
- else
- return errno = EINVAL;
-}
-