f5bf6da20a8f7c47ad8ccae54804f2725b4c06b4
[reactos.git] / ntoskrnl / nt / ntevent.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /*
20  * PROJECT:         ReactOS kernel
21  * FILE:            ntoskrnl/nt/event.c
22  * PURPOSE:         Named event support
23  * PROGRAMMER:      Philip Susi and David Welch
24  * UPDATE HISTORY:
25  *                  Created 22/05/98
26  */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <limits.h>
31 #include <ddk/ntddk.h>
32 #include <internal/id.h>
33 #include <ntos/synch.h>
34 #include <internal/pool.h>
35 #include <internal/safe.h>
36
37 #define NDEBUG
38 #include <internal/debug.h>
39
40 /* GLOBALS *******************************************************************/
41
42 POBJECT_TYPE EXPORTED ExEventObjectType = NULL;
43
44 static GENERIC_MAPPING ExpEventMapping = {
45         STANDARD_RIGHTS_READ | SYNCHRONIZE | EVENT_QUERY_STATE,
46         STANDARD_RIGHTS_WRITE | SYNCHRONIZE | EVENT_MODIFY_STATE,
47         STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | EVENT_QUERY_STATE,
48         EVENT_ALL_ACCESS};
49
50
51 /* FUNCTIONS *****************************************************************/
52
53 NTSTATUS STDCALL
54 NtpCreateEvent(PVOID ObjectBody,
55                PVOID Parent,
56                PWSTR RemainingPath,
57                POBJECT_ATTRIBUTES ObjectAttributes)
58 {
59   DPRINT("NtpCreateEvent(ObjectBody %x, Parent %x, RemainingPath %S)\n",
60          ObjectBody, Parent, RemainingPath);
61
62   if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
63     {
64       return(STATUS_UNSUCCESSFUL);
65     }
66
67   return(STATUS_SUCCESS);
68 }
69
70
71 VOID
72 NtInitializeEventImplementation(VOID)
73 {
74    ExEventObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
75    
76    RtlCreateUnicodeString(&ExEventObjectType->TypeName, L"Event");
77    
78    ExEventObjectType->Tag = TAG('E', 'V', 'T', 'T');
79    ExEventObjectType->MaxObjects = ULONG_MAX;
80    ExEventObjectType->MaxHandles = ULONG_MAX;
81    ExEventObjectType->TotalObjects = 0;
82    ExEventObjectType->TotalHandles = 0;
83    ExEventObjectType->PagedPoolCharge = 0;
84    ExEventObjectType->NonpagedPoolCharge = sizeof(KEVENT);
85    ExEventObjectType->Mapping = &ExpEventMapping;
86    ExEventObjectType->Dump = NULL;
87    ExEventObjectType->Open = NULL;
88    ExEventObjectType->Close = NULL;
89    ExEventObjectType->Delete = NULL;
90    ExEventObjectType->Parse = NULL;
91    ExEventObjectType->Security = NULL;
92    ExEventObjectType->QueryName = NULL;
93    ExEventObjectType->OkayToClose = NULL;
94    ExEventObjectType->Create = NtpCreateEvent;
95    ExEventObjectType->DuplicationNotify = NULL;
96 }
97
98 #ifndef LIBCAPTIVE
99
100 NTSTATUS STDCALL
101 NtClearEvent(IN HANDLE EventHandle)
102 {
103    PKEVENT Event;
104    NTSTATUS Status;
105    
106    Status = ObReferenceObjectByHandle(EventHandle,
107                                       EVENT_MODIFY_STATE,
108                                       ExEventObjectType,
109                                       UserMode,
110                                       (PVOID*)&Event,
111                                       NULL);
112    if (!NT_SUCCESS(Status))
113      {
114         return(Status);
115      }
116    KeClearEvent(Event);
117    ObDereferenceObject(Event);
118    return(STATUS_SUCCESS);
119 }
120
121 #endif /* LIBCAPTIVE */
122
123 NTSTATUS STDCALL
124 NtCreateEvent(OUT PHANDLE UnsafeEventHandle,
125               IN ACCESS_MASK DesiredAccess,
126               IN POBJECT_ATTRIBUTES UnsafeObjectAttributes,
127               IN BOOLEAN ManualReset,
128               IN BOOLEAN InitialState)
129 {
130    PKEVENT Event;
131    HANDLE EventHandle;
132    NTSTATUS Status;
133    OBJECT_ATTRIBUTES SafeObjectAttributes;
134    POBJECT_ATTRIBUTES ObjectAttributes;
135    
136    if (UnsafeObjectAttributes != NULL)
137      {
138        Status = MmCopyFromCaller(&SafeObjectAttributes, UnsafeObjectAttributes,
139                                  sizeof(OBJECT_ATTRIBUTES));
140        if (!NT_SUCCESS(Status))
141          {
142            return(Status);
143          }
144        ObjectAttributes = &SafeObjectAttributes;
145      }
146    else
147      {
148        ObjectAttributes = NULL;
149      }
150
151    Status = ObCreateObject(&EventHandle,
152                            DesiredAccess,
153                            ObjectAttributes,
154                            ExEventObjectType,
155                            (PVOID*)&Event);
156    if (!NT_SUCCESS(Status))
157      {
158         return(Status);
159      }
160    KeInitializeEvent(Event,
161                      ManualReset ? NotificationEvent : SynchronizationEvent,
162                      InitialState);
163    ObDereferenceObject(Event);
164
165    Status = MmCopyToCaller(UnsafeEventHandle, &EventHandle, sizeof(HANDLE));
166    if (!NT_SUCCESS(Status))
167      {
168         ZwClose(EventHandle);
169         return(Status);
170      }
171    return(STATUS_SUCCESS);
172 }
173
174 #ifndef LIBCAPTIVE
175
176 NTSTATUS STDCALL
177 NtOpenEvent(OUT PHANDLE UnsafeEventHandle,
178             IN ACCESS_MASK DesiredAccess,
179             IN POBJECT_ATTRIBUTES ObjectAttributes)
180 {
181    NTSTATUS Status;
182    HANDLE EventHandle;
183
184    DPRINT("ObjectName '%wZ'\n", ObjectAttributes->ObjectName);
185
186    Status = ObOpenObjectByName(ObjectAttributes,
187                                ExEventObjectType,
188                                NULL,
189                                UserMode,
190                                DesiredAccess,
191                                NULL,
192                                &EventHandle);
193
194    Status = MmCopyToCaller(UnsafeEventHandle, &EventHandle, sizeof(HANDLE));
195    if (!NT_SUCCESS(Status))
196      {
197        ZwClose(EventHandle);
198        return(Status);
199      }
200    
201    return(Status);
202 }
203
204
205 NTSTATUS STDCALL
206 NtPulseEvent(IN HANDLE EventHandle,
207              IN PULONG UnsafePulseCount OPTIONAL)
208 {
209    PKEVENT Event;
210    NTSTATUS Status;
211
212    DPRINT("NtPulseEvent(EventHandle %x UnsafePulseCount %x)\n",
213           EventHandle, UnsafePulseCount);
214
215    Status = ObReferenceObjectByHandle(EventHandle,
216                                       EVENT_MODIFY_STATE,
217                                       ExEventObjectType,
218                                       UserMode,
219                                       (PVOID*)&Event,
220                                       NULL);
221    if (!NT_SUCCESS(Status))
222      {
223        return(Status);
224      }
225
226    KePulseEvent(Event, EVENT_INCREMENT, FALSE);
227
228    ObDereferenceObject(Event);
229    return(STATUS_SUCCESS);
230 }
231
232
233 NTSTATUS STDCALL
234 NtQueryEvent(IN HANDLE EventHandle,
235              IN EVENT_INFORMATION_CLASS EventInformationClass,
236              OUT PVOID UnsafeEventInformation,
237              IN ULONG EventInformationLength,
238              OUT PULONG UnsafeReturnLength)
239 {
240    EVENT_BASIC_INFORMATION Info;
241    PKEVENT Event;
242    NTSTATUS Status;
243    ULONG ReturnLength;
244
245    if (EventInformationClass > EventBasicInformation)
246      return STATUS_INVALID_INFO_CLASS;
247
248    if (EventInformationLength < sizeof(EVENT_BASIC_INFORMATION))
249      return STATUS_INFO_LENGTH_MISMATCH;
250
251    Status = ObReferenceObjectByHandle(EventHandle,
252                                       EVENT_QUERY_STATE,
253                                       ExEventObjectType,
254                                       UserMode,
255                                       (PVOID*)&Event,
256                                       NULL);
257    if (!NT_SUCCESS(Status))
258      return Status;
259
260    if (Event->Header.Type == InternalNotificationEvent)
261      Info.EventType = NotificationEvent;
262    else
263      Info.EventType = SynchronizationEvent;
264    Info.EventState = KeReadStateEvent(Event);
265
266    Status = MmCopyToCaller(UnsafeEventInformation, &Event, 
267                            sizeof(EVENT_BASIC_INFORMATION));
268    if (!NT_SUCCESS(Status))
269      {
270        ObDereferenceObject(Event);
271        return(Status);
272      }
273
274    ReturnLength = sizeof(EVENT_BASIC_INFORMATION);
275    Status = MmCopyToCaller(UnsafeReturnLength, &ReturnLength, sizeof(ULONG));
276    if (!NT_SUCCESS(Status))
277      {
278        ObDereferenceObject(Event);
279        return(Status);
280      }
281
282    ObDereferenceObject(Event);
283
284    return(STATUS_SUCCESS);
285 }
286
287
288 NTSTATUS STDCALL
289 NtResetEvent(IN HANDLE EventHandle,
290              OUT PULONG UnsafeNumberOfWaitingThreads OPTIONAL)
291 {
292    PKEVENT Event;
293    NTSTATUS Status;
294    
295    DPRINT("NtResetEvent(EventHandle %x)\n", EventHandle);
296    
297    Status = ObReferenceObjectByHandle(EventHandle,
298                                       EVENT_MODIFY_STATE,
299                                       ExEventObjectType,
300                                       UserMode,
301                                       (PVOID*)&Event,
302                                       NULL);
303    if (!NT_SUCCESS(Status))
304      {
305         return(Status);
306      }
307    KeResetEvent(Event);
308    ObDereferenceObject(Event);
309    return(STATUS_SUCCESS);
310 }
311
312
313 NTSTATUS STDCALL
314 NtSetEvent(IN HANDLE EventHandle,
315            OUT PULONG UnsafeNumberOfThreadsReleased)
316 {
317    PKEVENT Event;
318    NTSTATUS Status;
319    
320    DPRINT("NtSetEvent(EventHandle %x)\n", EventHandle);
321    
322    Status = ObReferenceObjectByHandle(EventHandle,
323                                       EVENT_MODIFY_STATE,
324                                       ExEventObjectType,
325                                       UserMode,
326                                       (PVOID*)&Event,
327                                       NULL);
328    if (!NT_SUCCESS(Status))
329      {
330         return(Status);
331      }
332    KeSetEvent(Event,EVENT_INCREMENT,FALSE);
333    ObDereferenceObject(Event);
334    return(STATUS_SUCCESS);
335 }
336
337 #endif /* LIBCAPTIVE */
338
339 /* EOF */