175 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			175 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
/* 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__ */
 |