Welcome to mirror list, hosted at ThFree Co, Russian Federation.

timerfd.h « local_includes « cygwin « winsup - cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 80688e79ec5e67b564b57fc5004a3b235fcdc685 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/* 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__ */