ReactOS  0.4.14-dev-608-gd495a4f
timerqueue.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS system libraries
4  * PURPOSE: Timer Queue implementation
5  * FILE: lib/rtl/timerqueue.c
6  * PROGRAMMER:
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include <rtl.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 #undef LIST_FOR_EACH
17 #undef LIST_FOR_EACH_SAFE
18 #include <wine/list.h>
19 
20 /* FUNCTIONS ***************************************************************/
21 
25 
28 {
30 }
31 
33 {
34  if (timeout == INFINITE) return NULL;
35  pTime->QuadPart = (ULONGLONG)timeout * -10000;
36  return pTime;
37 }
38 
39 struct timer_queue;
41 {
42  struct timer_queue *q;
43  struct list entry;
44  ULONG runcount; /* number of callbacks pending execution */
50  BOOL destroy; /* timer should be deleted; once set, never unset */
51  HANDLE event; /* removal event */
52 };
53 
55 {
58  struct list timers; /* sorted by expiration time */
59  BOOL quit; /* queue should be deleted; once set, never unset */
62 };
63 
64 #define EXPIRE_NEVER (~(ULONGLONG) 0)
65 #define TIMER_QUEUE_MAGIC 0x516d6954 /* TimQ */
66 
67 static void queue_remove_timer(struct queue_timer *t)
68 {
69  /* We MUST hold the queue cs while calling this function. This ensures
70  that we cannot queue another callback for this timer. The runcount
71  being zero makes sure we don't have any already queued. */
72  struct timer_queue *q = t->q;
73 
74  assert(t->runcount == 0);
75  assert(t->destroy);
76 
77  list_remove(&t->entry);
78  if (t->event)
79  NtSetEvent(t->event, NULL);
80  RtlFreeHeap(RtlGetProcessHeap(), 0, t);
81 
82  if (q->quit && list_empty(&q->timers))
83  NtSetEvent(q->event, NULL);
84 }
85 
86 static void timer_cleanup_callback(struct queue_timer *t)
87 {
88  struct timer_queue *q = t->q;
90 
91  assert(0 < t->runcount);
92  --t->runcount;
93 
94  if (t->destroy && t->runcount == 0)
96 
98 }
99 
101 {
102  struct queue_timer *t = p;
103  t->callback(t->param, TRUE);
105 }
106 
107 static inline ULONGLONG queue_current_time(void)
108 {
109  LARGE_INTEGER now, freq;
111  return now.QuadPart * 1000 / freq.QuadPart;
112 }
113 
115  BOOL set_event)
116 {
117  /* We MUST hold the queue cs while calling this function. */
118  struct timer_queue *q = t->q;
119  struct list *ptr = &q->timers;
120 
121  assert(!q->quit || (t->destroy && time == EXPIRE_NEVER));
122 
123  if (time != EXPIRE_NEVER)
124  LIST_FOR_EACH(ptr, &q->timers)
125  {
126  struct queue_timer *cur = LIST_ENTRY(ptr, struct queue_timer, entry);
127  if (time < cur->expire)
128  break;
129  }
130  list_add_before(ptr, &t->entry);
131 
132  t->expire = time;
133 
134  /* If we insert at the head of the list, we need to expire sooner
135  than expected. */
136  if (set_event && &t->entry == list_head(&q->timers))
137  NtSetEvent(q->event, NULL);
138 }
139 
140 static inline void queue_move_timer(struct queue_timer *t, ULONGLONG time,
141  BOOL set_event)
142 {
143  /* We MUST hold the queue cs while calling this function. */
144  list_remove(&t->entry);
145  queue_add_timer(t, time, set_event);
146 }
147 
148 static void queue_timer_expire(struct timer_queue *q)
149 {
150  struct queue_timer *t = NULL;
151 
153  if (list_head(&q->timers))
154  {
155  ULONGLONG now, next;
156  t = LIST_ENTRY(list_head(&q->timers), struct queue_timer, entry);
157  if (!t->destroy && t->expire <= ((now = queue_current_time())))
158  {
159  ++t->runcount;
160  if (t->period)
161  {
162  next = t->expire + t->period;
163  /* avoid trigger cascade if overloaded / hibernated */
164  if (next < now)
165  next = now + t->period;
166  }
167  else
168  next = EXPIRE_NEVER;
170  }
171  else
172  t = NULL;
173  }
175 
176  if (t)
177  {
178  if (t->flags & WT_EXECUTEINTIMERTHREAD)
180  else
181  {
182  ULONG flags
183  = (t->flags
187  if (status != STATUS_SUCCESS)
189  }
190  }
191 }
192 
194 {
195  struct queue_timer *t;
197 
199  if (list_head(&q->timers))
200  {
201  t = LIST_ENTRY(list_head(&q->timers), struct queue_timer, entry);
202  assert(!t->destroy || t->expire == EXPIRE_NEVER);
203 
204  if (t->expire != EXPIRE_NEVER)
205  {
207  timeout = t->expire < time ? 0 : (ULONG)(t->expire - time);
208  }
209  }
211 
212  return timeout;
213 }
214 
216 {
217  struct timer_queue *q = p;
218  ULONG timeout_ms;
219 
220  timeout_ms = INFINITE;
221  for (;;)
222  {
225  BOOL done = FALSE;
226 
228  q->event, FALSE, get_nt_timeout(&timeout, timeout_ms));
229 
230  if (status == STATUS_WAIT_0)
231  {
232  /* There are two possible ways to trigger the event. Either
233  we are quitting and the last timer got removed, or a new
234  timer got put at the head of the list so we need to adjust
235  our timeout. */
237  if (q->quit && list_empty(&q->timers))
238  done = TRUE;
240  }
241  else if (status == STATUS_TIMEOUT)
243 
244  if (done)
245  break;
246 
247  timeout_ms = queue_get_timeout(q);
248  }
249 
250  NtClose(q->event);
252  q->magic = 0;
253  RtlFreeHeap(RtlGetProcessHeap(), 0, q);
255  return 0;
256 }
257 
258 static void queue_destroy_timer(struct queue_timer *t)
259 {
260  /* We MUST hold the queue cs while calling this function. */
261  t->destroy = TRUE;
262  if (t->runcount == 0)
263  /* Ensure a timer is promptly removed. If callbacks are pending,
264  it will be removed after the last one finishes by the callback
265  cleanup wrapper. */
267  else
268  /* Make sure no destroyed timer masks an active timer at the head
269  of the sorted list. */
271 }
272 
273 /***********************************************************************
274  * RtlCreateTimerQueue (NTDLL.@)
275  *
276  * Creates a timer queue object and returns a handle to it.
277  *
278  * PARAMS
279  * NewTimerQueue [O] The newly created queue.
280  *
281  * RETURNS
282  * Success: STATUS_SUCCESS.
283  * Failure: Any NTSTATUS code.
284  */
286 {
288  struct timer_queue *q = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof *q);
289  if (!q)
290  return STATUS_NO_MEMORY;
291 
293  list_init(&q->timers);
294  q->quit = FALSE;
295  q->magic = TIMER_QUEUE_MAGIC;
297  if (status != STATUS_SUCCESS)
298  {
299  RtlFreeHeap(RtlGetProcessHeap(), 0, q);
300  return status;
301  }
303  if (status != STATUS_SUCCESS)
304  {
305  NtClose(q->event);
306  RtlFreeHeap(RtlGetProcessHeap(), 0, q);
307  return status;
308  }
309 
310  NtResumeThread(q->thread, NULL);
311  *NewTimerQueue = q;
312  return STATUS_SUCCESS;
313 }
314 
315 /***********************************************************************
316  * RtlDeleteTimerQueueEx (NTDLL.@)
317  *
318  * Deletes a timer queue object.
319  *
320  * PARAMS
321  * TimerQueue [I] The timer queue to destroy.
322  * CompletionEvent [I] If NULL, return immediately. If INVALID_HANDLE_VALUE,
323  * wait until all timers are finished firing before
324  * returning. Otherwise, return immediately and set the
325  * event when all timers are done.
326  *
327  * RETURNS
328  * Success: STATUS_SUCCESS if synchronous, STATUS_PENDING if not.
329  * Failure: Any NTSTATUS code.
330  */
331 NTSTATUS WINAPI RtlDeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
332 {
333  struct timer_queue *q = TimerQueue;
334  struct queue_timer *t, *temp;
335  HANDLE thread;
337 
338  if (!q || q->magic != TIMER_QUEUE_MAGIC)
339  return STATUS_INVALID_HANDLE;
340 
341  thread = q->thread;
342 
344  q->quit = TRUE;
345  if (list_head(&q->timers))
346  /* When the last timer is removed, it will signal the timer thread to
347  exit... */
348  LIST_FOR_EACH_ENTRY_SAFE(t, temp, &q->timers, struct queue_timer, entry)
350  else
351  /* However if we have none, we must do it ourselves. */
352  NtSetEvent(q->event, NULL);
354 
355  if (CompletionEvent == INVALID_HANDLE_VALUE)
356  {
359  }
360  else
361  {
362  if (CompletionEvent)
363  {
364  DPRINT1("asynchronous return on completion event unimplemented\n");
366  NtSetEvent(CompletionEvent, NULL);
367  }
369  }
370 
371  NtClose(thread);
372  return status;
373 }
374 
375 static struct timer_queue *get_timer_queue(HANDLE TimerQueue)
376 {
377  static struct timer_queue *default_timer_queue;
378 
379  if (TimerQueue)
380  return TimerQueue;
381  else
382  {
383  if (!default_timer_queue)
384  {
385  HANDLE q;
387  if (status == STATUS_SUCCESS)
388  {
390  (void **) &default_timer_queue, q, NULL);
391  if (p)
392  /* Got beat to the punch. */
394  }
395  }
396  return default_timer_queue;
397  }
398 }
399 
400 /***********************************************************************
401  * RtlCreateTimer (NTDLL.@)
402  *
403  * Creates a new timer associated with the given queue.
404  *
405  * PARAMS
406  * NewTimer [O] The newly created timer.
407  * TimerQueue [I] The queue to hold the timer.
408  * Callback [I] The callback to fire.
409  * Parameter [I] The argument for the callback.
410  * DueTime [I] The delay, in milliseconds, before first firing the
411  * timer.
412  * Period [I] The period, in milliseconds, at which to fire the timer
413  * after the first callback. If zero, the timer will only
414  * fire once. It still needs to be deleted with
415  * RtlDeleteTimer.
416  * Flags [I] Flags controlling the execution of the callback. In
417  * addition to the WT_* thread pool flags (see
418  * RtlQueueWorkItem), WT_EXECUTEINTIMERTHREAD and
419  * WT_EXECUTEONLYONCE are supported.
420  *
421  * RETURNS
422  * Success: STATUS_SUCCESS.
423  * Failure: Any NTSTATUS code.
424  */
428  ULONG Flags)
429 {
431  struct queue_timer *t;
432  struct timer_queue *q = get_timer_queue(TimerQueue);
433 
434  if (!q) return STATUS_NO_MEMORY;
435  if (q->magic != TIMER_QUEUE_MAGIC) return STATUS_INVALID_HANDLE;
436 
437  t = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof *t);
438  if (!t)
439  return STATUS_NO_MEMORY;
440 
441  t->q = q;
442  t->runcount = 0;
443  t->callback = Callback;
444  t->param = Parameter;
445  t->period = Period;
446  t->flags = Flags;
447  t->destroy = FALSE;
448  t->event = NULL;
449 
452  if (q->quit)
454  else
457 
458  if (status == STATUS_SUCCESS)
459  *NewTimer = t;
460  else
461  RtlFreeHeap(RtlGetProcessHeap(), 0, t);
462 
463  return status;
464 }
465 
466 /***********************************************************************
467  * RtlUpdateTimer (NTDLL.@)
468  *
469  * Changes the time at which a timer expires.
470  *
471  * PARAMS
472  * TimerQueue [I] The queue that holds the timer.
473  * Timer [I] The timer to update.
474  * DueTime [I] The delay, in milliseconds, before next firing the timer.
475  * Period [I] The period, in milliseconds, at which to fire the timer
476  * after the first callback. If zero, the timer will not
477  * refire once. It still needs to be deleted with
478  * RtlDeleteTimer.
479  *
480  * RETURNS
481  * Success: STATUS_SUCCESS.
482  * Failure: Any NTSTATUS code.
483  */
486 {
487  struct queue_timer *t = Timer;
488  struct timer_queue *q = t->q;
489 
491  /* Can't change a timer if it was once-only or destroyed. */
492  if (t->expire != EXPIRE_NEVER)
493  {
494  t->period = Period;
496  }
498 
499  return STATUS_SUCCESS;
500 }
501 
502 /***********************************************************************
503  * RtlDeleteTimer (NTDLL.@)
504  *
505  * Cancels a timer-queue timer.
506  *
507  * PARAMS
508  * TimerQueue [I] The queue that holds the timer.
509  * Timer [I] The timer to update.
510  * CompletionEvent [I] If NULL, return immediately. If INVALID_HANDLE_VALUE,
511  * wait until the timer is finished firing all pending
512  * callbacks before returning. Otherwise, return
513  * immediately and set the timer is done.
514  *
515  * RETURNS
516  * Success: STATUS_SUCCESS if the timer is done, STATUS_PENDING if not,
517  or if the completion event is NULL.
518  * Failure: Any NTSTATUS code.
519  */
521  HANDLE CompletionEvent)
522 {
523  struct queue_timer *t = Timer;
524  struct timer_queue *q;
526  HANDLE event = NULL;
527 
528  if (!Timer)
530  q = t->q;
531  if (CompletionEvent == INVALID_HANDLE_VALUE)
532  {
534  if (status == STATUS_SUCCESS)
536  }
537  else if (CompletionEvent)
538  event = CompletionEvent;
539 
541  t->event = event;
542  if (t->runcount == 0 && event)
546 
547  if (CompletionEvent == INVALID_HANDLE_VALUE && event)
548  {
549  if (status == STATUS_PENDING)
550  {
553  }
554  NtClose(event);
555  }
556 
557  return status;
558 }
559 
560 /*
561  * @implemented
562  */
563 NTSTATUS
564 NTAPI
566 {
567  return RtlDeleteTimerQueueEx(TimerQueue, INVALID_HANDLE_VALUE);
568 }
569 
570 /* EOF */
#define TRUE
Definition: types.h:120
static void queue_move_timer(struct queue_timer *t, ULONGLONG time, BOOL set_event)
Definition: timerqueue.c:140
PRTL_START_POOL_THREAD RtlpStartThreadFunc
Definition: workitem.c:45
#define STATUS_NOT_IMPLEMENTED
Definition: ntstatus.h:225
NTSTATUS WINAPI RtlDeleteTimer(HANDLE TimerQueue, HANDLE Timer, HANDLE CompletionEvent)
Definition: timerqueue.c:520
HANDLE thread
Definition: timerqueue.c:61
#define EXPIRE_NEVER
Definition: timerqueue.c:64
_In_ LARGE_INTEGER DueTime
Definition: kefuncs.h:524
PRTL_EXIT_POOL_THREAD RtlpExitThreadFunc
Definition: workitem.c:46
LONG NTSTATUS
Definition: precomp.h:26
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:606
static VOID WINAPI timer_callback_wrapper(LPVOID p)
Definition: timerqueue.c:100
NTSTATUS NTAPI RtlDeleteTimerQueue(HANDLE TimerQueue)
Definition: timerqueue.c:565
NTSYSAPI NTSTATUS NTAPI RtlQueueWorkItem(_In_ WORKERCALLBACKFUNC Function, _In_opt_ PVOID Context, _In_ ULONG Flags)
#define WT_EXECUTEINIOTHREAD
Definition: winnt_old.h:1072
ULONG runcount
Definition: timerqueue.c:44
NTSTATUS NTAPI NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter, OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)
Definition: profile.c:278
NTSTATUS NTAPI NtCreateEvent(OUT PHANDLE EventHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN EVENT_TYPE EventType, IN BOOLEAN InitialState)
Definition: event.c:100
GLdouble GLdouble t
Definition: gl.h:2047
NTSYSAPI NTSTATUS NTAPI RtlEnterCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
#define INVALID_HANDLE_VALUE
Definition: compat.h:399
_In_ LARGE_INTEGER _In_ ULONG Period
Definition: kefuncs.h:1268
#define assert(x)
Definition: debug.h:53
static ULONG queue_get_timeout(struct timer_queue *q)
Definition: timerqueue.c:193
VOID(NTAPI * WAITORTIMERCALLBACKFUNC)(PVOID pvContext, BOOLEAN fTimerOrWaitFired)
Definition: rtltypes.h:492
Definition: dhcpd.h:245
RTL_CRITICAL_SECTION cs
Definition: timerqueue.c:57
static PLARGE_INTEGER get_nt_timeout(PLARGE_INTEGER pTime, ULONG timeout)
Definition: timerqueue.c:32
#define WT_TRANSFER_IMPERSONATION
Definition: winnt_old.h:1080
__u16 time
Definition: mkdosfs.c:366
_In_ PVOID Parameter
Definition: ldrtypes.h:241
NTSTATUS WINAPI RtlDeleteTimerQueueEx(HANDLE TimerQueue, HANDLE CompletionEvent)
Definition: timerqueue.c:331
NTSTATUS WINAPI RtlCreateTimerQueue(PHANDLE NewTimerQueue)
Definition: timerqueue.c:285
static void queue_remove_timer(struct queue_timer *t)
Definition: timerqueue.c:67
GLbitfield GLuint64 timeout
Definition: glext.h:7164
#define STATUS_INVALID_HANDLE
Definition: ntstatus.h:231
#define WT_EXECUTEINPERSISTENTTHREAD
Definition: winnt_old.h:1079
__WINE_SERVER_LIST_INLINE struct list * list_head(const struct list *list)
Definition: list.h:131
static void timer_cleanup_callback(struct queue_timer *t)
Definition: timerqueue.c:86
Definition: list.h:15
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define STATUS_WAIT_0
Definition: ntstatus.h:223
static void queue_add_timer(struct queue_timer *t, ULONGLONG time, BOOL set_event)
Definition: timerqueue.c:114
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
NTSTATUS WINAPI RtlCreateTimer(HANDLE TimerQueue, PHANDLE NewTimer, WAITORTIMERCALLBACKFUNC Callback, PVOID Parameter, DWORD DueTime, DWORD Period, ULONG Flags)
Definition: timerqueue.c:425
struct list timers
Definition: timerqueue.c:58
unsigned int BOOL
Definition: ntddk_ex.h:94
NTSYSAPI NTSTATUS NTAPI RtlLeaveCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
#define EVENT_ALL_ACCESS
Definition: isotest.c:82
time_t now
Definition: finger.c:65
static struct timer_queue * get_timer_queue(HANDLE TimerQueue)
Definition: timerqueue.c:375
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
static PVOID ptr
Definition: dispmode.c:27
static void queue_destroy_timer(struct queue_timer *t)
Definition: timerqueue.c:258
DWORD magic
Definition: timerqueue.c:56
_In_ PCCERT_CONTEXT _In_opt_ LPFILETIME pTime
Definition: wincrypt.h:4840
struct timer_queue * q
Definition: timerqueue.c:42
#define LIST_FOR_EACH(cursor, list)
Definition: list.h:188
smooth NULL
Definition: ftsmooth.c:416
DWORD period
Definition: timerqueue.c:47
ULONGLONG expire
Definition: timerqueue.c:49
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:588
struct list entry
Definition: timerqueue.c:43
__WINE_SERVER_LIST_INLINE void list_remove(struct list *elem)
Definition: list.h:108
#define WT_EXECUTELONGFUNCTION
Definition: winnt_old.h:1076
NTSTATUS NTAPI NtResumeThread(IN HANDLE ThreadHandle, OUT PULONG SuspendCount OPTIONAL)
Definition: state.c:290
NTSTATUS RtlpInitializeTimerThread(VOID)
Definition: timerqueue.c:27
NTSTATUS NTAPI NtSetEvent(IN HANDLE EventHandle, OUT PLONG PreviousState OPTIONAL)
Definition: event.c:458
NTSYSAPI NTSTATUS NTAPI RtlInitializeCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
#define STATUS_PENDING
Definition: ntstatus.h:82
uint64_t ULONGLONG
Definition: typedefs.h:65
BOOL destroy
Definition: timerqueue.c:50
HANDLE event
Definition: timerqueue.c:51
#define WINAPI
Definition: msvc.h:6
unsigned long DWORD
Definition: ntddk_ex.h:95
#define TIMER_QUEUE_MAGIC
Definition: timerqueue.c:65
GLdouble GLdouble GLdouble GLdouble q
Definition: gl.h:2063
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
GLbitfield flags
Definition: glext.h:7161
static HANDLE thread
Definition: service.c:33
#define WT_EXECUTEINTIMERTHREAD
Definition: winnt_old.h:1077
static ULONGLONG queue_current_time(void)
Definition: timerqueue.c:107
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:414
#define STATUS_INVALID_PARAMETER_1
Definition: ntstatus.h:461
uint32_t entry
Definition: isohybrid.c:63
Definition: _list.h:228
static DWORD WINAPI timer_queue_thread_proc(LPVOID p)
Definition: timerqueue.c:215
struct _cl_event * event
Definition: glext.h:7739
__WINE_SERVER_LIST_INLINE int list_empty(const struct list *list)
Definition: list.h:143
static void queue_timer_expire(struct timer_queue *q)
Definition: timerqueue.c:148
UINT Timer
Definition: capclock.c:11
static unsigned __int64 next
Definition: rand_nt.c:6
PVOID param
Definition: timerqueue.c:46
#define LIST_FOR_EACH_ENTRY_SAFE(cursor, cursor2, list, type, field)
Definition: list.h:204
static calc_node_t temp
Definition: rpn_ieee.c:38
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
__WINE_SERVER_LIST_INLINE void list_add_before(struct list *elem, struct list *to_add)
Definition: list.h:87
#define DPRINT1
Definition: precomp.h:8
HANDLE TimerThreadHandle
Definition: timerqueue.c:24
HANDLE event
Definition: timerqueue.c:60
__WINE_SERVER_LIST_INLINE void list_init(struct list *list)
Definition: list.h:149
WAITORTIMERCALLBACKFUNC callback
Definition: timerqueue.c:45
unsigned int ULONG
Definition: retypes.h:1
GLfloat GLfloat p
Definition: glext.h:8902
ULONG flags
Definition: timerqueue.c:48
#define LIST_ENTRY(type)
Definition: queue.h:175
NTSYSAPI NTSTATUS NTAPI RtlDeleteCriticalSection(_In_ PRTL_CRITICAL_SECTION CriticalSection)
#define INFINITE
Definition: serial.h:102
return STATUS_SUCCESS
Definition: btrfs.c:2938
LPFNPSPCALLBACK Callback
Definition: desk.c:111
static SERVICE_STATUS status
Definition: service.c:31
NTSTATUS WINAPI RtlUpdateTimer(HANDLE TimerQueue, HANDLE Timer, DWORD DueTime, DWORD Period)
Definition: timerqueue.c:484
NTSTATUS(NTAPI * PRTL_EXIT_POOL_THREAD)(_In_ NTSTATUS ExitStatus)
Definition: rtltypes.h:583
LONGLONG QuadPart
Definition: typedefs.h:112
NTSTATUS(NTAPI * PRTL_START_POOL_THREAD)(_In_ PTHREAD_START_ROUTINE Function, _In_ PVOID Parameter, _Out_ PHANDLE ThreadHandle)
Definition: rtltypes.h:576
Definition: ps.c:97
NTSYSAPI NTSTATUS NTAPI NtWaitForSingleObject(IN HANDLE hObject, IN BOOLEAN bAlertable, IN PLARGE_INTEGER Timeout)