/* timerfd.h: Define timerfd classes This file is part of Cygwin. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #ifndef __TIMERFD_H__ #define __TIMERFD_H__ #include "clock.h" #include "ntdll.h" class timerfd_shared { clockid_t _clockid; /* clockid */ struct itimerspec _time_spec; /* original incoming itimerspec */ LONG64 _exp_ts; /* start timestamp or next expire timestamp in 100ns */ LONG64 _interval; /* timer interval in 100ns */ LONG64 _expiration_count; /* expiry counter */ int _flags; /* settime flags */ DWORD _tc_time; /* timestamp of the last WM_TIMECHANGE msg */ /* read access methods */ LONG64 get_clock_now () const { return get_clock (_clockid)->n100secs (); } struct itimerspec &time_spec () { return _time_spec; } int get_flags () const { return _flags; } void set_flags (int nflags) { _flags = nflags; } /* write access methods */ void set_clockid (clockid_t clock_id) { _clockid = clock_id; } void increment_expiration_count (LONG64 add) { InterlockedAdd64 (&_expiration_count, add); } void set_expiration_count (LONG64 newval) { InterlockedExchange64 (&_expiration_count, newval); } LONG64 reset_expiration_count () { return InterlockedExchange64 (&_expiration_count, 0); } int arm_timer (int, const struct itimerspec *); int disarm_timer () { memset (&_time_spec, 0, sizeof _time_spec); _exp_ts = 0; _interval = 0; /* _flags = 0; DON'T DO THAT. Required for TFD_TIMER_CANCEL_ON_SET */ return 0; } void set_exp_ts (LONG64 ts) { _exp_ts = ts; } friend class timerfd_tracker; }; class timerfd_tracker /* cygheap! */ { /* Shared handles */ HANDLE tfd_shared_hdl; /* handle to shared mem */ HANDLE _access_mtx; /* controls access to shared data */ HANDLE _arm_evt; /* settimer sets event when timer is armed, unsets event when timer gets disarmed. */ HANDLE _disarm_evt; /* settimer sets event when timer is armed, unsets event when timer gets disarmed. */ HANDLE _timer; /* SynchronizationTimer */ HANDLE _expired_evt; /* Signal if timer expired, Unsignal on read. */ /* Process-local handles */ HANDLE cancel_evt; /* Signal thread to exit. */ HANDLE sync_thr; /* cygthread sync object. */ /* pointer to shared timerfd, misc */ timerfd_shared *tfd_shared; /* pointer to shared mem, needs NtMapViewOfSection in each new process. */ LONG instance_count; /* each open fd increments this. If 0 -> cancel thread. */ DWORD winpid; /* This is used @ fork/exec time to know if this tracker already has been fixed up. */ HWND window; /* window handle */ ATOM atom; /* window class */ void create_timechange_window (); void delete_timechange_window (); void handle_timechange_window (); bool dtor (); bool enter_critical_section () { return (WaitForSingleObject (_access_mtx, INFINITE) & ~WAIT_ABANDONED_0) == WAIT_OBJECT_0; } /* A version that honors a cancel event, for use in thread_func. */ int enter_critical_section_cancelable (); void leave_critical_section () { ReleaseMutex (_access_mtx); } HANDLE arm_evt () const { return _arm_evt; } HANDLE disarm_evt () const { return _disarm_evt; } HANDLE timer () const { return _timer; } HANDLE expired_evt () const { return _expired_evt; } void timer_expired () { SetEvent (_expired_evt); } int arm_timer (int flags, const struct itimerspec *new_value); int disarm_timer () { ResetEvent (_arm_evt); tfd_shared->disarm_timer (); NtCancelTimer (timer (), NULL); SetEvent (_disarm_evt); return 0; } void timer_expired () const { timer_expired (); } LONG64 expiration_count () const { return tfd_shared->_expiration_count; } void increment_expiration_count (LONG64 add) const { tfd_shared->increment_expiration_count (add); } void set_expiration_count (LONG64 exp_cnt) const { tfd_shared->set_expiration_count ((LONG64) exp_cnt); } LONG64 read_and_reset_expiration_count () { LONG64 ret = tfd_shared->reset_expiration_count (); if (ret) ResetEvent (_expired_evt); return ret; } struct timespec it_value () const { return tfd_shared->time_spec ().it_value; } struct timespec it_interval () const { return tfd_shared->time_spec ().it_interval; } void set_clockid (clockid_t clock_id) { tfd_shared->set_clockid (clock_id); } clock_t get_clockid () const { return tfd_shared->_clockid; } LONG64 get_clock_now () const { return tfd_shared->get_clock_now (); } struct itimerspec &time_spec () { return tfd_shared->time_spec (); } LONG64 get_exp_ts () const { return tfd_shared->_exp_ts; } LONG64 get_interval () const { return tfd_shared->_interval; } void set_interval (LONG64 intv) { tfd_shared->_interval = intv; } int get_flags () const { return tfd_shared->get_flags (); } void set_flags (int nflags) { tfd_shared->set_flags (nflags); } DWORD tc_time () const { return tfd_shared->_tc_time; } void set_tc_time (DWORD new_time) { tfd_shared->_tc_time = new_time; } void set_exp_ts (LONG64 ts) const { tfd_shared->set_exp_ts (ts); } LONG decrement_instances () { return InterlockedDecrement (&instance_count); } public: void *operator new (size_t, void *p) __attribute__ ((nothrow)) {return p;} timerfd_tracker () : tfd_shared_hdl (NULL), _access_mtx (NULL), _arm_evt (NULL), _disarm_evt (NULL), cancel_evt (NULL), sync_thr (NULL), tfd_shared (NULL), instance_count (1), winpid (0), window (NULL), atom (0) {} void init_fixup_after_fork_exec (); void fixup_after_fork_exec (bool); void fixup_after_fork () { init_fixup_after_fork_exec (); fixup_after_fork_exec (false); } void fixup_after_exec () { fixup_after_fork_exec (true); } void dup () { InterlockedIncrement (&instance_count); } HANDLE get_timerfd_handle () const { return expired_evt (); } LONG64 wait (bool); int ioctl_set_ticks (uint64_t); int create (clockid_t); int gettime (struct itimerspec *); int settime (int, const struct itimerspec *, struct itimerspec *); static void dtor (timerfd_tracker *); DWORD thread_func (); }; #endif /* __TIMERFD_H__ */