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
;
171 /* Check for synchronize access */
172 GrantedAccess
= HandleEntry
->GrantedAccess
;
173 if ((PreviousMode
!= KernelMode
) && (!(GrantedAccess
& SYNCHRONIZE
)))
175 /* Unlock the entry and fail */
176 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
177 Status
= STATUS_ACCESS_DENIED
;
181 /* Get the Object Header */
182 ObjectHeader
= ObpGetHandleObject(HandleEntry
);
184 /* Get default Object */
185 DefaultObject
= ObjectHeader
->Type
->DefaultObject
;
187 /* Check if it's the internal offset */
188 if (IsPointerOffset(DefaultObject
))
190 /* Increase reference count */
191 InterlockedIncrement(&ObjectHeader
->PointerCount
);
194 /* Save the Object and Wait Object, this is a relative offset */
195 Objects
[i
] = &ObjectHeader
->Body
;
196 WaitObjects
[i
] = (PVOID
)((ULONG_PTR
)&ObjectHeader
->Body
+
197 (ULONG_PTR
)DefaultObject
);
201 /* This is our internal Object */
204 WaitObjects
[i
] = DefaultObject
;
207 /* Unlock the Handle Table Entry */
208 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
212 } while (i
< ObjectCount
);
214 /* For a Waitall, we can't have the same object more then once */
215 if (WaitType
== WaitAll
)
217 /* Clear the main loop variable */
223 /* Check the current and forward object */
224 for (j
= i
+ 1; j
< ObjectCount
; j
++)
226 /* Make sure they don't match */
227 if (WaitObjects
[i
] == WaitObjects
[j
])
230 Status
= STATUS_INVALID_PARAMETER_MIX
;
237 } while (i
< ObjectCount
);
240 /* Now we can finally wait. Use SEH since it can raise an exception */
243 /* We're done playing with handles */
245 KeLeaveCriticalRegion();
247 /* Do the kernel wait */
248 Status
= KeWaitForMultipleObjects(ObjectCount
,
257 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
259 /* Get the exception code */
260 Status
= _SEH2_GetExceptionCode();
265 /* First derefence */
266 while (ReferencedObjects
)
268 /* Decrease the number of objects */
271 /* Check if we had a valid object in this position */
272 if (Objects
[ReferencedObjects
])
275 ObDereferenceObject(Objects
[ReferencedObjects
]);
279 /* Free wait block array */
280 if (WaitBlockArray
) ExFreePoolWithTag(WaitBlockArray
, TAG_WAIT
);
282 /* Re-enable APCs if needed */
283 if (LockInUse
) KeLeaveCriticalRegion();
290 * @name NtWaitForMultipleObjects32
293 * The NtWaitForMultipleObjects32 routine <FILLMEIN>
310 * @return STATUS_SUCCESS or appropriate error value.
317 NtWaitForMultipleObjects32(IN ULONG ObjectCount
,
319 IN WAIT_TYPE WaitType
,
320 IN BOOLEAN Alertable
,
321 IN PLARGE_INTEGER TimeOut OPTIONAL
)
324 return NtWaitForMultipleObjects(ObjectCount
,
332 * @name NtWaitForSingleObject
335 * The NtWaitForSingleObject routine <FILLMEIN>
337 * @param ObjectHandle
346 * @return STATUS_SUCCESS or appropriate error value.
353 NtWaitForSingleObject(IN HANDLE ObjectHandle
,
354 IN BOOLEAN Alertable
,
355 IN PLARGE_INTEGER TimeOut OPTIONAL
)
357 PVOID Object
, WaitableObject
;
358 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
359 LARGE_INTEGER SafeTimeOut
;
362 /* Check if we came with a timeout from user mode */
363 if ((TimeOut
) && (PreviousMode
!= KernelMode
))
365 /* Enter SEH for proving */
368 /* Make a copy on the stack */
369 SafeTimeOut
= ProbeForReadLargeInteger(TimeOut
);
370 TimeOut
= &SafeTimeOut
;
372 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
374 /* Return the exception code */
375 _SEH2_YIELD(return _SEH2_GetExceptionCode());
381 Status
= ObReferenceObjectByHandle(ObjectHandle
,
387 if (NT_SUCCESS(Status
))
389 /* Get the Waitable Object */
390 WaitableObject
= OBJECT_TO_OBJECT_HEADER(Object
)->Type
->DefaultObject
;
392 /* Is it an offset for internal objects? */
393 if (IsPointerOffset(WaitableObject
))
395 /* Turn it into a pointer */
396 WaitableObject
= (PVOID
)((ULONG_PTR
)Object
+
397 (ULONG_PTR
)WaitableObject
);
400 /* SEH this since it can also raise an exception */
403 /* Ask the kernel to do the wait */
404 Status
= KeWaitForSingleObject(WaitableObject
,
410 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
412 /* Get the exception code */
413 Status
= _SEH2_GetExceptionCode();
417 /* Dereference the Object */
418 ObDereferenceObject(Object
);
421 /* Return the status */
426 * @name NtSignalAndWaitForSingleObject
429 * The NtSignalAndWaitForSingleObject routine <FILLMEIN>
431 * @param ObjectHandleToSignal
434 * @param WaitableObjectHandle
443 * @return STATUS_SUCCESS or appropriate error value.
450 NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal
,
451 IN HANDLE WaitableObjectHandle
,
452 IN BOOLEAN Alertable
,
453 IN PLARGE_INTEGER TimeOut OPTIONAL
)
455 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
457 PVOID SignalObj
, WaitObj
, WaitableObject
;
458 LARGE_INTEGER SafeTimeOut
;
459 OBJECT_HANDLE_INFORMATION HandleInfo
;
462 /* Check if we came with a timeout from user mode */
463 if ((TimeOut
) && (PreviousMode
!= KernelMode
))
465 /* Enter SEH for probing */
468 /* Make a copy on the stack */
469 SafeTimeOut
= ProbeForReadLargeInteger(TimeOut
);
470 TimeOut
= &SafeTimeOut
;
472 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
474 /* Return the exception code */
475 _SEH2_YIELD(return _SEH2_GetExceptionCode());
480 /* Start by getting the signal object*/
481 Status
= ObReferenceObjectByHandle(ObjectHandleToSignal
,
487 if (!NT_SUCCESS(Status
)) return Status
;
489 /* Now get the wait object */
490 Status
= ObReferenceObjectByHandle(WaitableObjectHandle
,
496 if (!NT_SUCCESS(Status
))
498 /* Failed to reference the wait object */
499 ObDereferenceObject(SignalObj
);
503 /* Get the real waitable object */
504 WaitableObject
= OBJECT_TO_OBJECT_HEADER(WaitObj
)->Type
->DefaultObject
;
506 /* Handle internal offset */
507 if (IsPointerOffset(WaitableObject
))
509 /* Get real pointer */
510 WaitableObject
= (PVOID
)((ULONG_PTR
)WaitObj
+
511 (ULONG_PTR
)WaitableObject
);
514 /* Check Signal Object Type */
515 Type
= OBJECT_TO_OBJECT_HEADER(SignalObj
)->Type
;
516 if (Type
== ExEventObjectType
)
518 /* Check if we came from user-mode without the right access */
519 if ((PreviousMode
!= KernelMode
) &&
520 !(HandleInfo
.GrantedAccess
& EVENT_MODIFY_STATE
))
522 /* Fail: lack of rights */
523 Status
= STATUS_ACCESS_DENIED
;
528 KeSetEvent(SignalObj
, EVENT_INCREMENT
, TRUE
);
530 else if (Type
== ExMutantObjectType
)
532 /* This can raise an exception */
535 /* Release the mutant */
536 KeReleaseMutant(SignalObj
, MUTANT_INCREMENT
, FALSE
, TRUE
);
538 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
540 /* Get the exception code */
541 Status
= _SEH2_GetExceptionCode();
545 else if (Type
== ExSemaphoreObjectType
)
547 /* Check if we came from user-mode without the right access */
548 if ((PreviousMode
!= KernelMode
) &&
549 !(HandleInfo
.GrantedAccess
& SEMAPHORE_MODIFY_STATE
))
551 /* Fail: lack of rights */
552 Status
= STATUS_ACCESS_DENIED
;
556 /* This can raise an exception*/
559 /* Release the semaphore */
560 KeReleaseSemaphore(SignalObj
, SEMAPHORE_INCREMENT
, 1, TRUE
);
562 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
564 /* Get the exception code */
565 Status
= _SEH2_GetExceptionCode();
571 /* This isn't a valid object to be waiting on */
572 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
575 /* Make sure we didn't fail */
576 if (NT_SUCCESS(Status
))
578 /* SEH this since it can also raise an exception */
581 /* Perform the wait now */
582 Status
= KeWaitForSingleObject(WaitableObject
,
588 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
590 /* Get the exception code */
591 Status
= _SEH2_GetExceptionCode();
596 /* We're done here, dereference both objects */
598 ObDereferenceObject(SignalObj
);
599 ObDereferenceObject(WaitObj
);