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