- KdDebuggerNotPresent should be FALSE by default.
[reactos.git] / reactos / ntoskrnl / ob / obwait.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ob/obwait.c
5 * PURPOSE: Handles Waiting on Objects
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Thomas Weidenmueller (w3seek@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* FUNCTIONS *****************************************************************/
17
18 /*++
19 * @name NtWaitForMultipleObjects
20 * @implemented NT4
21 *
22 * The NtWaitForMultipleObjects routine <FILLMEIN>
23 *
24 * @param ObjectCount
25 * <FILLMEIN>
26 *
27 * @param HandleArray
28 * <FILLMEIN>
29 *
30 * @param WaitType
31 * <FILLMEIN>
32 *
33 * @param Alertable
34 * <FILLMEIN>
35 *
36 * @param TimeOut
37 * <FILLMEIN>
38 *
39 * @return STATUS_SUCCESS or appropriate error value.
40 *
41 * @remarks None.
42 *
43 *--*/
44 NTSTATUS
45 NTAPI
46 NtWaitForMultipleObjects(IN ULONG ObjectCount,
47 IN PHANDLE HandleArray,
48 IN WAIT_TYPE WaitType,
49 IN BOOLEAN Alertable,
50 IN PLARGE_INTEGER TimeOut OPTIONAL)
51 {
52 PKWAIT_BLOCK WaitBlockArray = NULL;
53 HANDLE Handles[MAXIMUM_WAIT_OBJECTS], KernelHandle;
54 PVOID Objects[MAXIMUM_WAIT_OBJECTS];
55 PVOID WaitObjects[MAXIMUM_WAIT_OBJECTS];
56 ULONG i = 0, ReferencedObjects = 0, j;
57 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
58 LARGE_INTEGER SafeTimeOut;
59 BOOLEAN LockInUse;
60 PHANDLE_TABLE_ENTRY HandleEntry;
61 POBJECT_HEADER ObjectHeader;
62 PHANDLE_TABLE HandleTable;
63 ACCESS_MASK GrantedAccess;
64 PVOID DefaultObject;
65 NTSTATUS Status = STATUS_SUCCESS;
66 PAGED_CODE();
67
68 /* Enter a critical region since we'll play with handles */
69 LockInUse = TRUE;
70 KeEnterCriticalRegion();
71
72 /* Check for valid Object Count */
73 if ((ObjectCount > MAXIMUM_WAIT_OBJECTS) || !(ObjectCount))
74 {
75 /* Fail */
76 Status = STATUS_INVALID_PARAMETER_1;
77 goto Quickie;
78 }
79
80 /* Check for valid Wait Type */
81 if ((WaitType != WaitAll) && (WaitType != WaitAny))
82 {
83 /* Fail */
84 Status = STATUS_INVALID_PARAMETER_3;
85 goto Quickie;
86 }
87
88 /* Enter SEH */
89 _SEH_TRY
90 {
91 /* Check if the call came from user mode */
92 if(PreviousMode != KernelMode)
93 {
94 /* Check if we have a timeout */
95 if (TimeOut)
96 {
97 /* Make a local copy of the timeout on the stack */
98 SafeTimeOut = ProbeForReadLargeInteger(TimeOut);
99 TimeOut = &SafeTimeOut;
100 }
101
102 /* Probe all the handles */
103 ProbeForRead(HandleArray,
104 ObjectCount * sizeof(HANDLE),
105 sizeof(HANDLE));
106 }
107
108 /*
109 * Make a copy so we don't have to guard with SEH later and keep
110 * track of what objects we referenced if dereferencing pointers
111 * suddenly fails
112 */
113 RtlCopyMemory(Handles,
114 HandleArray,
115 ObjectCount * sizeof(HANDLE));
116 }
117 _SEH_HANDLE
118 {
119 /* Get exception code */
120 Status = _SEH_GetExceptionCode();
121 }
122 _SEH_END;
123
124 /* Fail if we raised an exception */
125 if (!NT_SUCCESS(Status)) goto Quickie;
126
127 /* Check if we can use the internal Wait Array */
128 if (ObjectCount > THREAD_WAIT_OBJECTS)
129 {
130 /* Allocate from Pool */
131 WaitBlockArray = ExAllocatePoolWithTag(NonPagedPool,
132 ObjectCount *
133 sizeof(KWAIT_BLOCK),
134 TAG_WAIT);
135 if (!WaitBlockArray)
136 {
137 /* Fail */
138 Status = STATUS_INSUFFICIENT_RESOURCES;
139 goto Quickie;
140 }
141 }
142
143 /* Start the loop */
144 do
145 {
146 /* Use the right Executive Handle */
147 if (ObIsKernelHandle(Handles[i], PreviousMode))
148 {
149 /* Use the System Handle Table and decode */
150 HandleTable = ObpKernelHandleTable;
151 KernelHandle = ObKernelHandleToHandle(Handles[i]);
152
153 /* Get a pointer to it */
154 HandleEntry = ExMapHandleToPointer(HandleTable, KernelHandle);
155 }
156 else
157 {
158 /* Use the Process' Handle table and get the Ex Handle */
159 HandleTable = PsGetCurrentProcess()->ObjectTable;
160
161 /* Get a pointer to it */
162 HandleEntry = ExMapHandleToPointer(HandleTable, Handles[i]);
163 }
164
165 /* Check if we have an entry */
166 if (!HandleEntry)
167 {
168 /* Fail, handle is invalid */
169 Status = STATUS_INVALID_HANDLE;
170 goto Quickie;
171 }
172
173 /* Check for synchronize access */
174 GrantedAccess = HandleEntry->GrantedAccess;
175 if ((PreviousMode != KernelMode) && (!(GrantedAccess & SYNCHRONIZE)))
176 {
177 /* Unlock the entry and fail */
178 ExUnlockHandleTableEntry(HandleTable, HandleEntry);
179 Status = STATUS_ACCESS_DENIED;
180 goto Quickie;
181 }
182
183 /* Get the Object Header */
184 ObjectHeader = ObpGetHandleObject(HandleEntry);
185
186 /* Get default Object */
187 DefaultObject = ObjectHeader->Type->DefaultObject;
188
189 /* Check if it's the internal offset */
190 if (IsPointerOffset(DefaultObject))
191 {
192 /* Increase reference count */
193 InterlockedIncrement(&ObjectHeader->PointerCount);
194 ReferencedObjects++;
195
196 /* Save the Object and Wait Object, this is a relative offset */
197 Objects[i] = &ObjectHeader->Body;
198 WaitObjects[i] = (PVOID)((ULONG_PTR)&ObjectHeader->Body +
199 (ULONG_PTR)DefaultObject);
200 }
201 else
202 {
203 /* This is our internal Object */
204 ReferencedObjects++;
205 Objects[i] = NULL;
206 WaitObjects[i] = DefaultObject;
207 }
208
209 /* Unlock the Handle Table Entry */
210 ExUnlockHandleTableEntry(HandleTable, HandleEntry);
211
212 /* Keep looping */
213 i++;
214 } while (i < ObjectCount);
215
216 /* For a Waitall, we can't have the same object more then once */
217 if (WaitType == WaitAll)
218 {
219 /* Clear the main loop variable */
220 i = 0;
221
222 /* Start the loop */
223 do
224 {
225 /* Check the current and forward object */
226 for (j = i + 1; j < ObjectCount; j++)
227 {
228 /* Make sure they don't match */
229 if (WaitObjects[i] == WaitObjects[j])
230 {
231 /* Fail */
232 Status = STATUS_INVALID_PARAMETER_MIX;
233 goto Quickie;
234 }
235 }
236
237 /* Keep looping */
238 i++;
239 } while (i < ObjectCount);
240 }
241
242 /* Now we can finally wait. Use SEH since it can raise an exception */
243 _SEH_TRY
244 {
245 /* We're done playing with handles */
246 LockInUse = FALSE;
247 KeLeaveCriticalRegion();
248
249 /* Do the kernel wait */
250 Status = KeWaitForMultipleObjects(ObjectCount,
251 WaitObjects,
252 WaitType,
253 UserRequest,
254 PreviousMode,
255 Alertable,
256 TimeOut,
257 WaitBlockArray);
258 }
259 _SEH_HANDLE
260 {
261 /* Get the exception code */
262 Status = _SEH_GetExceptionCode();
263 }
264 _SEH_END;
265
266 Quickie:
267 /* First derefence */
268 while (ReferencedObjects)
269 {
270 /* Decrease the number of objects */
271 ReferencedObjects--;
272
273 /* Check if we had a valid object in this position */
274 if (Objects[ReferencedObjects])
275 {
276 /* Dereference it */
277 ObDereferenceObject(Objects[ReferencedObjects]);
278 }
279 }
280
281 /* Free wait block array */
282 if (WaitBlockArray) ExFreePool(WaitBlockArray);
283
284 /* Re-enable APCs if needed */
285 if (LockInUse) KeLeaveCriticalRegion();
286
287 /* Return status */
288 return Status;
289 }
290
291 /*++
292 * @name NtWaitForMultipleObjects32
293 * @implemented NT5.1
294 *
295 * The NtWaitForMultipleObjects32 routine <FILLMEIN>
296 *
297 * @param ObjectCount
298 * <FILLMEIN>
299 *
300 * @param HandleArray
301 * <FILLMEIN>
302 *
303 * @param WaitType
304 * <FILLMEIN>
305 *
306 * @param Alertable
307 * <FILLMEIN>
308 *
309 * @param TimeOut
310 * <FILLMEIN>
311 *
312 * @return STATUS_SUCCESS or appropriate error value.
313 *
314 * @remarks None.
315 *
316 *--*/
317 NTSTATUS
318 NTAPI
319 NtWaitForMultipleObjects32(IN ULONG ObjectCount,
320 IN PLONG Handles,
321 IN WAIT_TYPE WaitType,
322 IN BOOLEAN Alertable,
323 IN PLARGE_INTEGER TimeOut OPTIONAL)
324 {
325 /* FIXME WOW64 */
326 return NtWaitForMultipleObjects(ObjectCount,
327 (PHANDLE)Handles,
328 WaitType,
329 Alertable,
330 TimeOut);
331 }
332
333 /*++
334 * @name NtWaitForSingleObject
335 * @implemented NT4
336 *
337 * The NtWaitForSingleObject routine <FILLMEIN>
338 *
339 * @param ObjectHandle
340 * <FILLMEIN>
341 *
342 * @param Alertable
343 * <FILLMEIN>
344 *
345 * @param TimeOut
346 * <FILLMEIN>
347 *
348 * @return STATUS_SUCCESS or appropriate error value.
349 *
350 * @remarks None.
351 *
352 *--*/
353 NTSTATUS
354 NTAPI
355 NtWaitForSingleObject(IN HANDLE ObjectHandle,
356 IN BOOLEAN Alertable,
357 IN PLARGE_INTEGER TimeOut OPTIONAL)
358 {
359 PVOID Object, WaitableObject;
360 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
361 LARGE_INTEGER SafeTimeOut;
362 NTSTATUS Status = STATUS_SUCCESS;
363
364 /* Check if we came with a timeout from user mode */
365 if ((TimeOut) && (PreviousMode != KernelMode))
366 {
367 /* Enter SEH for proving */
368 _SEH_TRY
369 {
370 /* Make a copy on the stack */
371 SafeTimeOut = ProbeForReadLargeInteger(TimeOut);
372 TimeOut = &SafeTimeOut;
373 }
374 _SEH_HANDLE
375 {
376 /* Get the exception code */
377 Status = _SEH_GetExceptionCode();
378 }
379 _SEH_END;
380 if (!NT_SUCCESS(Status)) return Status;
381 }
382
383 /* Get the Object */
384 Status = ObReferenceObjectByHandle(ObjectHandle,
385 SYNCHRONIZE,
386 NULL,
387 PreviousMode,
388 &Object,
389 NULL);
390 if (NT_SUCCESS(Status))
391 {
392 /* Get the Waitable Object */
393 WaitableObject = OBJECT_TO_OBJECT_HEADER(Object)->Type->DefaultObject;
394
395 /* Is it an offset for internal objects? */
396 if (IsPointerOffset(WaitableObject))
397 {
398 /* Turn it into a pointer */
399 WaitableObject = (PVOID)((ULONG_PTR)Object +
400 (ULONG_PTR)WaitableObject);
401 }
402
403 /* SEH this since it can also raise an exception */
404 _SEH_TRY
405 {
406 /* Ask the kernel to do the wait */
407 Status = KeWaitForSingleObject(WaitableObject,
408 UserRequest,
409 PreviousMode,
410 Alertable,
411 TimeOut);
412 }
413 _SEH_HANDLE
414 {
415 /* Get the exception code */
416 Status = _SEH_GetExceptionCode();
417 }
418 _SEH_END;
419
420 /* Dereference the Object */
421 ObDereferenceObject(Object);
422 }
423
424 /* Return the status */
425 return Status;
426 }
427
428 /*++
429 * @name NtSignalAndWaitForSingleObject
430 * @implemented NT4
431 *
432 * The NtSignalAndWaitForSingleObject routine <FILLMEIN>
433 *
434 * @param ObjectHandleToSignal
435 * <FILLMEIN>
436 *
437 * @param WaitableObjectHandle
438 * <FILLMEIN>
439 *
440 * @param Alertable
441 * <FILLMEIN>
442 *
443 * @param TimeOut
444 * <FILLMEIN>
445 *
446 * @return STATUS_SUCCESS or appropriate error value.
447 *
448 * @remarks None.
449 *
450 *--*/
451 NTSTATUS
452 NTAPI
453 NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal,
454 IN HANDLE WaitableObjectHandle,
455 IN BOOLEAN Alertable,
456 IN PLARGE_INTEGER TimeOut OPTIONAL)
457 {
458 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
459 POBJECT_TYPE Type;
460 PVOID SignalObj, WaitObj, WaitableObject;
461 LARGE_INTEGER SafeTimeOut;
462 OBJECT_HANDLE_INFORMATION HandleInfo;
463 NTSTATUS Status = STATUS_SUCCESS;
464
465 /* Check if we came with a timeout from user mode */
466 if ((TimeOut) && (PreviousMode != KernelMode))
467 {
468 /* Enter SEH for probing */
469 _SEH_TRY
470 {
471 /* Make a copy on the stack */
472 SafeTimeOut = ProbeForReadLargeInteger(TimeOut);
473 TimeOut = &SafeTimeOut;
474 }
475 _SEH_HANDLE
476 {
477 /* Get the exception code */
478 Status = _SEH_GetExceptionCode();
479 }
480 _SEH_END;
481 if (!NT_SUCCESS(Status)) return Status;
482 }
483
484 /* Start by getting the signal object*/
485 Status = ObReferenceObjectByHandle(ObjectHandleToSignal,
486 0,
487 NULL,
488 PreviousMode,
489 &SignalObj,
490 &HandleInfo);
491 if (!NT_SUCCESS(Status)) return Status;
492
493 /* Now get the wait object */
494 Status = ObReferenceObjectByHandle(WaitableObjectHandle,
495 SYNCHRONIZE,
496 NULL,
497 PreviousMode,
498 &WaitObj,
499 NULL);
500 if (!NT_SUCCESS(Status))
501 {
502 /* Failed to reference the wait object */
503 ObDereferenceObject(SignalObj);
504 return Status;
505 }
506
507 /* Get the real waitable object */
508 WaitableObject = OBJECT_TO_OBJECT_HEADER(WaitObj)->Type->DefaultObject;
509
510 /* Handle internal offset */
511 if (IsPointerOffset(WaitableObject))
512 {
513 /* Get real pointer */
514 WaitableObject = (PVOID)((ULONG_PTR)WaitObj +
515 (ULONG_PTR)WaitableObject);
516 }
517
518 /* Check Signal Object Type */
519 Type = OBJECT_TO_OBJECT_HEADER(SignalObj)->Type;
520 if (Type == ExEventObjectType)
521 {
522 /* Check if we came from user-mode without the right access */
523 if ((PreviousMode != KernelMode) &&
524 !(HandleInfo.GrantedAccess & EVENT_MODIFY_STATE))
525 {
526 /* Fail: lack of rights */
527 Status = STATUS_ACCESS_DENIED;
528 goto Quickie;
529 }
530
531 /* Set the Event */
532 KeSetEvent(SignalObj, EVENT_INCREMENT, TRUE);
533 }
534 else if (Type == ExMutantObjectType)
535 {
536 /* This can raise an exception */
537 _SEH_TRY
538 {
539 /* Release the mutant */
540 KeReleaseMutant(SignalObj, MUTANT_INCREMENT, FALSE, TRUE);
541 }
542 _SEH_HANDLE
543 {
544 /* Get the exception code */
545 Status = _SEH_GetExceptionCode();
546 }
547 _SEH_END;
548 }
549 else if (Type == ExSemaphoreObjectType)
550 {
551 /* Check if we came from user-mode without the right access */
552 if ((PreviousMode != KernelMode) &&
553 !(HandleInfo.GrantedAccess & SEMAPHORE_MODIFY_STATE))
554 {
555 /* Fail: lack of rights */
556 Status = STATUS_ACCESS_DENIED;
557 goto Quickie;
558 }
559
560 /* This can raise an exception*/
561 _SEH_TRY
562 {
563 /* Release the semaphore */
564 KeReleaseSemaphore(SignalObj, SEMAPHORE_INCREMENT, 1, TRUE);
565 }
566 _SEH_HANDLE
567 {
568 /* Get the exception code */
569 Status = _SEH_GetExceptionCode();
570 }
571 _SEH_END;
572 }
573 else
574 {
575 /* This isn't a valid object to be waiting on */
576 Status = STATUS_OBJECT_TYPE_MISMATCH;
577 }
578
579 /* Make sure we didn't fail */
580 if (NT_SUCCESS(Status))
581 {
582 /* SEH this since it can also raise an exception */
583 _SEH_TRY
584 {
585 /* Perform the wait now */
586 Status = KeWaitForSingleObject(WaitableObject,
587 UserRequest,
588 PreviousMode,
589 Alertable,
590 TimeOut);
591 }
592 _SEH_HANDLE
593 {
594 /* Get the exception code */
595 Status = _SEH_GetExceptionCode();
596 }
597 _SEH_END;
598 }
599
600 /* We're done here, dereference both objects */
601 Quickie:
602 ObDereferenceObject(SignalObj);
603 ObDereferenceObject(WaitObj);
604 return Status;
605 }
606
607 /* EOF */