Fix NtSignalAndwaitForSingleObject: Use SEH when appropriate, use direct Mutant relea...
[reactos.git] / reactos / ntoskrnl / ob / wait.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ob/wait.c
5 * PURPOSE: Handles Waiting on Objects
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created file
8 * David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* FUNCTIONS *****************************************************************/
18
19 BOOL inline FASTCALL KiIsObjectWaitable(PVOID Object);
20
21 NTSTATUS STDCALL
22 NtWaitForMultipleObjects(IN ULONG ObjectCount,
23 IN PHANDLE ObjectsArray,
24 IN WAIT_TYPE WaitType,
25 IN BOOLEAN Alertable,
26 IN PLARGE_INTEGER TimeOut OPTIONAL)
27 {
28 KWAIT_BLOCK WaitBlockArray[MAXIMUM_WAIT_OBJECTS];
29 HANDLE SafeObjectsArray[MAXIMUM_WAIT_OBJECTS];
30 PVOID ObjectPtrArray[MAXIMUM_WAIT_OBJECTS];
31 ULONG i, j;
32 KPROCESSOR_MODE PreviousMode;
33 LARGE_INTEGER SafeTimeOut;
34 NTSTATUS Status = STATUS_SUCCESS;
35
36 DPRINT("NtWaitForMultipleObjects(ObjectCount %lu ObjectsArray[] %x, Alertable %d, "
37 "TimeOut %x)\n", ObjectCount,ObjectsArray,Alertable,TimeOut);
38
39 PreviousMode = ExGetPreviousMode();
40
41 if (ObjectCount > MAXIMUM_WAIT_OBJECTS)
42 return STATUS_UNSUCCESSFUL;
43 if (0 == ObjectCount)
44 return STATUS_INVALID_PARAMETER;
45
46 if(PreviousMode != KernelMode)
47 {
48 _SEH_TRY
49 {
50 ProbeForRead(ObjectsArray,
51 ObjectCount * sizeof(ObjectsArray[0]),
52 sizeof(ULONG));
53 /* make a copy so we don't have to guard with SEH later and keep track of
54 what objects we referenced in case dereferencing pointers suddenly fails */
55 RtlCopyMemory(SafeObjectsArray, ObjectsArray, ObjectCount * sizeof(ObjectsArray[0]));
56 ObjectsArray = SafeObjectsArray;
57
58 if(TimeOut != NULL)
59 {
60 ProbeForRead(TimeOut,
61 sizeof(LARGE_INTEGER),
62 sizeof(ULONG));
63 /* make a local copy of the timeout on the stack */
64 SafeTimeOut = *TimeOut;
65 TimeOut = &SafeTimeOut;
66 }
67 }
68 _SEH_HANDLE
69 {
70 Status = _SEH_GetExceptionCode();
71 }
72 _SEH_END;
73
74 if(!NT_SUCCESS(Status))
75 {
76 return Status;
77 }
78 }
79
80 /* reference all objects */
81 for (i = 0; i < ObjectCount; i++)
82 {
83 Status = ObReferenceObjectByHandle(ObjectsArray[i],
84 SYNCHRONIZE,
85 NULL,
86 PreviousMode,
87 &ObjectPtrArray[i],
88 NULL);
89 if (!NT_SUCCESS(Status) || !KiIsObjectWaitable(ObjectPtrArray[i]))
90 {
91 if (NT_SUCCESS(Status))
92 {
93 DPRINT1("Waiting for object type '%wZ' is not supported\n",
94 &BODY_TO_HEADER(ObjectPtrArray[i])->Type->Name);
95 Status = STATUS_INVALID_HANDLE;
96 i++;
97 }
98 /* dereference all referenced objects */
99 for (j = 0; j < i; j++)
100 {
101 ObDereferenceObject(ObjectPtrArray[j]);
102 }
103
104 return(Status);
105 }
106 }
107
108 Status = KeWaitForMultipleObjects(ObjectCount,
109 ObjectPtrArray,
110 WaitType,
111 UserRequest,
112 PreviousMode,
113 Alertable,
114 TimeOut,
115 WaitBlockArray);
116
117 /* dereference all objects */
118 for (i = 0; i < ObjectCount; i++)
119 {
120 ObDereferenceObject(ObjectPtrArray[i]);
121 }
122
123 return(Status);
124 }
125
126
127 /*
128 * @implemented
129 */
130 NTSTATUS STDCALL
131 NtWaitForSingleObject(IN HANDLE ObjectHandle,
132 IN BOOLEAN Alertable,
133 IN PLARGE_INTEGER TimeOut OPTIONAL)
134 {
135 PVOID ObjectPtr;
136 KPROCESSOR_MODE PreviousMode;
137 LARGE_INTEGER SafeTimeOut;
138 NTSTATUS Status = STATUS_SUCCESS;
139
140 DPRINT("NtWaitForSingleObject(ObjectHandle %x, Alertable %d, TimeOut %x)\n",
141 ObjectHandle,Alertable,TimeOut);
142
143 PreviousMode = ExGetPreviousMode();
144
145 if(TimeOut != NULL && PreviousMode != KernelMode)
146 {
147 _SEH_TRY
148 {
149 ProbeForRead(TimeOut,
150 sizeof(LARGE_INTEGER),
151 sizeof(ULONG));
152 /* make a copy on the stack */
153 SafeTimeOut = *TimeOut;
154 TimeOut = &SafeTimeOut;
155 }
156 _SEH_HANDLE
157 {
158 Status = _SEH_GetExceptionCode();
159 }
160 _SEH_END;
161
162 if(!NT_SUCCESS(Status))
163 {
164 return Status;
165 }
166 }
167
168 Status = ObReferenceObjectByHandle(ObjectHandle,
169 SYNCHRONIZE,
170 NULL,
171 PreviousMode,
172 &ObjectPtr,
173 NULL);
174 if (!NT_SUCCESS(Status))
175 {
176 return(Status);
177 }
178 if (!KiIsObjectWaitable(ObjectPtr))
179 {
180 DPRINT1("Waiting for object type '%wZ' is not supported\n",
181 &BODY_TO_HEADER(ObjectPtr)->Type->Name);
182 Status = STATUS_INVALID_HANDLE;
183 }
184 else
185 {
186 Status = KeWaitForSingleObject(ObjectPtr,
187 UserRequest,
188 PreviousMode,
189 Alertable,
190 TimeOut);
191 }
192
193 ObDereferenceObject(ObjectPtr);
194
195 return(Status);
196 }
197
198
199 NTSTATUS
200 STDCALL
201 NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal,
202 IN HANDLE WaitableObjectHandle,
203 IN BOOLEAN Alertable,
204 IN PLARGE_INTEGER TimeOut OPTIONAL)
205 {
206 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
207 PDISPATCHER_HEADER Header;
208 PVOID SignalObj;
209 PVOID WaitObj;
210 LARGE_INTEGER SafeTimeOut;
211 OBJECT_HANDLE_INFORMATION HandleInfo;
212 NTSTATUS Status = STATUS_SUCCESS;
213
214 /* Capture timeout */
215 if(!TimeOut && PreviousMode != KernelMode)
216 {
217 _SEH_TRY
218 {
219 ProbeForRead(TimeOut,
220 sizeof(LARGE_INTEGER),
221 sizeof(ULONG));
222 /* Make a copy on the stack */
223 SafeTimeOut = *TimeOut;
224 TimeOut = &SafeTimeOut;
225 }
226 _SEH_HANDLE
227 {
228 Status = _SEH_GetExceptionCode();
229 }
230 _SEH_END;
231
232 if(!NT_SUCCESS(Status)) return Status;
233 }
234
235 /* Start by getting the signal object*/
236 Status = ObReferenceObjectByHandle(ObjectHandleToSignal,
237 0,
238 NULL,
239 PreviousMode,
240 &SignalObj,
241 &HandleInfo);
242 if (!NT_SUCCESS(Status))
243 {
244 return Status;
245 }
246
247 /* Now get the wait object */
248 Status = ObReferenceObjectByHandle(WaitableObjectHandle,
249 SYNCHRONIZE,
250 NULL,
251 PreviousMode,
252 &WaitObj,
253 NULL);
254 if (!NT_SUCCESS(Status))
255 {
256 ObDereferenceObject(SignalObj);
257 return Status;
258 }
259
260 /* FIXME: Use DefaultObject from ObjectHeader */
261 Header = (PDISPATCHER_HEADER)SignalObj;
262
263 /* Check dispatcher type */
264 /* FIXME: Check Object Type instead! */
265 switch (Header->Type)
266 {
267 case EventNotificationObject:
268 case EventSynchronizationObject:
269 /* Set the Event */
270 /* FIXME: Check permissions */
271 KeSetEvent(SignalObj, EVENT_INCREMENT, TRUE);
272 break;
273
274 case MutantObject:
275 /* Release the Mutant. This can raise an exception*/
276 _SEH_TRY
277 {
278 KeReleaseMutant(SignalObj, MUTANT_INCREMENT, FALSE, TRUE);
279 }
280 _SEH_HANDLE
281 {
282 Status = _SEH_GetExceptionCode();
283 goto Quickie;
284 }
285 _SEH_END;
286 break;
287
288 case SemaphoreObject:
289 /* Release the Semaphore. This can raise an exception*/
290 /* FIXME: Check permissions */
291 _SEH_TRY
292 {
293 KeReleaseSemaphore(SignalObj, SEMAPHORE_INCREMENT, 1, TRUE);
294 }
295 _SEH_HANDLE
296 {
297 Status = _SEH_GetExceptionCode();
298 goto Quickie;
299 }
300 _SEH_END;
301 break;
302
303 default:
304 Status = STATUS_OBJECT_TYPE_MISMATCH;
305 goto Quickie;
306 }
307
308 /* Now wait. Also SEH this since it can also raise an exception */
309 _SEH_TRY
310 {
311 Status = KeWaitForSingleObject(WaitObj,
312 UserRequest,
313 PreviousMode,
314 Alertable,
315 TimeOut);
316 }
317 _SEH_HANDLE
318 {
319 Status = _SEH_GetExceptionCode();
320 }
321 _SEH_END;
322
323 /* We're done here */
324 Quickie:
325 ObDereferenceObject(SignalObj);
326 ObDereferenceObject(WaitObj);
327 return Status;
328 }
329
330 /* EOF */