diff --git a/winsup/cygwin/fhandler_timerfd.cc b/winsup/cygwin/fhandler_timerfd.cc index cbcbefdcb..360731ca1 100644 --- a/winsup/cygwin/fhandler_timerfd.cc +++ b/winsup/cygwin/fhandler_timerfd.cc @@ -176,15 +176,29 @@ int fhandler_timerfd::ioctl (unsigned int cmd, void *p) { int ret = -1; + uint64_t ov_cnt; switch (cmd) { case TFD_IOC_SET_TICKS: - /* TODO */ + __try + { + timer_tracker *tt = (timer_tracker *) timerid; + + ov_cnt = *(uint64_t *) p; + if (!ov_cnt) + { + set_errno (EINVAL); + break; + } + tt->set_event (ov_cnt); + } + __except (EFAULT) {} + __endtry ret = 0; break; default: - set_errno (EINVAL); + ret = fhandler_base::ioctl (cmd, p); break; } syscall_printf ("%d = ioctl_timerfd(%x, %p)", ret, cmd, p); diff --git a/winsup/cygwin/timer.cc b/winsup/cygwin/timer.cc index be3fcf7c5..c97274538 100644 --- a/winsup/cygwin/timer.cc +++ b/winsup/cygwin/timer.cc @@ -132,6 +132,22 @@ timer_tracker::arm_event () return ret; } +void +timer_tracker::set_event (uint64_t ov_cnt) +{ + LONG ret; + + while ((ret = InterlockedCompareExchange (&event_running, EVENT_LOCK, + EVENT_DISARMED)) == EVENT_LOCK) + yield (); + InterlockedExchange64 (&overrun_count, ov_cnt); + if (ret == EVENT_DISARMED) + { + SetEvent (get_timerfd_handle ()); + InterlockedExchange (&event_running, EVENT_ARMED); + } +} + LONG64 timer_tracker::_disarm_event () { diff --git a/winsup/cygwin/timer.h b/winsup/cygwin/timer.h index 3b426a308..b9a072e6d 100644 --- a/winsup/cygwin/timer.h +++ b/winsup/cygwin/timer.h @@ -55,7 +55,9 @@ class timer_tracker void gettime (itimerspec *); int settime (int, const itimerspec *, itimerspec *); + LONG arm_event (); + void set_event (uint64_t ov_cnt); unsigned int disarm_event (); DWORD thread_func ();