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
;
31 _Out_ PHANDLE OutHandle
,
32 _In_ ACCESS_MASK AccessMask
,
33 _In_ POBJECT_ATTRIBUTES ObjectAttributes
,
36 #define KeGetCurrentProcess() ((PKPROCESS)PsGetCurrentProcess())
38 /* GLOBALS *******************************************************************/
40 PEX_KEYED_EVENT ExpCritSecOutOfMemoryEvent
;
41 POBJECT_TYPE ExKeyedEventObjectType
;
44 GENERIC_MAPPING ExpKeyedEventMapping
=
46 STANDARD_RIGHTS_READ
| EVENT_QUERY_STATE
,
47 STANDARD_RIGHTS_WRITE
| EVENT_MODIFY_STATE
,
48 STANDARD_RIGHTS_EXECUTE
,
52 /* FUNCTIONS *****************************************************************/
57 ExpInitializeKeyedEventImplementation(VOID
)
59 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
= {0};
60 UNICODE_STRING TypeName
= RTL_CONSTANT_STRING(L
"KeyedEvent");
61 UNICODE_STRING Name
= RTL_CONSTANT_STRING(L
"\\KernelObjects\\CritSecOutOfMemoryEvent");
64 OBJECT_ATTRIBUTES ObjectAttributes
;
66 /* Set up the object type initializer */
67 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
68 ObjectTypeInitializer
.GenericMapping
= ExpKeyedEventMapping
;
69 ObjectTypeInitializer
.PoolType
= PagedPool
;
70 ObjectTypeInitializer
.ValidAccessMask
= EVENT_ALL_ACCESS
;
71 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
73 /* Create the keyed event object type */
74 Status
= ObCreateObjectType(&TypeName
,
75 &ObjectTypeInitializer
,
77 &ExKeyedEventObjectType
);
78 if (!NT_SUCCESS(Status
)) return FALSE
;
80 /* Create the out of memory event for critical sections */
81 InitializeObjectAttributes(&ObjectAttributes
, &Name
, OBJ_PERMANENT
, NULL
, NULL
);
82 Status
= ZwCreateKeyedEvent(&EventHandle
,
86 if (NT_SUCCESS(Status
))
88 /* Take a reference so we can get rid of the handle */
89 Status
= ObReferenceObjectByHandle(EventHandle
,
91 ExKeyedEventObjectType
,
93 (PVOID
*)&ExpCritSecOutOfMemoryEvent
,
104 ExpInitializeKeyedEvent(
105 _Out_ PEX_KEYED_EVENT KeyedEvent
)
109 /* Loop all hash buckets */
110 for (i
= 0; i
< NUM_KEY_HASH_BUCKETS
; i
++)
112 /* Initialize the mutex and the wait lists */
113 ExInitializePushLock(&KeyedEvent
->HashTable
[i
].Lock
);
114 InitializeListHead(&KeyedEvent
->HashTable
[i
].WaitListHead
);
115 InitializeListHead(&KeyedEvent
->HashTable
[i
].ReleaseListHead
);
121 ExpReleaseOrWaitForKeyedEvent(
122 _Inout_ PEX_KEYED_EVENT KeyedEvent
,
123 _In_ PVOID KeyedWaitValue
,
124 _In_ BOOLEAN Alertable
,
125 _In_ PLARGE_INTEGER Timeout
,
126 _In_ BOOLEAN Release
)
128 PETHREAD Thread
, CurrentThread
;
129 PKPROCESS CurrentProcess
;
130 PLIST_ENTRY ListEntry
, WaitListHead1
, WaitListHead2
;
134 /* Get the current process */
135 CurrentProcess
= KeGetCurrentProcess();
137 /* Calculate the hash index */
138 HashIndex
= (ULONG_PTR
)KeyedWaitValue
>> 5;
139 HashIndex
^= (ULONG_PTR
)CurrentProcess
>> 6;
140 HashIndex
%= NUM_KEY_HASH_BUCKETS
;
143 ExAcquirePushLockExclusive(&KeyedEvent
->HashTable
[HashIndex
].Lock
);
145 /* Get the lists for search and wait, depending on whether
146 we want to wait for the event or signal it */
149 WaitListHead1
= &KeyedEvent
->HashTable
[HashIndex
].WaitListHead
;
150 WaitListHead2
= &KeyedEvent
->HashTable
[HashIndex
].ReleaseListHead
;
154 WaitListHead1
= &KeyedEvent
->HashTable
[HashIndex
].ReleaseListHead
;
155 WaitListHead2
= &KeyedEvent
->HashTable
[HashIndex
].WaitListHead
;
158 /* loop the first wait list */
159 ListEntry
= WaitListHead1
->Flink
;
160 while (ListEntry
!= WaitListHead1
)
162 Thread
= CONTAINING_RECORD(ListEntry
, ETHREAD
, KeyedWaitChain
);
164 /* Check if this thread is a correct waiter */
165 if ((Thread
->Tcb
.Process
== CurrentProcess
) &&
166 (Thread
->KeyedWaitValue
== KeyedWaitValue
))
168 /* Remove the thread from the list */
169 RemoveEntryList(&Thread
->KeyedWaitChain
);
171 /* Wake the thread */
172 KeReleaseSemaphore(&Thread
->KeyedWaitSemaphore
, 0, 1, FALSE
);
174 /* Unlock the lists */
175 ExReleasePushLockExclusive(&KeyedEvent
->HashTable
[HashIndex
].Lock
);
177 return STATUS_SUCCESS
;
181 /* Get the current thread */
182 CurrentThread
= PsGetCurrentThread();
184 /* Set the wait key */
185 CurrentThread
->KeyedWaitValue
= KeyedWaitValue
;
187 /* Initialize the wait semaphore */
188 KeInitializeSemaphore(&CurrentThread
->KeyedWaitSemaphore
, 0, 1);
190 /* Insert the current thread into the secondary wait list */
191 InsertTailList(WaitListHead2
, &CurrentThread
->KeyedWaitChain
);
193 /* Unlock the lists */
194 ExReleasePushLockExclusive(&KeyedEvent
->HashTable
[HashIndex
].Lock
);
196 /* Wait for the keyed wait semaphore */
197 Status
= KeWaitForSingleObject(&CurrentThread
->KeyedWaitSemaphore
,
203 return STATUS_SUCCESS
;
208 ExpWaitForKeyedEvent(
209 _Inout_ PEX_KEYED_EVENT KeyedEvent
,
210 _In_ PVOID KeyedWaitValue
,
211 _In_ BOOLEAN Alertable
,
212 _In_ PLARGE_INTEGER Timeout
)
214 /* Call the generic internal function */
215 return ExpReleaseOrWaitForKeyedEvent(KeyedEvent
,
224 ExpReleaseKeyedEvent(
225 _Inout_ PEX_KEYED_EVENT KeyedEvent
,
226 _In_ PVOID KeyedWaitValue
,
227 _In_ BOOLEAN Alertable
,
228 _In_ PLARGE_INTEGER Timeout
)
230 /* Call the generic internal function */
231 return ExpReleaseOrWaitForKeyedEvent(KeyedEvent
,
241 _Out_ PHANDLE OutHandle
,
242 _In_ ACCESS_MASK AccessMask
,
243 _In_ POBJECT_ATTRIBUTES ObjectAttributes
,
246 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
247 PEX_KEYED_EVENT KeyedEvent
;
248 HANDLE KeyedEventHandle
;
254 /* We don't support any flags yet */
255 return STATUS_INVALID_PARAMETER
;
258 /* Create the object */
259 Status
= ObCreateObject(PreviousMode
,
260 ExKeyedEventObjectType
,
264 sizeof(EX_KEYED_EVENT
),
267 (PVOID
*)&KeyedEvent
);
269 /* Check for success */
270 if (!NT_SUCCESS(Status
)) return Status
;
272 /* Initalize the keyed event */
273 ExpInitializeKeyedEvent(KeyedEvent
);
276 Status
= ObInsertObject(KeyedEvent
,
283 /* Check for success (ObInsertObject dereferences!) */
284 if (!NT_SUCCESS(Status
)) return Status
;
286 if (PreviousMode
!= KernelMode
)
288 /* Enter SEH for return */
291 /* Return the handle to the caller */
292 ProbeForWrite(OutHandle
, sizeof(HANDLE
), sizeof(HANDLE
));
293 *OutHandle
= KeyedEventHandle
;
295 _SEH2_EXCEPT(ExSystemExceptionFilter())
297 /* Get the exception code */
298 Status
= _SEH2_GetExceptionCode();
301 ObCloseHandle(KeyedEventHandle
, PreviousMode
);
307 *OutHandle
= KeyedEventHandle
;
317 _Out_ PHANDLE OutHandle
,
318 _In_ ACCESS_MASK AccessMask
,
319 _In_ POBJECT_ATTRIBUTES ObjectAttributes
)
321 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
322 HANDLE KeyedEventHandle
;
325 /* Open the object */
326 Status
= ObOpenObjectByName(ObjectAttributes
,
327 ExKeyedEventObjectType
,
334 /* Check for success */
335 if (!NT_SUCCESS(Status
)) return Status
;
337 /* Enter SEH for return */
338 if (PreviousMode
!= KernelMode
)
342 /* Return the handle to the caller */
343 ProbeForWrite(OutHandle
, sizeof(HANDLE
), sizeof(HANDLE
));
344 *OutHandle
= KeyedEventHandle
;
346 _SEH2_EXCEPT(ExSystemExceptionFilter())
348 /* Get the exception code */
349 Status
= _SEH2_GetExceptionCode();
355 *OutHandle
= KeyedEventHandle
;
367 _In_ BOOLEAN Alertable
,
368 _In_ PLARGE_INTEGER Timeout
)
370 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
371 PEX_KEYED_EVENT KeyedEvent
;
374 /* Check if the caller provided a handle */
377 /* Get the keyed event object */
378 Status
= ObReferenceObjectByHandle(Handle
,
380 ExKeyedEventObjectType
,
385 /* Check for success */
386 if (!NT_SUCCESS(Status
)) return Status
;
390 /* Use the default keyed event for low memory critical sections */
391 KeyedEvent
= ExpCritSecOutOfMemoryEvent
;
395 Status
= ExpWaitForKeyedEvent(KeyedEvent
, Key
, Alertable
, Timeout
);
397 /* Dereference the keyed event */
398 ObDereferenceObject(KeyedEvent
);
400 /* Return the status */
409 _In_ BOOLEAN Alertable
,
410 _In_ PLARGE_INTEGER Timeout
)
412 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
413 PEX_KEYED_EVENT KeyedEvent
;
416 /* Check if the caller provided a handle */
419 /* Get the keyed event object */
420 Status
= ObReferenceObjectByHandle(Handle
,
422 ExKeyedEventObjectType
,
427 /* Check for success */
428 if (!NT_SUCCESS(Status
)) return Status
;
432 /* Use the default keyed event for low memory critical sections */
433 KeyedEvent
= ExpCritSecOutOfMemoryEvent
;
437 Status
= ExpReleaseKeyedEvent(KeyedEvent
, Key
, Alertable
, Timeout
);
439 /* Dereference the keyed event */
440 ObDereferenceObject(KeyedEvent
);
442 /* Return the status */