2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ex/keyedevt.c
5 * PURPOSE: Support for keyed events
6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
9 /* INCLUDES *****************************************************************/
15 /* INTERNAL TYPES *************************************************************/
17 #define NUM_KEY_HASH_BUCKETS 23
18 typedef struct _EX_KEYED_EVENT
23 LIST_ENTRY WaitListHead
;
24 LIST_ENTRY ReleaseListHead
;
25 } HashTable
[NUM_KEY_HASH_BUCKETS
];
26 } EX_KEYED_EVENT
, *PEX_KEYED_EVENT
;
30 ExpInitializeKeyedEvent(
31 _Out_ PEX_KEYED_EVENT KeyedEvent
);
33 #define KeGetCurrentProcess() ((PKPROCESS)PsGetCurrentProcess())
35 /* GLOBALS *******************************************************************/
37 PEX_KEYED_EVENT ExpCritSecOutOfMemoryEvent
;
38 POBJECT_TYPE ExKeyedEventObjectType
;
41 GENERIC_MAPPING ExpKeyedEventMapping
=
43 STANDARD_RIGHTS_READ
| EVENT_QUERY_STATE
,
44 STANDARD_RIGHTS_WRITE
| EVENT_MODIFY_STATE
,
45 STANDARD_RIGHTS_EXECUTE
,
50 /* FUNCTIONS *****************************************************************/
54 ExpInitializeKeyedEventImplementation(VOID
)
56 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
= {0};
57 UNICODE_STRING TypeName
= RTL_CONSTANT_STRING(L
"KeyedEvent");
60 /* Set up the object type initializer */
61 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
62 ObjectTypeInitializer
.GenericMapping
= ExpKeyedEventMapping
;
63 ObjectTypeInitializer
.PoolType
= PagedPool
;
64 ObjectTypeInitializer
.ValidAccessMask
= EVENT_ALL_ACCESS
;
65 //ObjectTypeInitializer.DeleteProcedure = ???;
66 //ObjectTypeInitializer.OkayToCloseProcedure = ???;
68 /* Create the keyed event object type */
69 Status
= ObCreateObjectType(&TypeName
,
70 &ObjectTypeInitializer
,
72 &ExKeyedEventObjectType
);
74 /* Check for success */
75 if (!NT_SUCCESS(Status
))
81 /* Create the global keyed event for critical sections on low memory */
82 Status
= ObCreateObject(KernelMode
,
83 ExKeyedEventObjectType
,
87 sizeof(EX_KEYED_EVENT
),
90 (PVOID
*)&ExpCritSecOutOfMemoryEvent
);
92 /* Check for success */
93 if (!NT_SUCCESS(Status
))
99 /* Initalize the keyed event */
100 ExpInitializeKeyedEvent(ExpCritSecOutOfMemoryEvent
);
105 ExpInitializeKeyedEvent(
106 _Out_ PEX_KEYED_EVENT KeyedEvent
)
110 /* Loop all hash buckets */
111 for (i
= 0; i
< NUM_KEY_HASH_BUCKETS
; i
++)
113 /* Initialize the mutex and the wait lists */
114 ExInitializePushLock(&KeyedEvent
->HashTable
[i
].Lock
);
115 InitializeListHead(&KeyedEvent
->HashTable
[i
].WaitListHead
);
116 InitializeListHead(&KeyedEvent
->HashTable
[i
].ReleaseListHead
);
122 ExpReleaseOrWaitForKeyedEvent(
123 _Inout_ PEX_KEYED_EVENT KeyedEvent
,
124 _In_ PVOID KeyedWaitValue
,
125 _In_ BOOLEAN Alertable
,
126 _In_ PLARGE_INTEGER Timeout
,
127 _In_ BOOLEAN Release
)
129 PETHREAD Thread
, CurrentThread
;
130 PKPROCESS CurrentProcess
;
131 PLIST_ENTRY ListEntry
, WaitListHead1
, WaitListHead2
;
135 /* Get the current process */
136 CurrentProcess
= KeGetCurrentProcess();
138 /* Calculate the hash index */
139 HashIndex
= (ULONG_PTR
)KeyedWaitValue
>> 5;
140 HashIndex
^= (ULONG_PTR
)CurrentProcess
>> 6;
141 HashIndex
%= NUM_KEY_HASH_BUCKETS
;
144 ExAcquirePushLockExclusive(&KeyedEvent
->HashTable
[HashIndex
].Lock
);
146 /* Get the lists for search and wait, depending on whether
147 we want to wait for the event or signal it */
150 WaitListHead1
= &KeyedEvent
->HashTable
[HashIndex
].WaitListHead
;
151 WaitListHead2
= &KeyedEvent
->HashTable
[HashIndex
].ReleaseListHead
;
155 WaitListHead1
= &KeyedEvent
->HashTable
[HashIndex
].ReleaseListHead
;
156 WaitListHead2
= &KeyedEvent
->HashTable
[HashIndex
].WaitListHead
;
159 /* loop the first wait list */
160 ListEntry
= WaitListHead1
->Flink
;
161 while (ListEntry
!= WaitListHead1
)
163 Thread
= CONTAINING_RECORD(ListEntry
, ETHREAD
, KeyedWaitChain
);
165 /* Check if this thread is a correct waiter */
166 if ((Thread
->Tcb
.Process
== CurrentProcess
) &&
167 (Thread
->KeyedWaitValue
== KeyedWaitValue
))
169 /* Remove the thread from the list */
170 RemoveEntryList(&Thread
->KeyedWaitChain
);
172 /* Wake the thread */
173 KeReleaseSemaphore(&Thread
->KeyedWaitSemaphore
, 0, 1, FALSE
);
175 /* Unlock the lists */
176 ExReleasePushLockExclusive(&KeyedEvent
->HashTable
[HashIndex
].Lock
);
178 return STATUS_SUCCESS
;
182 /* Get the current thread */
183 CurrentThread
= PsGetCurrentThread();
185 /* Set the wait key */
186 CurrentThread
->KeyedWaitValue
= KeyedWaitValue
;
188 /* Initialize the wait semaphore */
189 KeInitializeSemaphore(&CurrentThread
->KeyedWaitSemaphore
, 0, 1);
191 /* Insert the current thread into the secondary wait list */
192 InsertTailList(WaitListHead2
, &CurrentThread
->KeyedWaitChain
);
194 /* Unlock the lists */
195 ExReleasePushLockExclusive(&KeyedEvent
->HashTable
[HashIndex
].Lock
);
197 /* Wait for the keyed wait semaphore */
198 Status
= KeWaitForSingleObject(&CurrentThread
->KeyedWaitSemaphore
,
204 return STATUS_SUCCESS
;
209 ExpWaitForKeyedEvent(
210 _Inout_ PEX_KEYED_EVENT KeyedEvent
,
211 _In_ PVOID KeyedWaitValue
,
212 _In_ BOOLEAN Alertable
,
213 _In_ PLARGE_INTEGER Timeout
)
215 /* Call the generic internal function */
216 return ExpReleaseOrWaitForKeyedEvent(KeyedEvent
,
225 ExpReleaseKeyedEvent(
226 _Inout_ PEX_KEYED_EVENT KeyedEvent
,
227 _In_ PVOID KeyedWaitValue
,
228 _In_ BOOLEAN Alertable
,
229 _In_ PLARGE_INTEGER Timeout
)
231 /* Call the generic internal function */
232 return ExpReleaseOrWaitForKeyedEvent(KeyedEvent
,
242 _Out_ PHANDLE OutHandle
,
243 _In_ ACCESS_MASK AccessMask
,
244 _In_ POBJECT_ATTRIBUTES ObjectAttributes
,
247 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
248 PEX_KEYED_EVENT KeyedEvent
;
249 HANDLE KeyedEventHandle
;
255 /* We don't support any flags yet */
256 return STATUS_INVALID_PARAMETER
;
259 /* Create the object */
260 Status
= ObCreateObject(PreviousMode
,
261 ExKeyedEventObjectType
,
265 sizeof(EX_KEYED_EVENT
),
268 (PVOID
*)&KeyedEvent
);
270 /* Check for success */
271 if (!NT_SUCCESS(Status
)) return Status
;
273 /* Initalize the keyed event */
274 ExpInitializeKeyedEvent(KeyedEvent
);
277 Status
= ObInsertObject(KeyedEvent
,
284 /* Check for success (ObInsertObject dereferences!) */
285 if (!NT_SUCCESS(Status
)) return Status
;
287 if (PreviousMode
!= KernelMode
)
289 /* Enter SEH for return */
292 /* Return the handle to the caller */
293 ProbeForWrite(OutHandle
, sizeof(HANDLE
), sizeof(HANDLE
));
294 *OutHandle
= KeyedEventHandle
;
296 _SEH2_EXCEPT(ExSystemExceptionFilter())
298 /* Get the exception code */
299 Status
= _SEH2_GetExceptionCode();
302 ObCloseHandle(KeyedEventHandle
, PreviousMode
);
308 *OutHandle
= KeyedEventHandle
;
318 _Out_ PHANDLE OutHandle
,
319 _In_ ACCESS_MASK AccessMask
,
320 _In_ POBJECT_ATTRIBUTES ObjectAttributes
)
322 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
323 HANDLE KeyedEventHandle
;
326 /* Open the object */
327 Status
= ObOpenObjectByName(ObjectAttributes
,
328 ExKeyedEventObjectType
,
335 /* Check for success */
336 if (!NT_SUCCESS(Status
)) return Status
;
338 /* Enter SEH for return */
339 if (PreviousMode
!= KernelMode
)
343 /* Return the handle to the caller */
344 ProbeForWrite(OutHandle
, sizeof(HANDLE
), sizeof(HANDLE
));
345 *OutHandle
= KeyedEventHandle
;
347 _SEH2_EXCEPT(ExSystemExceptionFilter())
349 /* Get the exception code */
350 Status
= _SEH2_GetExceptionCode();
356 *OutHandle
= KeyedEventHandle
;
368 _In_ BOOLEAN Alertable
,
369 _In_ PLARGE_INTEGER Timeout
)
371 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
372 PEX_KEYED_EVENT KeyedEvent
;
375 /* Check if the caller provided a handle */
378 /* Get the keyed event object */
379 Status
= ObReferenceObjectByHandle(Handle
,
381 ExKeyedEventObjectType
,
386 /* Check for success */
387 if (!NT_SUCCESS(Status
)) return Status
;
391 /* Use the default keyed event for low memory critical sections */
392 KeyedEvent
= ExpCritSecOutOfMemoryEvent
;
396 Status
= ExpWaitForKeyedEvent(KeyedEvent
, Key
, Alertable
, Timeout
);
398 /* Dereference the keyed event */
399 ObDereferenceObject(KeyedEvent
);
401 /* Return the status */
410 _In_ BOOLEAN Alertable
,
411 _In_ PLARGE_INTEGER Timeout
)
413 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
414 PEX_KEYED_EVENT KeyedEvent
;
417 /* Check if the caller provided a handle */
420 /* Get the keyed event object */
421 Status
= ObReferenceObjectByHandle(Handle
,
423 ExKeyedEventObjectType
,
428 /* Check for success */
429 if (!NT_SUCCESS(Status
)) return Status
;
433 /* Use the default keyed event for low memory critical sections */
434 KeyedEvent
= ExpCritSecOutOfMemoryEvent
;
438 Status
= ExpReleaseKeyedEvent(KeyedEvent
, Key
, Alertable
, Timeout
);
440 /* Dereference the keyed event */
441 ObDereferenceObject(KeyedEvent
);
443 /* Return the status */