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 ******************************************************************/
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
;
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
));
117 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
119 /* Return the exception code */
120 Status
= _SEH2_GetExceptionCode();
121 _SEH2_YIELD(goto Quickie
);
125 /* Check if we can use the internal Wait Array */
126 if (ObjectCount
> THREAD_WAIT_OBJECTS
)
128 /* Allocate from Pool */
129 WaitBlockArray
= ExAllocatePoolWithTag(NonPagedPool
,
136 Status
= STATUS_INSUFFICIENT_RESOURCES
;
144 /* Use the right Executive Handle */
145 if (ObIsKernelHandle(Handles
[i
], PreviousMode
))
147 /* Use the System Handle Table and decode */
148 HandleTable
= ObpKernelHandleTable
;
149 KernelHandle
= ObKernelHandleToHandle(Handles
[i
]);
151 /* Get a pointer to it */
152 HandleEntry
= ExMapHandleToPointer(HandleTable
, KernelHandle
);
156 /* Use the Process' Handle table and get the Ex Handle */
157 HandleTable
= PsGetCurrentProcess()->ObjectTable
;
159 /* Get a pointer to it */
160 HandleEntry
= ExMapHandleToPointer(HandleTable
, Handles
[i
]);
163 /* Check if we have an entry */
166 /* Fail, handle is invalid */
167 Status
= STATUS_INVALID_HANDLE
;
168 DPRINT1("Invalid handle passed to NtWaitForMultipleObjects\n");
172 /* Check for synchronize access */
173 GrantedAccess
= HandleEntry
->GrantedAccess
;
174 if ((PreviousMode
!= KernelMode
) && (!(GrantedAccess
& SYNCHRONIZE
)))
176 /* Unlock the entry and fail */
177 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
178 DPRINT1("Handle does not have SYNCHRONIZE access\n");
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
;
233 DPRINT1("Passed a duplicate object to NtWaitForMultipleObjects\n");
240 } while (i
< ObjectCount
);
243 /* Now we can finally wait. Use SEH since it can raise an exception */
246 /* We're done playing with handles */
248 KeLeaveCriticalRegion();
250 /* Do the kernel wait */
251 Status
= KeWaitForMultipleObjects(ObjectCount
,
260 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
262 /* Get the exception code */
263 Status
= _SEH2_GetExceptionCode();
268 /* First derefence */
269 while (ReferencedObjects
)
271 /* Decrease the number of objects */
274 /* Check if we had a valid object in this position */
275 if (Objects
[ReferencedObjects
])
278 ObDereferenceObject(Objects
[ReferencedObjects
]);
282 /* Free wait block array */
283 if (WaitBlockArray
) ExFreePoolWithTag(WaitBlockArray
, TAG_WAIT
);
285 /* Re-enable APCs if needed */
286 if (LockInUse
) KeLeaveCriticalRegion();
293 * @name NtWaitForMultipleObjects32
296 * The NtWaitForMultipleObjects32 routine <FILLMEIN>
313 * @return STATUS_SUCCESS or appropriate error value.
320 NtWaitForMultipleObjects32(IN ULONG ObjectCount
,
322 IN WAIT_TYPE WaitType
,
323 IN BOOLEAN Alertable
,
324 IN PLARGE_INTEGER TimeOut OPTIONAL
)
327 return NtWaitForMultipleObjects(ObjectCount
,
335 * @name NtWaitForSingleObject
338 * The NtWaitForSingleObject routine <FILLMEIN>
340 * @param ObjectHandle
349 * @return STATUS_SUCCESS or appropriate error value.
356 NtWaitForSingleObject(IN HANDLE ObjectHandle
,
357 IN BOOLEAN Alertable
,
358 IN PLARGE_INTEGER TimeOut OPTIONAL
)
360 PVOID Object
, WaitableObject
;
361 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
362 LARGE_INTEGER SafeTimeOut
;
365 /* Check if we came with a timeout from user mode */
366 if ((TimeOut
) && (PreviousMode
!= KernelMode
))
368 /* Enter SEH for proving */
371 /* Make a copy on the stack */
372 SafeTimeOut
= ProbeForReadLargeInteger(TimeOut
);
373 TimeOut
= &SafeTimeOut
;
375 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
377 /* Return the exception code */
378 _SEH2_YIELD(return _SEH2_GetExceptionCode());
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
,
413 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
415 /* Get the exception code */
416 Status
= _SEH2_GetExceptionCode();
420 /* Dereference the Object */
421 ObDereferenceObject(Object
);
425 DPRINT1("Failed to reference the handle with status 0x%x\n", Status
);
428 /* Return the status */
433 * @name NtSignalAndWaitForSingleObject
436 * The NtSignalAndWaitForSingleObject routine <FILLMEIN>
438 * @param ObjectHandleToSignal
441 * @param WaitableObjectHandle
450 * @return STATUS_SUCCESS or appropriate error value.
457 NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal
,
458 IN HANDLE WaitableObjectHandle
,
459 IN BOOLEAN Alertable
,
460 IN PLARGE_INTEGER TimeOut OPTIONAL
)
462 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
464 PVOID SignalObj
, WaitObj
, WaitableObject
;
465 LARGE_INTEGER SafeTimeOut
;
466 OBJECT_HANDLE_INFORMATION HandleInfo
;
469 /* Check if we came with a timeout from user mode */
470 if ((TimeOut
) && (PreviousMode
!= KernelMode
))
472 /* Enter SEH for probing */
475 /* Make a copy on the stack */
476 SafeTimeOut
= ProbeForReadLargeInteger(TimeOut
);
477 TimeOut
= &SafeTimeOut
;
479 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
481 /* Return the exception code */
482 _SEH2_YIELD(return _SEH2_GetExceptionCode());
487 /* Start by getting the signal object*/
488 Status
= ObReferenceObjectByHandle(ObjectHandleToSignal
,
494 if (!NT_SUCCESS(Status
)) return Status
;
496 /* Now get the wait object */
497 Status
= ObReferenceObjectByHandle(WaitableObjectHandle
,
503 if (!NT_SUCCESS(Status
))
505 /* Failed to reference the wait object */
506 ObDereferenceObject(SignalObj
);
510 /* Get the real waitable object */
511 WaitableObject
= OBJECT_TO_OBJECT_HEADER(WaitObj
)->Type
->DefaultObject
;
513 /* Handle internal offset */
514 if (IsPointerOffset(WaitableObject
))
516 /* Get real pointer */
517 WaitableObject
= (PVOID
)((ULONG_PTR
)WaitObj
+
518 (ULONG_PTR
)WaitableObject
);
521 /* Check Signal Object Type */
522 Type
= OBJECT_TO_OBJECT_HEADER(SignalObj
)->Type
;
523 if (Type
== ExEventObjectType
)
525 /* Check if we came from user-mode without the right access */
526 if ((PreviousMode
!= KernelMode
) &&
527 !(HandleInfo
.GrantedAccess
& EVENT_MODIFY_STATE
))
529 /* Fail: lack of rights */
530 Status
= STATUS_ACCESS_DENIED
;
535 KeSetEvent(SignalObj
, EVENT_INCREMENT
, TRUE
);
537 else if (Type
== ExMutantObjectType
)
539 /* This can raise an exception */
542 /* Release the mutant */
543 KeReleaseMutant(SignalObj
, MUTANT_INCREMENT
, FALSE
, TRUE
);
545 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
547 /* Get the exception code */
548 Status
= _SEH2_GetExceptionCode();
552 else if (Type
== ExSemaphoreObjectType
)
554 /* Check if we came from user-mode without the right access */
555 if ((PreviousMode
!= KernelMode
) &&
556 !(HandleInfo
.GrantedAccess
& SEMAPHORE_MODIFY_STATE
))
558 /* Fail: lack of rights */
559 Status
= STATUS_ACCESS_DENIED
;
563 /* This can raise an exception*/
566 /* Release the semaphore */
567 KeReleaseSemaphore(SignalObj
, SEMAPHORE_INCREMENT
, 1, TRUE
);
569 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
571 /* Get the exception code */
572 Status
= _SEH2_GetExceptionCode();
578 /* This isn't a valid object to be waiting on */
579 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
582 /* Make sure we didn't fail */
583 if (NT_SUCCESS(Status
))
585 /* SEH this since it can also raise an exception */
588 /* Perform the wait now */
589 Status
= KeWaitForSingleObject(WaitableObject
,
595 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
597 /* Get the exception code */
598 Status
= _SEH2_GetExceptionCode();
603 /* We're done here, dereference both objects */
605 ObDereferenceObject(SignalObj
);
606 ObDereferenceObject(WaitObj
);