:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[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
99 NTSTATUS STDCALL
100 NtClearEvent(IN HANDLE EventHandle)
101 {
102    PKEVENT Event;
103    NTSTATUS Status;
104    
105    Status = ObReferenceObjectByHandle(EventHandle,
106                                       EVENT_MODIFY_STATE,
107                                       ExEventObjectType,
108                                       UserMode,
109                                       (PVOID*)&Event,
110                                       NULL);
111    if (!NT_SUCCESS(Status))
112      {
113         return(Status);
114      }
115    KeClearEvent(Event);
116    ObDereferenceObject(Event);
117    return(STATUS_SUCCESS);
118 }
119
120
121 NTSTATUS STDCALL
122 NtCreateEvent(OUT PHANDLE UnsafeEventHandle,
123               IN ACCESS_MASK DesiredAccess,
124               IN POBJECT_ATTRIBUTES UnsafeObjectAttributes,
125               IN BOOLEAN ManualReset,
126               IN BOOLEAN InitialState)
127 {
128    PKEVENT Event;
129    HANDLE EventHandle;
130    NTSTATUS Status;
131    OBJECT_ATTRIBUTES SafeObjectAttributes;
132    POBJECT_ATTRIBUTES ObjectAttributes;
133    
134    if (UnsafeObjectAttributes != NULL)
135      {
136        Status = MmCopyFromCaller(&SafeObjectAttributes, UnsafeObjectAttributes,
137                                  sizeof(OBJECT_ATTRIBUTES));
138        if (!NT_SUCCESS(Status))
139          {
140            return(Status);
141          }
142        ObjectAttributes = &SafeObjectAttributes;
143      }
144    else
145      {
146        ObjectAttributes = NULL;
147      }
148
149    Status = ObCreateObject(&EventHandle,
150                            DesiredAccess,
151                            ObjectAttributes,
152                            ExEventObjectType,
153                            (PVOID*)&Event);
154    if (!NT_SUCCESS(Status))
155      {
156         return(Status);
157      }
158    KeInitializeEvent(Event,
159                      ManualReset ? NotificationEvent : SynchronizationEvent,
160                      InitialState);
161    ObDereferenceObject(Event);
162
163    Status = MmCopyToCaller(UnsafeEventHandle, &EventHandle, sizeof(HANDLE));
164    if (!NT_SUCCESS(Status))
165      {
166         ZwClose(EventHandle);
167         return(Status);
168      }
169    return(STATUS_SUCCESS);
170 }
171
172
173 NTSTATUS STDCALL
174 NtOpenEvent(OUT PHANDLE UnsafeEventHandle,
175             IN ACCESS_MASK DesiredAccess,
176             IN POBJECT_ATTRIBUTES ObjectAttributes)
177 {
178    NTSTATUS Status;
179    HANDLE EventHandle;
180
181    DPRINT("ObjectName '%wZ'\n", ObjectAttributes->ObjectName);
182
183    Status = ObOpenObjectByName(ObjectAttributes,
184                                ExEventObjectType,
185                                NULL,
186                                UserMode,
187                                DesiredAccess,
188                                NULL,
189                                &EventHandle);
190
191    Status = MmCopyToCaller(UnsafeEventHandle, &EventHandle, sizeof(HANDLE));
192    if (!NT_SUCCESS(Status))
193      {
194        ZwClose(EventHandle);
195        return(Status);
196      }
197    
198    return(Status);
199 }
200
201
202 NTSTATUS STDCALL
203 NtPulseEvent(IN HANDLE EventHandle,
204              IN PULONG UnsafePulseCount OPTIONAL)
205 {
206    PKEVENT Event;
207    NTSTATUS Status;
208
209    DPRINT("NtPulseEvent(EventHandle %x UnsafePulseCount %x)\n",
210           EventHandle, UnsafePulseCount);
211
212    Status = ObReferenceObjectByHandle(EventHandle,
213                                       EVENT_MODIFY_STATE,
214                                       ExEventObjectType,
215                                       UserMode,
216                                       (PVOID*)&Event,
217                                       NULL);
218    if (!NT_SUCCESS(Status))
219      {
220        return(Status);
221      }
222
223    KePulseEvent(Event, EVENT_INCREMENT, FALSE);
224
225    ObDereferenceObject(Event);
226    return(STATUS_SUCCESS);
227 }
228
229
230 NTSTATUS STDCALL
231 NtQueryEvent(IN HANDLE EventHandle,
232              IN EVENT_INFORMATION_CLASS EventInformationClass,
233              OUT PVOID UnsafeEventInformation,
234              IN ULONG EventInformationLength,
235              OUT PULONG UnsafeReturnLength)
236 {
237    EVENT_BASIC_INFORMATION Info;
238    PKEVENT Event;
239    NTSTATUS Status;
240    ULONG ReturnLength;
241
242    if (EventInformationClass > EventBasicInformation)
243      return STATUS_INVALID_INFO_CLASS;
244
245    if (EventInformationLength < sizeof(EVENT_BASIC_INFORMATION))
246      return STATUS_INFO_LENGTH_MISMATCH;
247
248    Status = ObReferenceObjectByHandle(EventHandle,
249                                       EVENT_QUERY_STATE,
250                                       ExEventObjectType,
251                                       UserMode,
252                                       (PVOID*)&Event,
253                                       NULL);
254    if (!NT_SUCCESS(Status))
255      return Status;
256
257    if (Event->Header.Type == InternalNotificationEvent)
258      Info.EventType = NotificationEvent;
259    else
260      Info.EventType = SynchronizationEvent;
261    Info.EventState = KeReadStateEvent(Event);
262
263    Status = MmCopyToCaller(UnsafeEventInformation, &Event, 
264                            sizeof(EVENT_BASIC_INFORMATION));
265    if (!NT_SUCCESS(Status))
266      {
267        ObDereferenceObject(Event);
268        return(Status);
269      }
270
271    ReturnLength = sizeof(EVENT_BASIC_INFORMATION);
272    Status = MmCopyToCaller(UnsafeReturnLength, &ReturnLength, sizeof(ULONG));
273    if (!NT_SUCCESS(Status))
274      {
275        ObDereferenceObject(Event);
276        return(Status);
277      }
278
279    ObDereferenceObject(Event);
280
281    return(STATUS_SUCCESS);
282 }
283
284
285 NTSTATUS STDCALL
286 NtResetEvent(IN HANDLE EventHandle,
287              OUT PULONG UnsafeNumberOfWaitingThreads OPTIONAL)
288 {
289    PKEVENT Event;
290    NTSTATUS Status;
291    
292    DPRINT("NtResetEvent(EventHandle %x)\n", EventHandle);
293    
294    Status = ObReferenceObjectByHandle(EventHandle,
295                                       EVENT_MODIFY_STATE,
296                                       ExEventObjectType,
297                                       UserMode,
298                                       (PVOID*)&Event,
299                                       NULL);
300    if (!NT_SUCCESS(Status))
301      {
302         return(Status);
303      }
304    KeResetEvent(Event);
305    ObDereferenceObject(Event);
306    return(STATUS_SUCCESS);
307 }
308
309
310 NTSTATUS STDCALL
311 NtSetEvent(IN HANDLE EventHandle,
312            OUT PULONG UnsafeNumberOfThreadsReleased)
313 {
314    PKEVENT Event;
315    NTSTATUS Status;
316    
317    DPRINT("NtSetEvent(EventHandle %x)\n", EventHandle);
318    
319    Status = ObReferenceObjectByHandle(EventHandle,
320                                       EVENT_MODIFY_STATE,
321                                       ExEventObjectType,
322                                       UserMode,
323                                       (PVOID*)&Event,
324                                       NULL);
325    if (!NT_SUCCESS(Status))
326      {
327         return(Status);
328      }
329    KeSetEvent(Event,EVENT_INCREMENT,FALSE);
330    ObDereferenceObject(Event);
331    return(STATUS_SUCCESS);
332 }
333
334 /* EOF */