723de86ef27b0251123059a6e166d3684003774e
[reactos.git] / reactos / ntoskrnl / nt / evtpair.c
1 /* $Id: evtpair.c,v 1.23 2004/09/28 15:02:29 weiden Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/nt/evtpair.c
6 * PURPOSE: Support for event pairs
7 * PROGRAMMER: David Welch (welch@mcmail.com)
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 * Updated 09/08/2003 by Skywing (skywing@valhallalegends.com)
11 * to correctly maintain ownership of the dispatcher lock
12 * between KeSetEvent and KeWaitForSingleObject calls.
13 * Additionally, implemented the thread-eventpair routines.
14 */
15
16 /* INCLUDES *****************************************************************/
17
18 #include <ntoskrnl.h>
19 #define NDEBUG
20 #include <internal/debug.h>
21
22 #ifndef NTSYSAPI
23 #define NTSYSAPI
24 #endif
25
26 #ifndef NTAPI
27 #define NTAPI STDCALL
28 #endif
29
30
31 /* GLOBALS *******************************************************************/
32
33 POBJECT_TYPE EXPORTED ExEventPairObjectType = NULL;
34
35 static GENERIC_MAPPING ExEventPairMapping = {
36 STANDARD_RIGHTS_READ,
37 STANDARD_RIGHTS_WRITE,
38 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
39 EVENT_PAIR_ALL_ACCESS};
40
41 static KSPIN_LOCK ExThreadEventPairSpinLock;
42
43 /* FUNCTIONS *****************************************************************/
44
45 NTSTATUS STDCALL
46 NtpCreateEventPair(PVOID ObjectBody,
47 PVOID Parent,
48 PWSTR RemainingPath,
49 POBJECT_ATTRIBUTES ObjectAttributes)
50 {
51 DPRINT("NtpCreateEventPair(ObjectBody %x, Parent %x, RemainingPath %S)\n",
52 ObjectBody, Parent, RemainingPath);
53
54 if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
55 {
56 return(STATUS_UNSUCCESSFUL);
57 }
58
59 return(STATUS_SUCCESS);
60 }
61
62 VOID INIT_FUNCTION
63 NtInitializeEventPairImplementation(VOID)
64 {
65 ExEventPairObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
66
67 RtlCreateUnicodeString(&ExEventPairObjectType->TypeName, L"EventPair");
68 ExEventPairObjectType->Tag = TAG('E', 'v', 'P', 'a');
69 ExEventPairObjectType->MaxObjects = ULONG_MAX;
70 ExEventPairObjectType->MaxHandles = ULONG_MAX;
71 ExEventPairObjectType->TotalObjects = 0;
72 ExEventPairObjectType->TotalHandles = 0;
73 ExEventPairObjectType->PagedPoolCharge = 0;
74 ExEventPairObjectType->NonpagedPoolCharge = sizeof(KEVENT_PAIR);
75 ExEventPairObjectType->Mapping = &ExEventPairMapping;
76 ExEventPairObjectType->Dump = NULL;
77 ExEventPairObjectType->Open = NULL;
78 ExEventPairObjectType->Close = NULL;
79 ExEventPairObjectType->Delete = NULL;
80 ExEventPairObjectType->Parse = NULL;
81 ExEventPairObjectType->Security = NULL;
82 ExEventPairObjectType->QueryName = NULL;
83 ExEventPairObjectType->OkayToClose = NULL;
84 ExEventPairObjectType->Create = NtpCreateEventPair;
85 ExEventPairObjectType->DuplicationNotify = NULL;
86
87 KeInitializeSpinLock(&ExThreadEventPairSpinLock);
88 ObpCreateTypeObject(ExEventPairObjectType);
89 }
90
91
92 NTSTATUS STDCALL
93 NtCreateEventPair(OUT PHANDLE EventPairHandle,
94 IN ACCESS_MASK DesiredAccess,
95 IN POBJECT_ATTRIBUTES ObjectAttributes)
96 {
97 PKEVENT_PAIR EventPair;
98 NTSTATUS Status;
99
100 DPRINT("NtCreateEventPair()\n");
101 Status = ObCreateObject(ExGetPreviousMode(),
102 ExEventPairObjectType,
103 ObjectAttributes,
104 ExGetPreviousMode(),
105 NULL,
106 sizeof(KEVENT_PAIR),
107 0,
108 0,
109 (PVOID*)&EventPair);
110 if (!NT_SUCCESS(Status))
111 {
112 return(Status);
113 }
114
115 KeInitializeEvent(&EventPair->LowEvent,
116 SynchronizationEvent,
117 FALSE);
118 KeInitializeEvent(&EventPair->HighEvent,
119 SynchronizationEvent,
120 FALSE);
121
122 Status = ObInsertObject ((PVOID)EventPair,
123 NULL,
124 DesiredAccess,
125 0,
126 NULL,
127 EventPairHandle);
128
129 ObDereferenceObject(EventPair);
130
131 return Status;
132 }
133
134
135 NTSTATUS STDCALL
136 NtOpenEventPair(OUT PHANDLE EventPairHandle,
137 IN ACCESS_MASK DesiredAccess,
138 IN POBJECT_ATTRIBUTES ObjectAttributes)
139 {
140 NTSTATUS Status;
141
142 DPRINT("NtOpenEventPair()\n");
143
144 Status = ObOpenObjectByName(ObjectAttributes,
145 ExEventPairObjectType,
146 NULL,
147 UserMode,
148 DesiredAccess,
149 NULL,
150 EventPairHandle);
151
152 return Status;
153 }
154
155
156 NTSTATUS STDCALL
157 NtSetHighEventPair(IN HANDLE EventPairHandle)
158 {
159 PKEVENT_PAIR EventPair;
160 NTSTATUS Status;
161
162 DPRINT("NtSetHighEventPair(EventPairHandle %x)\n",
163 EventPairHandle);
164
165 Status = ObReferenceObjectByHandle(EventPairHandle,
166 EVENT_PAIR_ALL_ACCESS,
167 ExEventPairObjectType,
168 UserMode,
169 (PVOID*)&EventPair,
170 NULL);
171 if (!NT_SUCCESS(Status))
172 return(Status);
173
174 KeSetEvent(&EventPair->HighEvent,
175 EVENT_INCREMENT,
176 FALSE);
177
178 ObDereferenceObject(EventPair);
179 return(STATUS_SUCCESS);
180 }
181
182
183 NTSTATUS STDCALL
184 NtSetHighWaitLowEventPair(IN HANDLE EventPairHandle)
185 {
186 PKEVENT_PAIR EventPair;
187 NTSTATUS Status;
188
189 DPRINT("NtSetHighWaitLowEventPair(EventPairHandle %x)\n",
190 EventPairHandle);
191
192 Status = ObReferenceObjectByHandle(EventPairHandle,
193 EVENT_PAIR_ALL_ACCESS,
194 ExEventPairObjectType,
195 UserMode,
196 (PVOID*)&EventPair,
197 NULL);
198 if (!NT_SUCCESS(Status))
199 return(Status);
200
201 KeSetEvent(&EventPair->HighEvent,
202 EVENT_INCREMENT,
203 TRUE);
204
205 KeWaitForSingleObject(&EventPair->LowEvent,
206 WrEventPair,
207 UserMode,
208 FALSE,
209 NULL);
210
211 ObDereferenceObject(EventPair);
212 return(STATUS_SUCCESS);
213 }
214
215
216 NTSTATUS STDCALL
217 NtSetLowEventPair(IN HANDLE EventPairHandle)
218 {
219 PKEVENT_PAIR EventPair;
220 NTSTATUS Status;
221
222 DPRINT("NtSetLowEventPair(EventPairHandle %x)\n",
223 EventPairHandle);
224
225 Status = ObReferenceObjectByHandle(EventPairHandle,
226 EVENT_PAIR_ALL_ACCESS,
227 ExEventPairObjectType,
228 UserMode,
229 (PVOID*)&EventPair,
230 NULL);
231 if (!NT_SUCCESS(Status))
232 return(Status);
233
234 KeSetEvent(&EventPair->LowEvent,
235 EVENT_INCREMENT,
236 FALSE);
237
238 ObDereferenceObject(EventPair);
239 return(STATUS_SUCCESS);
240 }
241
242
243 NTSTATUS STDCALL
244 NtSetLowWaitHighEventPair(IN HANDLE EventPairHandle)
245 {
246 PKEVENT_PAIR EventPair;
247 NTSTATUS Status;
248
249 DPRINT("NtSetLowWaitHighEventPair(EventPairHandle %x)\n",
250 EventPairHandle);
251
252 Status = ObReferenceObjectByHandle(EventPairHandle,
253 EVENT_PAIR_ALL_ACCESS,
254 ExEventPairObjectType,
255 UserMode,
256 (PVOID*)&EventPair,
257 NULL);
258 if (!NT_SUCCESS(Status))
259 return(Status);
260
261 KeSetEvent(&EventPair->LowEvent,
262 EVENT_INCREMENT,
263 TRUE);
264
265 KeWaitForSingleObject(&EventPair->HighEvent,
266 WrEventPair,
267 UserMode,
268 FALSE,
269 NULL);
270
271 ObDereferenceObject(EventPair);
272 return(STATUS_SUCCESS);
273 }
274
275
276 NTSTATUS STDCALL
277 NtWaitLowEventPair(IN HANDLE EventPairHandle)
278 {
279 PKEVENT_PAIR EventPair;
280 NTSTATUS Status;
281
282 DPRINT("NtWaitLowEventPair(EventPairHandle %x)\n",
283 EventPairHandle);
284
285 Status = ObReferenceObjectByHandle(EventPairHandle,
286 EVENT_PAIR_ALL_ACCESS,
287 ExEventPairObjectType,
288 UserMode,
289 (PVOID*)&EventPair,
290 NULL);
291 if (!NT_SUCCESS(Status))
292 return(Status);
293
294 KeWaitForSingleObject(&EventPair->LowEvent,
295 WrEventPair,
296 UserMode,
297 FALSE,
298 NULL);
299
300 ObDereferenceObject(EventPair);
301 return(STATUS_SUCCESS);
302 }
303
304
305 NTSTATUS STDCALL
306 NtWaitHighEventPair(IN HANDLE EventPairHandle)
307 {
308 PKEVENT_PAIR EventPair;
309 NTSTATUS Status;
310
311 DPRINT("NtWaitHighEventPair(EventPairHandle %x)\n",
312 EventPairHandle);
313
314 Status = ObReferenceObjectByHandle(EventPairHandle,
315 EVENT_PAIR_ALL_ACCESS,
316 ExEventPairObjectType,
317 UserMode,
318 (PVOID*)&EventPair,
319 NULL);
320 if (!NT_SUCCESS(Status))
321 return(Status);
322
323 KeWaitForSingleObject(&EventPair->HighEvent,
324 WrEventPair,
325 UserMode,
326 FALSE,
327 NULL);
328
329 ObDereferenceObject(EventPair);
330 return(STATUS_SUCCESS);
331 }
332
333 #ifdef _ENABLE_THRDEVTPAIR
334
335 /*
336 * Author: Skywing (skywing@valhallalegends.com), 09/08/2003
337 * Note that the eventpair spinlock must be acquired when setting the thread
338 * eventpair via NtSetInformationThread.
339 * @implemented
340 */
341 NTSTATUS
342 NTSYSAPI
343 NTAPI
344 NtSetLowWaitHighThread(
345 VOID
346 )
347 {
348 PETHREAD Thread;
349 PKEVENT_PAIR EventPair;
350 NTSTATUS Status;
351 KIRQL Irql;
352
353 Thread = PsGetCurrentThread();
354
355 if(!Thread->EventPair)
356 return STATUS_NO_EVENT_PAIR;
357
358 KeAcquireSpinLock(&ExThreadEventPairSpinLock, &Irql);
359
360 EventPair = Thread->EventPair;
361
362 if(EventPair)
363 ObReferenceObjectByPointer(EventPair,
364 EVENT_PAIR_ALL_ACCESS,
365 ExEventPairObjectType,
366 UserMode);
367
368 KeReleaseSpinLock(&ExThreadEventPairSpinLock, Irql);
369
370 if(EventPair == NULL)
371 return STATUS_NO_EVENT_PAIR;
372
373 KeSetEvent(&EventPair->LowEvent,
374 EVENT_INCREMENT,
375 TRUE);
376
377 Status = KeWaitForSingleObject(&EventPair->HighEvent,
378 WrEventPair,
379 UserMode,
380 FALSE,
381 NULL);
382
383 ObDereferenceObject(EventPair);
384
385 return Status;
386 }
387
388
389 /*
390 * Author: Skywing (skywing@valhallalegends.com), 09/08/2003
391 * Note that the eventpair spinlock must be acquired when setting the thread
392 * eventpair via NtSetInformationThread.
393 * @implemented
394 */
395 NTSTATUS
396 NTSYSAPI
397 NTAPI
398 NtSetHighWaitLowThread(
399 VOID
400 )
401 {
402 PETHREAD Thread;
403 PKEVENT_PAIR EventPair;
404 NTSTATUS Status;
405 KIRQL Irql;
406
407 Thread = PsGetCurrentThread();
408
409 if(!Thread->EventPair)
410 return STATUS_NO_EVENT_PAIR;
411
412 KeAcquireSpinLock(&ExThreadEventPairSpinLock, &Irql);
413
414 EventPair = PsGetCurrentThread()->EventPair;
415
416 if(EventPair)
417 ObReferenceObjectByPointer(EventPair,
418 EVENT_PAIR_ALL_ACCESS,
419 ExEventPairObjectType,
420 UserMode);
421
422 KeReleaseSpinLock(&ExThreadEventPairSpinLock, Irql);
423
424 if(EventPair == NULL)
425 return STATUS_NO_EVENT_PAIR;
426
427 KeSetEvent(&EventPair->HighEvent,
428 EVENT_INCREMENT,
429 TRUE);
430
431 Status = KeWaitForSingleObject(&EventPair->LowEvent,
432 WrEventPair,
433 UserMode,
434 FALSE,
435 NULL);
436
437 ObDereferenceObject(EventPair);
438
439 return Status;
440 }
441
442 /*
443 * Author: Skywing (skywing@valhallalegends.com), 09/08/2003
444 * Note that the eventpair spinlock must be acquired when waiting on the
445 * eventpair via NtSetLow/HighWaitHigh/LowThread. Additionally, when
446 * deleting a thread object, NtpSwapThreadEventPair(Thread, NULL) should
447 * be called to release any preexisting eventpair object associated with
448 * the thread. The Microsoft name for this function is not known.
449 */
450 VOID
451 ExpSwapThreadEventPair(
452 IN PETHREAD Thread,
453 IN PKEVENT_PAIR EventPair
454 )
455 {
456 PKEVENT_PAIR OriginalEventPair;
457 KIRQL Irql;
458
459 KeAcquireSpinLock(&ExThreadEventPairSpinLock, &Irql);
460
461 OriginalEventPair = Thread->EventPair;
462 Thread->EventPair = EventPair;
463
464 if(OriginalEventPair)
465 ObDereferenceObject(OriginalEventPair);
466
467 KeReleaseSpinLock(&ExThreadEventPairSpinLock, Irql);
468 }
469
470 #else /* !_ENABLE_THRDEVTPAIR */
471
472 NTSTATUS
473 NTSYSAPI
474 NTAPI
475 NtSetLowWaitHighThread(
476 VOID
477 )
478 {
479 DPRINT1("NtSetLowWaitHighThread() not supported anymore (NT4 only)!\n");
480 return STATUS_NOT_IMPLEMENTED;
481 }
482
483 NTSTATUS
484 NTSYSAPI
485 NTAPI
486 NtSetHighWaitLowThread(
487 VOID
488 )
489 {
490 DPRINT1("NtSetHighWaitLowThread() not supported anymore (NT4 only)!\n");
491 return STATUS_NOT_IMPLEMENTED;
492 }
493
494 #endif /* _ENABLE_THRDEVTPAIR */
495
496 /* EOF */