ReactOS 0.4.15-dev-7934-g1dc8d80
fxtimer.cpp
Go to the documentation of this file.
1/*++
2
3Copyright (c) Microsoft Corporation
4
5Module Name:
6
7 FxTimer.hpp
8
9Abstract:
10
11 This module implements a frameworks managed TIMER that
12 can synchrononize with driver frameworks object locks.
13
14Author:
15
16
17
18Environment:
19
20 Both kernel and user mode
21
22Revision History:
23
24
25--*/
26
27#include "coreprivshared.hpp"
28
29#include "fxtimer.hpp"
30
31// Tracing support
32extern "C" {
33// #include "FxTimer.tmh"
34}
35
36//
37// Public constructors
38//
39
41 __in PFX_DRIVER_GLOBALS FxDriverGlobals
42 ) :
44{
45 m_Object = NULL;
46 m_Period = 0;
57
58 //
59 // Mark the object has having passive level dispose so that KeFlushQueuedDpcs
60 // can be called in Dispose().
61 //
63
65}
66
68{
69 //
70 // If this hits, its because someone destroyed the TIMER by
71 // removing too many references by mistake without calling WdfObjectDelete
72 //
73 if (m_Object != NULL) {
76 "WDFTIMER %p destroyed without calling WdfObjectDelete, "
77 "or by Framework processing DeviceRemove. Possible reference count "
78 "problem?", GetObjectHandleUnchecked());
80 }
81
83}
84
88 __in PFX_DRIVER_GLOBALS FxDriverGlobals,
91 __in FxObject* ParentObject,
92 __out WDFTIMER* Timer
93 )
94{
97
98 pFxTimer = new(FxDriverGlobals, Attributes) FxTimer(FxDriverGlobals);
99
100 if (pFxTimer == NULL) {
102 }
103
106 Config,
107 ParentObject,
108 Timer
109 );
110
111 if (!NT_SUCCESS(status)) {
113 }
114
115 return status;
116}
117
123 __in FxObject* ParentObject,
124 __out WDFTIMER* Timer
125 )
126{
128 IFxHasCallbacks* pCallbacks;
130 BOOLEAN isPassiveTimer;
131
133 pCallbacks = NULL;
134 isPassiveTimer = FALSE;
135
136 m_Period = Config->Period;
137
138 // Set tolerable delay.
139 if (Config->Size > sizeof(WDF_TIMER_CONFIG_V1_7)) {
140 m_TolerableDelay = Config->TolerableDelay;
141 }
142
143 if (Config->Size > sizeof(WDF_TIMER_CONFIG_V1_11)) {
144 m_UseHighResolutionTimer = Config->UseHighResolutionTimer;
145 }
146
147 // Set users callback function
148 m_Callback = Config->EvtTimerFunc;
149
150 //
151 // Decide whether to use the legacy KTimer or the new Ktimer2/ExTimer
152 // and call the appropriate initialization routine.
153 // The new ExTimers expose two kind of timers:no wake timers and the
154 // high resolution timers. For kernel mode, these timers are only exposed
155 // to new clients.
156 // For user mode,the underlying Threadpool APIs internally were upgraded
157 // to using the no wake timers and we don't expose the High
158 // resolution timers. Therefore the user mode code does not need to use
159 // the ex initialization.
160 //
161
162#if (FX_CORE_MODE == FX_CORE_KERNEL_MODE)
163 // __REACTOS__ Ex timers are not supported
164 // if (pFxDriverGlobals->IsVersionGreaterThanOrEqualTo(1,13)) {
165 // status = m_Timer.InitializeEx(this, FxTimer::_FxTimerExtCallbackThunk, m_Period,
166 // m_TolerableDelay, m_UseHighResolutionTimer);
167 // } else
168 {
170 }
171#else
173#endif
174
175 if (!NT_SUCCESS(status)) {
178 "Failed to initialize timer %!STATUS!", status);
179 return status;
180 }
181
182 //
183 // As long as we are associated, the parent object holds a reference
184 // count on the TIMER.
185 //
186 // We keep an extra reference count since on Dispose, we wait until
187 // all outstanding DPCs complete before allowing finalization.
188 //
189 // This reference must be taken early before we return any failure,
190 // since Dispose() expects this extra reference, and Dispose() will
191 // be called even if we return a failure status right now.
192 //
193 ADDREF(this);
194
195 m_DeviceBase = FxDeviceBase::_SearchForDevice(ParentObject, &pCallbacks);
196 if (m_DeviceBase == NULL) {
198 }
199
200 if (Attributes->ExecutionLevel == WdfExecutionLevelPassive) {
201 isPassiveTimer = TRUE;
202 }
203
204 //
205 // Configure Serialization for the callbacks on the supplied object.
206 //
208 ParentObject,
209 pCallbacks,
210 Config->AutomaticSerialization,
211 isPassiveTimer,
214 );
215
216 if (!NT_SUCCESS(status)) {
218
219
220
221
222
223
226 "ParentObject %p cannot automatically synchronize callbacks "
227 "with a Timer since it is configured for passive level callback "
228 "constraints. Set AutomaticSerialization to FALSE. %!STATUS!",
229 Attributes->ParentObject, status);
230 }
231
232 return status;
233 }
234
235 //
236 // If the caller wants passive callback then create a workitem.
237 //
238 if (isPassiveTimer) {
242 );
243 if (!NT_SUCCESS(status)) {
245 "Could not allocate workitem: %!STATUS!", status);
246 return status;
247 }
248 }
249
250 //
251 // We automatically synchronize with and reference count
252 // the lifetime of the framework object to prevent any TIMER races
253 // that can access the object while it is going away.
254 //
255
256 //
257 // The caller supplied object is the object the caller wants the
258 // TIMER to be associated with, and the framework must ensure this
259 // object remains live until the TIMER object is destroyed. Otherwise,
260 // it could access either object context memory, or an object API
261 // on a freed object.
262 //
263 // Due to the locking model of the framework, the lock may actually
264 // be owned by a higher level object as well. This is the lockObject
265 // returned. As long was we are a child of this object, the lockObject
266 // does not need to be dereferenced since it will notify us of Cleanup
267 // before it goes away.
268 //
269
270 //
271 // Associate the FxTimer with the object. When this object Cleans up, it
272 // will notify our Dispose function as well.
273 //
274
275 //
276 // Add a reference to the parent object we are associated with.
277 // We will be notified of Cleanup to release this reference.
278 //
279 ParentObject->ADDREF(this);
280
281 //
282 // Save the ptr to the object the TIMER is associated with
283 //
284 m_Object = ParentObject;
285
286 //
287 // Attributes->ParentObject is the same as ParentObject. Since we already
288 // converted it to an object, use that.
289 //
290 status = Commit(Attributes, (WDFOBJECT*)Timer, ParentObject);
291
292 if (!NT_SUCCESS(status)) {
293 return status;
294 }
295
296 return status;
297}
298
299VOID
301 VOID
302 )
303{
305
306 if (m_Callback != NULL) {
307
308 //
309 // Save the current thread object pointer. We will use this avoid
310 // deadlock if the driver tries to delete or stop the timer from within
311 // the callback.
312 //
314
315 if (m_CallbackLock != NULL) {
316 KIRQL irql = 0;
317
321 }
322 else {
324 }
325
327 }
328}
329
330VOID
332 __in PKDPC TimerDpc,
336 )
337/*++
338
339Routine Description:
340
341 This is the C routine called by the kernel's TIMER DPC handler
342
343Arguments:
344
345 TimerDpc - our DPC object associated with our Timer
346 DeferredContext - Context for the TIMER that we setup in DriverEntry
347 SystemArgument1 -
348 SystemArgument2 -
349
350Return Value:
351
352 Nothing.
353
354--*/
355
356{
357 FxTimer* pTimer = (FxTimer*)DeferredContext;
358
359 UNREFERENCED_PARAMETER(TimerDpc);
362
363 if (pTimer->m_SystemWorkItem == NULL) {
364
365#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
366 FxPerfTraceDpc(&pTimer->m_Callback);
367#endif
368
369 //
370 // Dispatch-level timer callback
371 //
372 pTimer->TimerHandler();
373 }
374 else {
375 //
376 // Passive timer callback.Queue only if the previous one is completed.
377 //
379 }
380
381 return;
382}
383
384VOID
388 )
389/*++
390
391Routine Description:
392
393 This is the C routine called by the kernel's ex timer
394
395Arguments:
396
397 Timer - Ex timer
398 Context - Context for the TIMER that we passed while creating it
399
400Return Value:
401
402 Nothing.
403
404--*/
405
406{
407 FxTimer* pTimer = (FxTimer*)Context;
408
410
411 if (pTimer->m_SystemWorkItem == NULL) {
412
413#if (FX_CORE_MODE==FX_CORE_KERNEL_MODE)
414 FxPerfTraceDpc(&pTimer->m_Callback);
415#endif
416
417 //
418 // Dispatch-level timer callback
419 //
420 pTimer->TimerHandler();
421 }
422 else {
423 //
424 // Passive timer callback.Queue only if the previous one is completed.
425 //
427 }
428
429 return;
430}
431
432VOID
435 )
436/*++
437
438Routine Description:
439 Thunk used when callback must be made at passive-level
440
441--*/
442{
443 FxTimer* pTimer = (FxTimer*)Parameter;
444
445 pTimer->TimerHandler();
446
447 return;
448}
449
450//
451// Called when DeleteObject is called, or when the parent
452// is being deleted or Disposed.
453//
454// Also invoked directly by the cleanup list at our request after
455// a Dispose occurs and must be deferred if not at passive level.
456//
459{
460 KIRQL irql;
461
462 // MarkPassiveDispose() in Initialize ensures this
464
465 //
466 // Signal that we are running down.
467 //
468 Lock(&irql);
470 Unlock(irql);
471
472 //
473 // Cancel the timer, wait for its callback, then cleanup.
474 //
476
477 return TRUE;
478}
479
480VOID
482 VOID
483 )
484/*++
485
486Routine Description:
487 Called by the system work item to finish the rundown.
488
489Arguments:
490 None
491
492Return Value:
493 None
494
495 --*/
496{
498
501 "Deleting WDFTIMER %p from with in the callback will "
502 "lead to deadlock, PRKTHREAD %p",
505 }
506
507 //
508 // Cancel the timer, wait for its callback.
509 //
510 Stop(TRUE);
511
512 //
513 // Delete will also wait for the workitem to exit.
514 //
515 if (m_SystemWorkItem != NULL) {
518 }
519
520 //
521 // Release our reference count to the associated parent object if present
522 //
523 if (m_Object != NULL) {
525 m_Object = NULL;
526
527 pObject->RELEASE(this);
528 }
529
530 //
531 // Perform our final release to ourselves, destroying the FxTimer
532 //
533 RELEASE(this);
534}
535
539 )
540
541/*++
542
543Routine Description:
544
545 Start or restart the timer
546
547Arguments:
548
549 DueTime - Time when the timer will be scheduled
550
551Returns:
552
553 TRUE if a previous timer was reset to the new duetime.
554 FALSE otherwise.
555
556--*/
557
558{
559 KIRQL irql;
562
563 Lock(&irql);
564
565 //
566 // Basic check to make sure timer object is not deleted. Note that this
567 // logic is not foolproof b/c someone may dispose the timer just after this
568 // validation and before the start routine queues the timer; but at least it
569 // is better than nothing.
570 //
571 if (m_RunningDown) {
573 "Calling WdfTimerStart when the timer object %p is"
574 " running down will lead to a crash",
575 GetHandle());
577 }
578 else if (m_StopThread != NULL) {
581 "WDFTIMER 0x%p is been stopped by PRKTHREAD 0x%p. "
582 "Ignoring the request to start timer",
584
585 //
586 // Let the stop thread know that we aborted this start operation.
587 //
589 }
590 else {
591 //
592 // Yes, the timer can be started.
593 //
595 }
596
597 Unlock(irql);
598
599 if (startTimer) {
600 //
601 // It may be possible for the timer to fire before the call from
602 // KeSetTimerEx completes. If this happens and if the timer callback
603 // disposes the timer object, a dispose work-item is queued.
604 // This work-item in turn may also run before KeSetTimerEx completes,
605 // making the object invalid by the time we try to take its Lock()
606 // below. This ADDREF() prevents the object from going away and it is
607 // matched by a RELEASE() when we are done.
608 //
609 ADDREF(this);
610
611 //
612 // Call the tolerable timer API only if OS supports it and driver
613 // requested it.
614 //
616
617 Lock(&irql);
618 if (m_StopThread != NULL) {
620 }
621 Unlock(irql);
622
623 //
624 // See ADDREF() comment above.
625 //
626 RELEASE(this);
627 }
628
629 return result;
630}
631
635 )
636{
637 KIRQL irql;
639#ifdef DBG
640 ULONG retryCount = 0;
641#endif
642
643 if (Wait) {
644 //
645 // If the caller specified wait, we will flush the queued DPC's
646 // to ensure any outstanding timer DPC has finished executing.
647 //
648 // The return value of timers is ambiguous in the case of periodic
649 // timers, so we flush whenever the caller desires to ensure all
650 // callbacks are complete.
651 //
652
653 //
654 // Make sure the stop is not called from within the callback
655 // because it's semantically incorrect and can lead to deadlock
656 // if the wait parameter is set.
657 //
661 "Calling WdfTimerStop from within the WDFTIMER "
662 "%p callback will lead to deadlock, PRKTHREAD %p",
665 return FALSE;
666 }
667
668 if (GetDriverGlobals()->FxVerifierOn) {
672 "WdfTimerStop(Wait==TRUE) called at IRQL > PASSIVE_LEVEL, "
673 "current IRQL = 0x%x", Mx::MxGetCurrentIrql());
675 return FALSE;
676 }
677 }
678
679 //
680 // Prevent the callback from restarting the timer.
681 //
682 Lock(&irql);
683
684 //
685 // Driver issue.
686 //
687 if (GetDriverGlobals()->IsVerificationEnabled(1, 9, OkForDownLevel) &&
688 m_StopThread != NULL) {
691 "Detected multiple calls to WdfTimerStop for "
692 "WDFTIMER 0x%p, stop in progress on PRKTHREAD 0x%p, "
693 "current PRKTHREAD 0x%p",
696 }
697
698 //
699 // Reset the flag to find out if the timer's start logic aborts
700 // b/c of this stop operation.
701 //
703
704 //
705 // This field is used for the following purposes:
706 // (a) Let the start thread know not to restart the timer while stop
707 // is running.
708 // (b) Detect concurrent calls to stop the timer.
709 // (c) To remember the thread id of the stopping thread.
710 //
712
713 do {
714#ifdef DBG
715 retryCount++;
716#endif
717 //
718 // Reset flag to catch when timer callback is restarting the
719 // timer.
720 //
722 Unlock(irql);
723
724 //
725 // Cancel the timer
726 //
727 result = m_Timer.Stop();
728
729 //
730 // Wait for the timer's DPC.
731 //
733
734 //
735 // Wait for the timer's passive work item.
736 //
737 if (m_SystemWorkItem != NULL) {
739 }
740
741 Lock(&irql);
742#ifdef DBG
743 //
744 // This loop is run for a max of 2 times.
745 //
746 ASSERT(retryCount < 3);
747#endif
748 //
749 // Re-stop timer if timer was not in queue and
750 // it got restarted in callback.
751 //
752 }while (result == FALSE && m_StopAgain);
753
754 //
755 // Stop completed.
756 //
759
760 //
761 // Return TRUE (i.e., timer in queue) if
762 // (a) stop logic successfully cancelled the timer or
763 // (b) the start logic aborted b/c of this stop.
764 //
765 if (m_StartAborted) {
766 result = TRUE;
768 }
769
770 Unlock(irql);
771 }
772 else {
773 //
774 // Caller doesn't want any synchronization.
775 // Cancel the timer.
776 //
777 result = m_Timer.Stop();
778 }
779
780 return result;
781}
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
virtual void Lock(__out PKIRQL PreviousIrql)=0
virtual void Unlock(__in KIRQL PreviousIrql)=0
static FxDeviceBase * _SearchForDevice(__in FxObject *Object, __out_opt IFxHasCallbacks **Callbacks)
MdDeviceObject __inline GetDeviceObject(VOID)
Definition: fxdevice.hpp:174
VOID MarkPassiveDispose(__in FxObjectLockState State=ObjectLock)
Definition: fxobject.hpp:944
virtual VOID DeleteObject(VOID)
PVOID __inline GetObjectHandleUnchecked(VOID)
Definition: fxobject.hpp:446
__inline PFX_DRIVER_GLOBALS GetDriverGlobals(VOID)
Definition: fxobject.hpp:734
CfxDevice * m_Device
Definition: fxobject.hpp:329
static _Must_inspect_result_ NTSTATUS _GetEffectiveLock(__in FxObject *Object, __in_opt IFxHasCallbacks *Callbacks, __in BOOLEAN AutomaticLocking, __in BOOLEAN PassiveCallbacks, __out FxCallbackLock **CallbackLock, __out_opt FxObject **CallbackLockObject)
Definition: fxobject.cpp:1044
CfxDeviceBase * m_DeviceBase
Definition: fxobject.hpp:328
__drv_restoresIRQL KIRQL __in BOOLEAN Unlock
Definition: fxobject.hpp:1474
VOID DeleteFromFailedCreate(VOID)
Definition: fxobject.cpp:391
VOID MarkDisposeOverride(__in FxObjectLockState State=ObjectLock)
Definition: fxobject.hpp:1101
_Must_inspect_result_ NTSTATUS Commit(__in_opt PWDF_OBJECT_ATTRIBUTES Attributes, __out_opt WDFOBJECT *ObjectHandle, __in_opt FxObject *Parent=NULL, __in BOOLEAN AssignDriverAsDefaultParent=TRUE)
Definition: fxobject.cpp:904
static _Must_inspect_result_ NTSTATUS _Create(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PVOID WdmObject, __out FxSystemWorkItem **pObject)
__inline BOOLEAN TryToEnqueue(__in PFN_WDF_SYSTEMWORKITEM CallbackFunc, __in PVOID Parameter)
FxSystemWorkItem * m_SystemWorkItem
Definition: fxtimer.hpp:94
static MdExtCallbackType _FxTimerExtCallbackThunk
Definition: fxtimer.hpp:217
virtual ~FxTimer(VOID)
Definition: fxtimer.cpp:67
BOOLEAN m_StartAborted
Definition: fxtimer.hpp:117
_Must_inspect_result_ NTSTATUS Initialize(__in PWDF_OBJECT_ATTRIBUTES Attributes, __in PWDF_TIMER_CONFIG Config, __in FxObject *ParentObject, __out WDFTIMER *Timer)
Definition: fxtimer.cpp:120
FxObject * m_CallbackLockObject
Definition: fxtimer.hpp:83
static FN_WDF_SYSTEMWORKITEM _FxTimerWorkItemCallback
Definition: fxtimer.hpp:209
ULONG m_TolerableDelay
Definition: fxtimer.hpp:65
MxTimer m_Timer
Definition: fxtimer.hpp:49
BOOLEAN Stop(__in BOOLEAN Wait)
Definition: fxtimer.cpp:633
MxThread m_StopThread
Definition: fxtimer.hpp:107
virtual BOOLEAN Dispose(VOID)
Definition: fxtimer.cpp:458
static MdDeferredRoutineType _FxTimerDpcThunk
Definition: fxtimer.hpp:213
FxTimer(__in PFX_DRIVER_GLOBALS FxDriverGlobals)
Definition: fxtimer.cpp:40
VOID TimerHandler(VOID)
Definition: fxtimer.cpp:300
FxCallbackLock * m_CallbackLock
Definition: fxtimer.hpp:77
FxObject * m_Object
Definition: fxtimer.hpp:55
static _Must_inspect_result_ NTSTATUS _Create(__in PFX_DRIVER_GLOBALS FxDriverGlobals, __in PWDF_TIMER_CONFIG Config, __in PWDF_OBJECT_ATTRIBUTES Attributes, __in FxObject *ParentObject, __out WDFTIMER *Timer)
Definition: fxtimer.cpp:87
BOOLEAN m_UseHighResolutionTimer
Definition: fxtimer.hpp:71
BOOLEAN m_RunningDown
Definition: fxtimer.hpp:122
BOOLEAN Start(__in LARGE_INTEGER DueTime)
Definition: fxtimer.cpp:537
VOID FlushAndRundown(VOID)
Definition: fxtimer.cpp:481
ULONG m_Period
Definition: fxtimer.hpp:60
volatile POINTER_ALIGNMENT MxThread m_CallbackThread
Definition: fxtimer.hpp:101
PFN_WDF_TIMER m_Callback
Definition: fxtimer.hpp:88
BOOLEAN m_StopAgain
Definition: fxtimer.hpp:112
_Must_inspect_result_ __inline BOOLEAN Stop(VOID)
Definition: mxtimerkm.h:273
__inline VOID FlushQueuedDpcs(VOID)
Definition: mxtimerkm.h:291
CHECK_RETURN_IF_USER_MODE __inline NTSTATUS Initialize(__in_opt PVOID TimerContext, __in MdDeferredRoutine TimerCallback, __in LONG Period)
Definition: mxtimerkm.h:119
__inline BOOLEAN StartWithReturn(__in LARGE_INTEGER DueTime, __in ULONG TolerableDelay=0)
Definition: mxtimerkm.h:209
static __inline MxThread MxGetCurrentThread()
Definition: mxgeneralkm.h:61
static __inline KIRQL MxGetCurrentIrql()
Definition: mxgeneralkm.h:86
#define __in
Definition: dbghelp.h:35
#define __out
Definition: dbghelp.h:62
#define TRACINGDEVICE
Definition: dbgtrace.h:58
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
KIRQL irql
Definition: wave.h:1
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
UCHAR KIRQL
Definition: env_spec_w32.h:591
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, "Enter, WDFDEVICE %p", Device)
PFX_DRIVER_GLOBALS pFxDriverGlobals
FX_TRACK_DRIVER(fxDriverGlobals)
FxVerifierDbgBreakPoint(pFxDriverGlobals)
@ OkForDownLevel
Definition: fxglobals.h:80
@ ObjectDoNotLock
Definition: fxobject.hpp:128
#define ADDREF(_tag)
Definition: fxobject.hpp:49
#define RELEASE(_tag)
Definition: fxobject.hpp:50
FxObject * pObject
FORCEINLINE VOID FxPerfTraceDpc(_In_ PVOID DriverCallback)
FxTimer * pFxTimer
Definition: fxtimerapi.cpp:234
@ FX_TYPE_TIMER
Definition: fxtypes.h:81
GLuint64EXT * result
Definition: glext.h:11304
_In_opt_ PVOID _Out_ BOOLEAN * Stop
Definition: ldrtypes.h:241
#define ASSERT(a)
Definition: mode.c:44
#define _Must_inspect_result_
Definition: ms_sal.h:558
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
Definition: ketypes.h:699
Definition: ps.c:97
#define GetHandle(h)
Definition: treelist.c:116
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_CHILD_LIST_CONFIG Config
Definition: wdfchildlist.h:476
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes
_In_ WDFDPC _In_ BOOLEAN Wait
Definition: wdfdpc.h:170
@ WdfExecutionLevelPassive
Definition: wdfobject.h:54
#define STATUS_WDF_INCOMPATIBLE_EXECUTION_LEVEL
Definition: wdfstatus.h:198
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWAITLOCK * Lock
Definition: wdfsync.h:127
_In_ WDFTIMER _In_ LONGLONG DueTime
Definition: wdftimer.h:190
struct _EX_TIMER * PEX_TIMER
Definition: extypes.h:291
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:688
_In_opt_ PVOID DeferredContext
Definition: ketypes.h:687
_In_opt_ PVOID _In_opt_ PVOID _In_opt_ PVOID SystemArgument2
Definition: ketypes.h:689
_Inout_opt_ PVOID Parameter
Definition: rtltypes.h:323
static void startTimer(void)
Definition: xmllint.c:460