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