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 _SEH2_YIELD(return _SEH2_GetExceptionCode());
124 /* Check if we can use the internal Wait Array */
125 if (ObjectCount
> THREAD_WAIT_OBJECTS
)
127 /* Allocate from Pool */
128 WaitBlockArray
= ExAllocatePoolWithTag(NonPagedPool
,
135 Status
= STATUS_INSUFFICIENT_RESOURCES
;
143 /* Use the right Executive Handle */
144 if (ObIsKernelHandle(Handles
[i
], PreviousMode
))
146 /* Use the System Handle Table and decode */
147 HandleTable
= ObpKernelHandleTable
;
148 KernelHandle
= ObKernelHandleToHandle(Handles
[i
]);
150 /* Get a pointer to it */
151 HandleEntry
= ExMapHandleToPointer(HandleTable
, KernelHandle
);
155 /* Use the Process' Handle table and get the Ex Handle */
156 HandleTable
= PsGetCurrentProcess()->ObjectTable
;
158 /* Get a pointer to it */
159 HandleEntry
= ExMapHandleToPointer(HandleTable
, Handles
[i
]);
162 /* Check if we have an entry */
165 /* Fail, handle is invalid */
166 Status
= STATUS_INVALID_HANDLE
;
170 /* Check for synchronize access */
171 GrantedAccess
= HandleEntry
->GrantedAccess
;
172 if ((PreviousMode
!= KernelMode
) && (!(GrantedAccess
& SYNCHRONIZE
)))
174 /* Unlock the entry and fail */
175 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
176 Status
= STATUS_ACCESS_DENIED
;
180 /* Get the Object Header */
181 ObjectHeader
= ObpGetHandleObject(HandleEntry
);
183 /* Get default Object */
184 DefaultObject
= ObjectHeader
->Type
->DefaultObject
;
186 /* Check if it's the internal offset */
187 if (IsPointerOffset(DefaultObject
))
189 /* Increase reference count */
190 InterlockedIncrement(&ObjectHeader
->PointerCount
);
193 /* Save the Object and Wait Object, this is a relative offset */
194 Objects
[i
] = &ObjectHeader
->Body
;
195 WaitObjects
[i
] = (PVOID
)((ULONG_PTR
)&ObjectHeader
->Body
+
196 (ULONG_PTR
)DefaultObject
);
200 /* This is our internal Object */
203 WaitObjects
[i
] = DefaultObject
;
206 /* Unlock the Handle Table Entry */
207 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
211 } while (i
< ObjectCount
);
213 /* For a Waitall, we can't have the same object more then once */
214 if (WaitType
== WaitAll
)
216 /* Clear the main loop variable */
222 /* Check the current and forward object */
223 for (j
= i
+ 1; j
< ObjectCount
; j
++)
225 /* Make sure they don't match */
226 if (WaitObjects
[i
] == WaitObjects
[j
])
229 Status
= STATUS_INVALID_PARAMETER_MIX
;
236 } while (i
< ObjectCount
);
239 /* Now we can finally wait. Use SEH since it can raise an exception */
242 /* We're done playing with handles */
244 KeLeaveCriticalRegion();
246 /* Do the kernel wait */
247 Status
= KeWaitForMultipleObjects(ObjectCount
,
256 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
258 /* Get the exception code */
259 Status
= _SEH2_GetExceptionCode();
264 /* First derefence */
265 while (ReferencedObjects
)
267 /* Decrease the number of objects */
270 /* Check if we had a valid object in this position */
271 if (Objects
[ReferencedObjects
])
274 ObDereferenceObject(Objects
[ReferencedObjects
]);
278 /* Free wait block array */
279 if (WaitBlockArray
) ExFreePoolWithTag(WaitBlockArray
, TAG_WAIT
);
281 /* Re-enable APCs if needed */
282 if (LockInUse
) KeLeaveCriticalRegion();
289 * @name NtWaitForMultipleObjects32
292 * The NtWaitForMultipleObjects32 routine <FILLMEIN>
309 * @return STATUS_SUCCESS or appropriate error value.
316 NtWaitForMultipleObjects32(IN ULONG ObjectCount
,
318 IN WAIT_TYPE WaitType
,
319 IN BOOLEAN Alertable
,
320 IN PLARGE_INTEGER TimeOut OPTIONAL
)
323 return NtWaitForMultipleObjects(ObjectCount
,
331 * @name NtWaitForSingleObject
334 * The NtWaitForSingleObject routine <FILLMEIN>
336 * @param ObjectHandle
345 * @return STATUS_SUCCESS or appropriate error value.
352 NtWaitForSingleObject(IN HANDLE ObjectHandle
,
353 IN BOOLEAN Alertable
,
354 IN PLARGE_INTEGER TimeOut OPTIONAL
)
356 PVOID Object
, WaitableObject
;
357 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
358 LARGE_INTEGER SafeTimeOut
;
361 /* Check if we came with a timeout from user mode */
362 if ((TimeOut
) && (PreviousMode
!= KernelMode
))
364 /* Enter SEH for proving */
367 /* Make a copy on the stack */
368 SafeTimeOut
= ProbeForReadLargeInteger(TimeOut
);
369 TimeOut
= &SafeTimeOut
;
371 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
373 /* Return the exception code */
374 _SEH2_YIELD(return _SEH2_GetExceptionCode());
380 Status
= ObReferenceObjectByHandle(ObjectHandle
,
386 if (NT_SUCCESS(Status
))
388 /* Get the Waitable Object */
389 WaitableObject
= OBJECT_TO_OBJECT_HEADER(Object
)->Type
->DefaultObject
;
391 /* Is it an offset for internal objects? */
392 if (IsPointerOffset(WaitableObject
))
394 /* Turn it into a pointer */
395 WaitableObject
= (PVOID
)((ULONG_PTR
)Object
+
396 (ULONG_PTR
)WaitableObject
);
399 /* SEH this since it can also raise an exception */
402 /* Ask the kernel to do the wait */
403 Status
= KeWaitForSingleObject(WaitableObject
,
409 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
411 /* Get the exception code */
412 Status
= _SEH2_GetExceptionCode();
416 /* Dereference the Object */
417 ObDereferenceObject(Object
);
420 /* Return the status */
425 * @name NtSignalAndWaitForSingleObject
428 * The NtSignalAndWaitForSingleObject routine <FILLMEIN>
430 * @param ObjectHandleToSignal
433 * @param WaitableObjectHandle
442 * @return STATUS_SUCCESS or appropriate error value.
449 NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal
,
450 IN HANDLE WaitableObjectHandle
,
451 IN BOOLEAN Alertable
,
452 IN PLARGE_INTEGER TimeOut OPTIONAL
)
454 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
456 PVOID SignalObj
, WaitObj
, WaitableObject
;
457 LARGE_INTEGER SafeTimeOut
;
458 OBJECT_HANDLE_INFORMATION HandleInfo
;
461 /* Check if we came with a timeout from user mode */
462 if ((TimeOut
) && (PreviousMode
!= KernelMode
))
464 /* Enter SEH for probing */
467 /* Make a copy on the stack */
468 SafeTimeOut
= ProbeForReadLargeInteger(TimeOut
);
469 TimeOut
= &SafeTimeOut
;
471 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
473 /* Return the exception code */
474 _SEH2_YIELD(return _SEH2_GetExceptionCode());
479 /* Start by getting the signal object*/
480 Status
= ObReferenceObjectByHandle(ObjectHandleToSignal
,
486 if (!NT_SUCCESS(Status
)) return Status
;
488 /* Now get the wait object */
489 Status
= ObReferenceObjectByHandle(WaitableObjectHandle
,
495 if (!NT_SUCCESS(Status
))
497 /* Failed to reference the wait object */
498 ObDereferenceObject(SignalObj
);
502 /* Get the real waitable object */
503 WaitableObject
= OBJECT_TO_OBJECT_HEADER(WaitObj
)->Type
->DefaultObject
;
505 /* Handle internal offset */
506 if (IsPointerOffset(WaitableObject
))
508 /* Get real pointer */
509 WaitableObject
= (PVOID
)((ULONG_PTR
)WaitObj
+
510 (ULONG_PTR
)WaitableObject
);
513 /* Check Signal Object Type */
514 Type
= OBJECT_TO_OBJECT_HEADER(SignalObj
)->Type
;
515 if (Type
== ExEventObjectType
)
517 /* Check if we came from user-mode without the right access */
518 if ((PreviousMode
!= KernelMode
) &&
519 !(HandleInfo
.GrantedAccess
& EVENT_MODIFY_STATE
))
521 /* Fail: lack of rights */
522 Status
= STATUS_ACCESS_DENIED
;
527 KeSetEvent(SignalObj
, EVENT_INCREMENT
, TRUE
);
529 else if (Type
== ExMutantObjectType
)
531 /* This can raise an exception */
534 /* Release the mutant */
535 KeReleaseMutant(SignalObj
, MUTANT_INCREMENT
, FALSE
, TRUE
);
537 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
539 /* Get the exception code */
540 Status
= _SEH2_GetExceptionCode();
544 else if (Type
== ExSemaphoreObjectType
)
546 /* Check if we came from user-mode without the right access */
547 if ((PreviousMode
!= KernelMode
) &&
548 !(HandleInfo
.GrantedAccess
& SEMAPHORE_MODIFY_STATE
))
550 /* Fail: lack of rights */
551 Status
= STATUS_ACCESS_DENIED
;
555 /* This can raise an exception*/
558 /* Release the semaphore */
559 KeReleaseSemaphore(SignalObj
, SEMAPHORE_INCREMENT
, 1, TRUE
);
561 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
563 /* Get the exception code */
564 Status
= _SEH2_GetExceptionCode();
570 /* This isn't a valid object to be waiting on */
571 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
574 /* Make sure we didn't fail */
575 if (NT_SUCCESS(Status
))
577 /* SEH this since it can also raise an exception */
580 /* Perform the wait now */
581 Status
= KeWaitForSingleObject(WaitableObject
,
587 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
589 /* Get the exception code */
590 Status
= _SEH2_GetExceptionCode();
595 /* We're done here, dereference both objects */
597 ObDereferenceObject(SignalObj
);
598 ObDereferenceObject(WaitObj
);