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)
10 /* INCLUDES ******************************************************************/
14 #include <internal/debug.h>
16 /* FUNCTIONS *****************************************************************/
19 * @name NtWaitForMultipleObjects
22 * The NtWaitForMultipleObjects routine <FILLMEIN>
39 * @return STATUS_SUCCESS or appropriate error value.
46 NtWaitForMultipleObjects(IN ULONG ObjectCount
,
47 IN PHANDLE HandleArray
,
48 IN WAIT_TYPE WaitType
,
50 IN PLARGE_INTEGER TimeOut OPTIONAL
)
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
;
60 PHANDLE_TABLE_ENTRY HandleEntry
;
61 POBJECT_HEADER ObjectHeader
;
62 PHANDLE_TABLE HandleTable
;
63 ACCESS_MASK GrantedAccess
;
65 NTSTATUS Status
= STATUS_SUCCESS
;
68 /* Enter a critical region since we'll play with handles */
70 KeEnterCriticalRegion();
72 /* Check for valid Object Count */
73 if ((ObjectCount
> MAXIMUM_WAIT_OBJECTS
) || !(ObjectCount
))
76 Status
= STATUS_INVALID_PARAMETER_1
;
80 /* Check for valid Wait Type */
81 if ((WaitType
!= WaitAll
) && (WaitType
!= WaitAny
))
84 Status
= STATUS_INVALID_PARAMETER_3
;
91 /* Check if the call came from user mode */
92 if(PreviousMode
!= KernelMode
)
94 /* Check if we have a timeout */
97 /* Make a local copy of the timeout on the stack */
98 SafeTimeOut
= ProbeForReadLargeInteger(TimeOut
);
99 TimeOut
= &SafeTimeOut
;
102 /* Probe all the handles */
103 ProbeForRead(HandleArray
,
104 ObjectCount
* sizeof(HANDLE
),
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
113 RtlCopyMemory(Handles
,
115 ObjectCount
* sizeof(HANDLE
));
119 /* Get exception code */
120 Status
= _SEH_GetExceptionCode();
124 /* Fail if we raised an exception */
125 if (!NT_SUCCESS(Status
)) goto Quickie
;
127 /* Check if we can use the internal Wait Array */
128 if (ObjectCount
> THREAD_WAIT_OBJECTS
)
130 /* Allocate from Pool */
131 WaitBlockArray
= ExAllocatePoolWithTag(NonPagedPool
,
138 Status
= STATUS_INSUFFICIENT_RESOURCES
;
146 /* Use the right Executive Handle */
147 if (ObIsKernelHandle(Handles
[i
], PreviousMode
))
149 /* Use the System Handle Table and decode */
150 HandleTable
= ObpKernelHandleTable
;
151 KernelHandle
= ObKernelHandleToHandle(Handles
[i
]);
153 /* Get a pointer to it */
154 HandleEntry
= ExMapHandleToPointer(HandleTable
, KernelHandle
);
158 /* Use the Process' Handle table and get the Ex Handle */
159 HandleTable
= PsGetCurrentProcess()->ObjectTable
;
161 /* Get a pointer to it */
162 HandleEntry
= ExMapHandleToPointer(HandleTable
, Handles
[i
]);
165 /* Check if we have an entry */
168 /* Fail, handle is invalid */
169 Status
= STATUS_INVALID_HANDLE
;
173 /* Check for synchronize access */
174 GrantedAccess
= HandleEntry
->GrantedAccess
;
175 if ((PreviousMode
!= KernelMode
) && (!(GrantedAccess
& SYNCHRONIZE
)))
177 /* Unlock the entry and fail */
178 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
179 Status
= STATUS_ACCESS_DENIED
;
183 /* Get the Object Header */
184 ObjectHeader
= ObpGetHandleObject(HandleEntry
);
186 /* Get default Object */
187 DefaultObject
= ObjectHeader
->Type
->DefaultObject
;
189 /* Check if it's the internal offset */
190 if (IsPointerOffset(DefaultObject
))
192 /* Increase reference count */
193 InterlockedIncrement(&ObjectHeader
->PointerCount
);
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
);
203 /* This is our internal Object */
206 WaitObjects
[i
] = DefaultObject
;
209 /* Unlock the Handle Table Entry */
210 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
214 } while (i
< ObjectCount
);
216 /* For a Waitall, we can't have the same object more then once */
217 if (WaitType
== WaitAll
)
219 /* Clear the main loop variable */
225 /* Check the current and forward object */
226 for (j
= i
+ 1; j
< ObjectCount
; j
++)
228 /* Make sure they don't match */
229 if (WaitObjects
[i
] == WaitObjects
[j
])
232 Status
= STATUS_INVALID_PARAMETER_MIX
;
239 } while (i
< ObjectCount
);
242 /* Now we can finally wait. Use SEH since it can raise an exception */
245 /* We're done playing with handles */
247 KeLeaveCriticalRegion();
249 /* Do the kernel wait */
250 Status
= KeWaitForMultipleObjects(ObjectCount
,
261 /* Get the exception code */
262 Status
= _SEH_GetExceptionCode();
267 /* First derefence */
268 while (ReferencedObjects
)
270 /* Decrease the number of objects */
273 /* Check if we had a valid object in this position */
274 if (Objects
[ReferencedObjects
])
277 ObDereferenceObject(Objects
[ReferencedObjects
]);
281 /* Free wait block array */
282 if (WaitBlockArray
) ExFreePool(WaitBlockArray
);
284 /* Re-enable APCs if needed */
285 if (LockInUse
) KeLeaveCriticalRegion();
292 * @name NtWaitForMultipleObjects32
295 * The NtWaitForMultipleObjects32 routine <FILLMEIN>
312 * @return STATUS_SUCCESS or appropriate error value.
319 NtWaitForMultipleObjects32(IN ULONG ObjectCount
,
321 IN WAIT_TYPE WaitType
,
322 IN BOOLEAN Alertable
,
323 IN PLARGE_INTEGER TimeOut OPTIONAL
)
326 return NtWaitForMultipleObjects(ObjectCount
,
334 * @name NtWaitForSingleObject
337 * The NtWaitForSingleObject routine <FILLMEIN>
339 * @param ObjectHandle
348 * @return STATUS_SUCCESS or appropriate error value.
355 NtWaitForSingleObject(IN HANDLE ObjectHandle
,
356 IN BOOLEAN Alertable
,
357 IN PLARGE_INTEGER TimeOut OPTIONAL
)
359 PVOID Object
, WaitableObject
;
360 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
361 LARGE_INTEGER SafeTimeOut
;
362 NTSTATUS Status
= STATUS_SUCCESS
;
364 /* Check if we came with a timeout from user mode */
365 if ((TimeOut
) && (PreviousMode
!= KernelMode
))
367 /* Enter SEH for proving */
370 /* Make a copy on the stack */
371 SafeTimeOut
= ProbeForReadLargeInteger(TimeOut
);
372 TimeOut
= &SafeTimeOut
;
376 /* Get the exception code */
377 Status
= _SEH_GetExceptionCode();
380 if (!NT_SUCCESS(Status
)) return Status
;
384 Status
= ObReferenceObjectByHandle(ObjectHandle
,
390 if (NT_SUCCESS(Status
))
392 /* Get the Waitable Object */
393 WaitableObject
= OBJECT_TO_OBJECT_HEADER(Object
)->Type
->DefaultObject
;
395 /* Is it an offset for internal objects? */
396 if (IsPointerOffset(WaitableObject
))
398 /* Turn it into a pointer */
399 WaitableObject
= (PVOID
)((ULONG_PTR
)Object
+
400 (ULONG_PTR
)WaitableObject
);
403 /* SEH this since it can also raise an exception */
406 /* Ask the kernel to do the wait */
407 Status
= KeWaitForSingleObject(WaitableObject
,
415 /* Get the exception code */
416 Status
= _SEH_GetExceptionCode();
420 /* Dereference the Object */
421 ObDereferenceObject(Object
);
424 /* Return the status */
429 * @name NtSignalAndWaitForSingleObject
432 * The NtSignalAndWaitForSingleObject routine <FILLMEIN>
434 * @param ObjectHandleToSignal
437 * @param WaitableObjectHandle
446 * @return STATUS_SUCCESS or appropriate error value.
453 NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal
,
454 IN HANDLE WaitableObjectHandle
,
455 IN BOOLEAN Alertable
,
456 IN PLARGE_INTEGER TimeOut OPTIONAL
)
458 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
460 PVOID SignalObj
, WaitObj
, WaitableObject
;
461 LARGE_INTEGER SafeTimeOut
;
462 OBJECT_HANDLE_INFORMATION HandleInfo
;
463 NTSTATUS Status
= STATUS_SUCCESS
;
465 /* Check if we came with a timeout from user mode */
466 if ((TimeOut
) && (PreviousMode
!= KernelMode
))
468 /* Enter SEH for probing */
471 /* Make a copy on the stack */
472 SafeTimeOut
= ProbeForReadLargeInteger(TimeOut
);
473 TimeOut
= &SafeTimeOut
;
477 /* Get the exception code */
478 Status
= _SEH_GetExceptionCode();
481 if (!NT_SUCCESS(Status
)) return Status
;
484 /* Start by getting the signal object*/
485 Status
= ObReferenceObjectByHandle(ObjectHandleToSignal
,
491 if (!NT_SUCCESS(Status
)) return Status
;
493 /* Now get the wait object */
494 Status
= ObReferenceObjectByHandle(WaitableObjectHandle
,
500 if (!NT_SUCCESS(Status
))
502 /* Failed to reference the wait object */
503 ObDereferenceObject(SignalObj
);
507 /* Get the real waitable object */
508 WaitableObject
= OBJECT_TO_OBJECT_HEADER(WaitObj
)->Type
->DefaultObject
;
510 /* Handle internal offset */
511 if (IsPointerOffset(WaitableObject
))
513 /* Get real pointer */
514 WaitableObject
= (PVOID
)((ULONG_PTR
)WaitObj
+
515 (ULONG_PTR
)WaitableObject
);
518 /* Check Signal Object Type */
519 Type
= OBJECT_TO_OBJECT_HEADER(SignalObj
)->Type
;
520 if (Type
== ExEventObjectType
)
522 /* Check if we came from user-mode without the right access */
523 if ((PreviousMode
!= KernelMode
) &&
524 !(HandleInfo
.GrantedAccess
& EVENT_MODIFY_STATE
))
526 /* Fail: lack of rights */
527 Status
= STATUS_ACCESS_DENIED
;
532 KeSetEvent(SignalObj
, EVENT_INCREMENT
, TRUE
);
534 else if (Type
== ExMutantObjectType
)
536 /* This can raise an exception */
539 /* Release the mutant */
540 KeReleaseMutant(SignalObj
, MUTANT_INCREMENT
, FALSE
, TRUE
);
544 /* Get the exception code */
545 Status
= _SEH_GetExceptionCode();
549 else if (Type
== ExSemaphoreObjectType
)
551 /* Check if we came from user-mode without the right access */
552 if ((PreviousMode
!= KernelMode
) &&
553 !(HandleInfo
.GrantedAccess
& SEMAPHORE_MODIFY_STATE
))
555 /* Fail: lack of rights */
556 Status
= STATUS_ACCESS_DENIED
;
560 /* This can raise an exception*/
563 /* Release the semaphore */
564 KeReleaseSemaphore(SignalObj
, SEMAPHORE_INCREMENT
, 1, TRUE
);
568 /* Get the exception code */
569 Status
= _SEH_GetExceptionCode();
575 /* This isn't a valid object to be waiting on */
576 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
579 /* Make sure we didn't fail */
580 if (NT_SUCCESS(Status
))
582 /* SEH this since it can also raise an exception */
585 /* Perform the wait now */
586 Status
= KeWaitForSingleObject(WaitableObject
,
594 /* Get the exception code */
595 Status
= _SEH_GetExceptionCode();
600 /* We're done here, dereference both objects */
602 ObDereferenceObject(SignalObj
);
603 ObDereferenceObject(WaitObj
);