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 37 MxEvent::MxEvent() 38 { 39 CLEAR_DBGFLAG_INITIALIZED; 40 41 m_Event.Event = NULL; 42 } 43 44 __inline 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 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 104 MxEvent::GetEvent( 105 ) 106 { 107 ASSERT_DBGFLAG_INITIALIZED; 108 109 return m_Event.Event; 110 } 111 112 __inline 113 VOID 114 MxEvent::Set( 115 ) 116 { 117 ASSERT_DBGFLAG_INITIALIZED; 118 119 SetEvent(m_Event.Event); 120 } 121 122 __inline 123 VOID 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 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 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 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 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