1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 ModuleName:
6 
7     MxEventUm.h
8 
9 Abstract:
10 
11     User mode implementation of event
12     class defined in MxEvent.h
13 
14 Author:
15 
16 
17 
18 Revision History:
19 
20 
21 
22 --*/
23 
24 #pragma once
25 
26 typedef struct {
27     HANDLE Event;
28 #if DBG
29     EVENT_TYPE Type; //tracked to allow ReadState only for notification events
30 #endif
31 } MdEvent;
32 
33 #include "DbgMacros.h"
34 #include "MxEvent.h"
35 
36 __inline
MxEvent()37 MxEvent::MxEvent()
38 {
39     CLEAR_DBGFLAG_INITIALIZED;
40 
41     m_Event.Event = NULL;
42 }
43 
44 __inline
~MxEvent()45 MxEvent::~MxEvent()
46 {
47     //
48     // PLEASE NOTE: shared code must not rely of d'tor uninitializing the
49     // event. d'tor may not be invoked if the event is used in a structure
50     // which is allocated/deallocated using MxPoolAllocate/Free instead of
51     // new/delete
52     //
53     Uninitialize();
54 }
55 
56 _Must_inspect_result_
57 __inline
58 NTSTATUS
Initialize(__in EVENT_TYPE Type,__in BOOLEAN InitialState)59 MxEvent::Initialize(
60     __in EVENT_TYPE Type,
61     __in BOOLEAN InitialState
62     )
63 {
64     NTSTATUS status = STATUS_SUCCESS;
65     HANDLE event;
66     BOOL bManualReset;
67 
68     if (NotificationEvent == Type)
69     {
70         bManualReset = TRUE;
71     }
72     else
73     {
74         bManualReset = FALSE;
75     }
76 
77     event = CreateEvent(
78         NULL,
79         bManualReset,
80         InitialState ? TRUE : FALSE,
81         NULL
82         );
83 
84     if (NULL == event) {
85         DWORD err = GetLastError();
86         status = WinErrorToNtStatus(err);
87         goto exit;
88     }
89 
90     m_Event.Event = event;
91 
92 #if DBG
93     m_Event.Type = Type;
94 #endif
95 
96     SET_DBGFLAG_INITIALIZED;
97 
98 exit:
99     return status;
100 }
101 
102 __inline
103 PVOID
GetEvent()104 MxEvent::GetEvent(
105     )
106 {
107     ASSERT_DBGFLAG_INITIALIZED;
108 
109     return m_Event.Event;
110 }
111 
112 __inline
113 VOID
Set()114 MxEvent::Set(
115     )
116 {
117     ASSERT_DBGFLAG_INITIALIZED;
118 
119     SetEvent(m_Event.Event);
120 }
121 
122 __inline
123 VOID
SetWithIncrement(__in KPRIORITY Priority)124 MxEvent::SetWithIncrement(
125     __in KPRIORITY Priority
126     )
127 {
128     UNREFERENCED_PARAMETER(Priority);
129 
130     ASSERT_DBGFLAG_INITIALIZED;
131 
132     Set();
133 }
134 
135 __inline
136 VOID
Clear()137 MxEvent::Clear(
138     )
139 {
140     ASSERT_DBGFLAG_INITIALIZED;
141 
142     ResetEvent(m_Event.Event);
143 }
144 
145 __drv_when(Timeout != NULL, _Must_inspect_result_)
146 __inline
147 NTSTATUS
WaitFor(__in KWAIT_REASON WaitReason,__in KPROCESSOR_MODE WaitMode,__in BOOLEAN Alertable,__in_opt PLARGE_INTEGER Timeout)148 MxEvent::WaitFor(
149     __in     KWAIT_REASON  WaitReason,
150     __in     KPROCESSOR_MODE  WaitMode,
151     __in     BOOLEAN  Alertable,
152     __in_opt PLARGE_INTEGER  Timeout
153     )
154 /*++
155 
156 Routine Description:
157     Waits for the event
158 
159 Arguments:
160     WaitReason  - Unused (only there to match km definition)
161 
162     WaitMode    - Unuses (only there to match km definition)
163 
164     Altertable  - Whether the wait is alertable
165 
166     Timout      - Timeout in 100 ns units, MUST BE NEGATIVE
167                   (negative implies relative timeout)
168 
169 Return Value:
170     Status corresponding to return value of WaitForSingleObjectEx
171 
172   --*/
173 {
174     ASSERT_DBGFLAG_INITIALIZED;
175 
176     DWORD retVal;
177 
178     UNREFERENCED_PARAMETER(WaitReason);
179     UNREFERENCED_PARAMETER(WaitMode);
180 
181     LONGLONG relativeTimeOut = 0;
182     LONGLONG timeoutInMs = 0;
183     DWORD dwTimeout = 0;
184 
185     if (NULL != Timeout)
186     {
187         //
188         // Make sure that timeout is 0 or -ve (which implies relative timeout)
189         //
190         if (Timeout->QuadPart > 0)
191         {
192             Mx::MxAssertMsg(
193                 "Absolute wait not supported in user mode",
194                 FALSE
195                 );
196 
197             return STATUS_INVALID_PARAMETER;
198         }
199 
200         //
201         // Remove the -ve sign
202         //
203         if (Timeout->QuadPart < 0)
204         {
205             relativeTimeOut = -1 * Timeout->QuadPart;
206         }
207 
208         //
209         // Convert from 100ns units to milliseconds
210         //
211         timeoutInMs = (relativeTimeOut / (10 * 1000));
212 
213         if (timeoutInMs > ULONG_MAX)
214         {
215             Mx::MxAssertMsg("Timeout too large", FALSE);
216 
217             return STATUS_INVALID_PARAMETER;
218         }
219         else
220         {
221             dwTimeout = (DWORD) timeoutInMs;
222         }
223     }
224 
225     retVal = WaitForSingleObjectEx(
226                     m_Event.Event,
227                     (NULL == Timeout) ? INFINITE : dwTimeout,
228                     Alertable
229                     );
230 
231     switch(retVal)
232     {
233         case WAIT_ABANDONED:
234             return STATUS_ABANDONED;
235         case WAIT_OBJECT_0:
236             return STATUS_SUCCESS;
237         case WAIT_TIMEOUT:
238             return STATUS_TIMEOUT;
239         case WAIT_FAILED:
240         {
241             DWORD err = GetLastError();
242             return WinErrorToNtStatus(err);
243         }
244         default:
245         {
246             //
247             // We shoudn't get here
248             //
249             Mx::MxAssert(FALSE);
250             return STATUS_UNSUCCESSFUL;
251         }
252     }
253 }
254 
255 LONG
256 __inline
ReadState()257 MxEvent::ReadState(
258     )
259 {
260     ASSERT_DBGFLAG_INITIALIZED;
261 
262 #if DBG
263     Mx::MxAssert(m_Event.Type == NotificationEvent);
264 #endif
265 
266     if (WAIT_OBJECT_0 == WaitForSingleObject(
267                 m_Event.Event,
268                 0
269                 )) {
270         return 1;
271     }
272     else {
273         return 0;
274     }
275 }
276 
277 
278 __inline
279 VOID
Uninitialize()280 MxEvent::Uninitialize(
281     )
282 {
283     if (NULL != m_Event.Event) {
284         CloseHandle(m_Event.Event);
285         m_Event.Event = NULL;
286     }
287 
288     CLEAR_DBGFLAG_INITIALIZED;
289 }
290