update for HEAD-2003091401
[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 #define NTOS_MODE_KERNEL
32 #include <ntos.h>
33 #include <internal/id.h>
34 #include <ntos/synch.h>
35 #include <internal/pool.h>
36 #include <internal/safe.h>
37
38 #define NDEBUG
39 #include <internal/debug.h>
40
41 /* GLOBALS *******************************************************************/
42
43 POBJECT_TYPE EXPORTED ExEventObjectType = NULL;
44
45 static GENERIC_MAPPING ExpEventMapping = {
46         STANDARD_RIGHTS_READ | SYNCHRONIZE | EVENT_QUERY_STATE,
47         STANDARD_RIGHTS_WRITE | SYNCHRONIZE | EVENT_MODIFY_STATE,
48         STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | EVENT_QUERY_STATE,
49         EVENT_ALL_ACCESS};
50
51
52 /* FUNCTIONS *****************************************************************/
53
54 NTSTATUS STDCALL
55 NtpCreateEvent(PVOID ObjectBody,
56                PVOID Parent,
57                PWSTR RemainingPath,
58                POBJECT_ATTRIBUTES ObjectAttributes)
59 {
60   DPRINT("NtpCreateEvent(ObjectBody %x, Parent %x, RemainingPath %S)\n",
61          ObjectBody, Parent, RemainingPath);
62
63   if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
64     {
65       return(STATUS_UNSUCCESSFUL);
66     }
67
68   return(STATUS_SUCCESS);
69 }
70
71
72 VOID
73 NtInitializeEventImplementation(VOID)
74 {
75    ExEventObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
76    
77    RtlCreateUnicodeString(&ExEventObjectType->TypeName, L"Event");
78    
79    ExEventObjectType->Tag = TAG('E', 'V', 'T', 'T');
80    ExEventObjectType->MaxObjects = ULONG_MAX;
81    ExEventObjectType->MaxHandles = ULONG_MAX;
82    ExEventObjectType->TotalObjects = 0;
83    ExEventObjectType->TotalHandles = 0;
84    ExEventObjectType->PagedPoolCharge = 0;
85    ExEventObjectType->NonpagedPoolCharge = sizeof(KEVENT);
86    ExEventObjectType->Mapping = &ExpEventMapping;
87    ExEventObjectType->Dump = NULL;
88    ExEventObjectType->Open = NULL;
89    ExEventObjectType->Close = NULL;
90    ExEventObjectType->Delete = NULL;
91    ExEventObjectType->Parse = NULL;
92    ExEventObjectType->Security = NULL;
93    ExEventObjectType->QueryName = NULL;
94    ExEventObjectType->OkayToClose = NULL;
95    ExEventObjectType->Create = NtpCreateEvent;
96    ExEventObjectType->DuplicationNotify = NULL;
97 }
98
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
122 /*
123  * @implemented
124  */
125 NTSTATUS STDCALL
126 NtCreateEvent(OUT PHANDLE UnsafeEventHandle,
127               IN ACCESS_MASK DesiredAccess,
128               IN POBJECT_ATTRIBUTES UnsafeObjectAttributes,
129               IN BOOLEAN ManualReset,
130               IN BOOLEAN InitialState)
131 {
132    PKEVENT Event;
133    HANDLE EventHandle;
134    NTSTATUS Status;
135    OBJECT_ATTRIBUTES SafeObjectAttributes;
136    POBJECT_ATTRIBUTES ObjectAttributes;
137    
138    if (UnsafeObjectAttributes != NULL)
139      {
140        Status = MmCopyFromCaller(&SafeObjectAttributes, UnsafeObjectAttributes,
141                                  sizeof(OBJECT_ATTRIBUTES));
142        if (!NT_SUCCESS(Status))
143          {
144            return(Status);
145          }
146        ObjectAttributes = &SafeObjectAttributes;
147      }
148    else
149      {
150        ObjectAttributes = NULL;
151      }
152
153    Status = ObRosCreateObject(&EventHandle,
154                            DesiredAccess,
155                            ObjectAttributes,
156                            ExEventObjectType,
157                            (PVOID*)&Event);
158    if (!NT_SUCCESS(Status))
159      {
160         return(Status);
161      }
162    KeInitializeEvent(Event,
163                      ManualReset ? NotificationEvent : SynchronizationEvent,
164                      InitialState);
165    ObDereferenceObject(Event);
166
167    Status = MmCopyToCaller(UnsafeEventHandle, &EventHandle, sizeof(HANDLE));
168    if (!NT_SUCCESS(Status))
169      {
170         ZwClose(EventHandle);
171         return(Status);
172      }
173    return(STATUS_SUCCESS);
174 }
175
176
177 NTSTATUS STDCALL
178 NtOpenEvent(OUT PHANDLE UnsafeEventHandle,
179             IN ACCESS_MASK DesiredAccess,
180             IN POBJECT_ATTRIBUTES ObjectAttributes)
181 {
182    NTSTATUS Status;
183    HANDLE EventHandle;
184
185    DPRINT("ObjectName '%wZ'\n", ObjectAttributes->ObjectName);
186
187    Status = ObOpenObjectByName(ObjectAttributes,
188                                ExEventObjectType,
189                                NULL,
190                                UserMode,
191                                DesiredAccess,
192                                NULL,
193                                &EventHandle);
194
195    Status = MmCopyToCaller(UnsafeEventHandle, &EventHandle, sizeof(HANDLE));
196    if (!NT_SUCCESS(Status))
197      {
198        ZwClose(EventHandle);
199        return(Status);
200      }
201    
202    return(Status);
203 }
204
205
206 NTSTATUS STDCALL
207 NtPulseEvent(IN HANDLE EventHandle,
208              IN PULONG UnsafePulseCount OPTIONAL)
209 {
210    PKEVENT Event;
211    NTSTATUS Status;
212
213    DPRINT("NtPulseEvent(EventHandle %x UnsafePulseCount %x)\n",
214           EventHandle, UnsafePulseCount);
215
216    Status = ObReferenceObjectByHandle(EventHandle,
217                                       EVENT_MODIFY_STATE,
218                                       ExEventObjectType,
219                                       UserMode,
220                                       (PVOID*)&Event,
221                                       NULL);
222    if (!NT_SUCCESS(Status))
223      {
224        return(Status);
225      }
226
227    KePulseEvent(Event, EVENT_INCREMENT, FALSE);
228
229    ObDereferenceObject(Event);
230    return(STATUS_SUCCESS);
231 }
232
233
234 NTSTATUS STDCALL
235 NtQueryEvent(IN HANDLE EventHandle,
236              IN EVENT_INFORMATION_CLASS EventInformationClass,
237              OUT PVOID UnsafeEventInformation,
238              IN ULONG EventInformationLength,
239              OUT PULONG UnsafeReturnLength)
240 {
241    EVENT_BASIC_INFORMATION Info;
242    PKEVENT Event;
243    NTSTATUS Status;
244    ULONG ReturnLength;
245
246    if (EventInformationClass > EventBasicInformation)
247      return STATUS_INVALID_INFO_CLASS;
248
249    if (EventInformationLength < sizeof(EVENT_BASIC_INFORMATION))
250      return STATUS_INFO_LENGTH_MISMATCH;
251
252    Status = ObReferenceObjectByHandle(EventHandle,
253                                       EVENT_QUERY_STATE,
254                                       ExEventObjectType,
255                                       UserMode,
256                                       (PVOID*)&Event,
257                                       NULL);
258    if (!NT_SUCCESS(Status))
259      return Status;
260
261    if (Event->Header.Type == InternalNotificationEvent)
262      Info.EventType = NotificationEvent;
263    else
264      Info.EventType = SynchronizationEvent;
265    Info.EventState = KeReadStateEvent(Event);
266
267    Status = MmCopyToCaller(UnsafeEventInformation, &Event, 
268                            sizeof(EVENT_BASIC_INFORMATION));
269    if (!NT_SUCCESS(Status))
270      {
271        ObDereferenceObject(Event);
272        return(Status);
273      }
274
275    ReturnLength = sizeof(EVENT_BASIC_INFORMATION);
276    Status = MmCopyToCaller(UnsafeReturnLength, &ReturnLength, sizeof(ULONG));
277    if (!NT_SUCCESS(Status))
278      {
279        ObDereferenceObject(Event);
280        return(Status);
281      }
282
283    ObDereferenceObject(Event);
284
285    return(STATUS_SUCCESS);
286 }
287
288
289 NTSTATUS STDCALL
290 NtResetEvent(IN HANDLE EventHandle,
291              OUT PULONG UnsafeNumberOfWaitingThreads OPTIONAL)
292 {
293    PKEVENT Event;
294    NTSTATUS Status;
295    
296    DPRINT("NtResetEvent(EventHandle %x)\n", EventHandle);
297    
298    Status = ObReferenceObjectByHandle(EventHandle,
299                                       EVENT_MODIFY_STATE,
300                                       ExEventObjectType,
301                                       UserMode,
302                                       (PVOID*)&Event,
303                                       NULL);
304    if (!NT_SUCCESS(Status))
305      {
306         return(Status);
307      }
308    KeResetEvent(Event);
309    ObDereferenceObject(Event);
310    return(STATUS_SUCCESS);
311 }
312
313
314 /*
315  * @implemented
316  */
317 NTSTATUS STDCALL
318 NtSetEvent(IN HANDLE EventHandle,
319            OUT PULONG UnsafeNumberOfThreadsReleased)
320 {
321    PKEVENT Event;
322    NTSTATUS Status;
323    
324    DPRINT("NtSetEvent(EventHandle %x)\n", EventHandle);
325    
326    Status = ObReferenceObjectByHandle(EventHandle,
327                                       EVENT_MODIFY_STATE,
328                                       ExEventObjectType,
329                                       UserMode,
330                                       (PVOID*)&Event,
331                                       NULL);
332    if (!NT_SUCCESS(Status))
333      {
334         return(Status);
335      }
336    KeSetEvent(Event,EVENT_INCREMENT,FALSE);
337    ObDereferenceObject(Event);
338    return(STATUS_SUCCESS);
339 }
340
341 /* EOF */