Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

885 lines
26 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Copyright (c) 1992 Microsoft Corporation
  4. Module Name:
  5. obwait.c
  6. Abstract:
  7. This module implements the generic wait system services.
  8. Author:
  9. Steve Wood (stevewo) 12-May-1989
  10. Revision History:
  11. --*/
  12. #include "obp.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE, NtWaitForSingleObject)
  15. #pragma alloc_text(PAGE, NtWaitForMultipleObjects)
  16. #pragma alloc_text(PAGE, ObWaitForSingleObject)
  17. #endif
  18. //
  19. // We special case these three object types in the wait routine
  20. //
  21. extern POBJECT_TYPE ExEventObjectType;
  22. extern POBJECT_TYPE ExMutantObjectType;
  23. extern POBJECT_TYPE ExSemaphoreObjectType;
  24. NTSTATUS
  25. NtSignalAndWaitForSingleObject (
  26. IN HANDLE SignalHandle,
  27. IN HANDLE WaitHandle,
  28. IN BOOLEAN Alertable,
  29. IN PLARGE_INTEGER Timeout OPTIONAL
  30. )
  31. /*++
  32. Routine Description:
  33. This function atomically signals the specified signal object and then
  34. waits until the specified wait object attains a state of Signaled. An
  35. optional timeout can also be specified. If a timeout is not specified,
  36. then the wait will not be satisfied until the wait object attains a
  37. state of Signaled. If a timeout is specified, and the wait object has
  38. not attained a state of Signaled when the timeout expires, then the
  39. wait is automatically satisfied. If an explicit timeout value of zero
  40. is specified, then no wait will occur if the wait cannot be satisfied
  41. immediately. The wait can also be specified as alertable.
  42. Arguments:
  43. SignalHandle - Supplies the handle of the signal object.
  44. WaitHandle - Supplies the handle for the wait object.
  45. Alertable - Supplies a boolean value that specifies whether the wait
  46. is alertable.
  47. Timeout - Supplies an pointer to an absolute or relative time over
  48. which the wait is to occur.
  49. Return Value:
  50. The wait completion status. A value of STATUS_TIMEOUT is returned if a
  51. timeout occurred. A value of STATUS_SUCCESS is returned if the specified
  52. object satisfied the wait. A value of STATUS_ALERTED is returned if the
  53. wait was aborted to deliver an alert to the current thread. A value of
  54. STATUS_USER_APC is returned if the wait was aborted to deliver a user
  55. APC to the current thread.
  56. --*/
  57. {
  58. OBJECT_HANDLE_INFORMATION HandleInformation;
  59. KPROCESSOR_MODE PreviousMode;
  60. PVOID RealObject;
  61. PVOID SignalObject;
  62. POBJECT_HEADER SignalObjectHeader;
  63. NTSTATUS Status;
  64. LARGE_INTEGER TimeoutValue;
  65. PVOID WaitObject;
  66. POBJECT_HEADER WaitObjectHeader;
  67. //
  68. // Establish an exception handler and probe the specified timeout value
  69. // if necessary. If the probe fails, then return the exception code as
  70. // the service status.
  71. //
  72. PreviousMode = KeGetPreviousMode();
  73. if ((ARGUMENT_PRESENT(Timeout)) && (PreviousMode != KernelMode)) {
  74. try {
  75. TimeoutValue = ProbeAndReadLargeInteger(Timeout);
  76. Timeout = &TimeoutValue;
  77. } except(EXCEPTION_EXECUTE_HANDLER) {
  78. return GetExceptionCode();
  79. }
  80. }
  81. //
  82. // Reference the signal object by handle.
  83. //
  84. Status = ObReferenceObjectByHandle( SignalHandle,
  85. 0,
  86. NULL,
  87. PreviousMode,
  88. &SignalObject,
  89. &HandleInformation );
  90. //
  91. // If the reference was successful, then reference the wait object by
  92. // handle.
  93. //
  94. if (NT_SUCCESS(Status)) {
  95. Status = ObReferenceObjectByHandle( WaitHandle,
  96. SYNCHRONIZE,
  97. NULL,
  98. PreviousMode,
  99. &WaitObject,
  100. NULL );
  101. //
  102. // If the reference was successful, then determine the real wait
  103. // object, check the signal object access, signal the signal object,
  104. // and wait for the real wait object.
  105. //
  106. if (NT_SUCCESS(Status)) {
  107. WaitObjectHeader = OBJECT_TO_OBJECT_HEADER(WaitObject);
  108. RealObject = WaitObjectHeader->Type->DefaultObject;
  109. if ((LONG_PTR)RealObject >= 0) {
  110. RealObject = (PVOID)((PCHAR)WaitObject + (ULONG_PTR)RealObject);
  111. }
  112. //
  113. // If the signal object is an event, then check for modify access
  114. // and set the event. Otherwise, if the signal object is a
  115. // mutant, then attempt to release ownership of the mutant.
  116. // Otherwise, if the object is a semaphore, then check for modify
  117. // access and release the semaphore. Otherwise, the signal objet
  118. // is invalid.
  119. //
  120. SignalObjectHeader = OBJECT_TO_OBJECT_HEADER(SignalObject);
  121. Status = STATUS_ACCESS_DENIED;
  122. if (SignalObjectHeader->Type == ExEventObjectType) {
  123. //
  124. // Check for access to the specified event object,
  125. //
  126. if ((PreviousMode != KernelMode) &&
  127. (SeComputeDeniedAccesses( HandleInformation.GrantedAccess,
  128. EVENT_MODIFY_STATE) != 0 )) {
  129. goto WaitExit;
  130. }
  131. //
  132. // Set the specified event and wait atomically.
  133. //
  134. // N.B. This returns with the dispatcher lock held !!!
  135. //
  136. KeSetEvent((PKEVENT)SignalObject, EVENT_INCREMENT, TRUE);
  137. } else if (SignalObjectHeader->Type == ExMutantObjectType) {
  138. //
  139. // Release the specified mutant and wait atomically.
  140. //
  141. // N.B. The release will only be successful if the current
  142. // thread is the owner of the mutant.
  143. //
  144. try {
  145. KeReleaseMutant( (PKMUTANT)SignalObject,
  146. MUTANT_INCREMENT,
  147. FALSE,
  148. TRUE );
  149. } except((GetExceptionCode () == STATUS_ABANDONED ||
  150. GetExceptionCode () == STATUS_MUTANT_NOT_OWNED)?
  151. EXCEPTION_EXECUTE_HANDLER :
  152. EXCEPTION_CONTINUE_SEARCH) {
  153. Status = GetExceptionCode();
  154. goto WaitExit;
  155. }
  156. } else if (SignalObjectHeader->Type == ExSemaphoreObjectType) {
  157. //
  158. // Check for access to the specified semaphore object,
  159. //
  160. if ((PreviousMode != KernelMode) &&
  161. (SeComputeDeniedAccesses( HandleInformation.GrantedAccess,
  162. SEMAPHORE_MODIFY_STATE) != 0 )) {
  163. goto WaitExit;
  164. }
  165. //
  166. // Release the specified semaphore and wait atomically.
  167. //
  168. try {
  169. //
  170. // Release the specified semaphore and wait atomically.
  171. //
  172. KeReleaseSemaphore( (PKSEMAPHORE)SignalObject,
  173. SEMAPHORE_INCREMENT,
  174. 1,
  175. TRUE );
  176. } except((GetExceptionCode () == STATUS_SEMAPHORE_LIMIT_EXCEEDED)?
  177. EXCEPTION_EXECUTE_HANDLER :
  178. EXCEPTION_CONTINUE_SEARCH) {
  179. Status = GetExceptionCode();
  180. goto WaitExit;
  181. }
  182. } else {
  183. Status = STATUS_OBJECT_TYPE_MISMATCH;
  184. goto WaitExit;
  185. }
  186. //
  187. // Protect the wait call just in case KeWait decides to raise
  188. // For example, a mutant level is exceeded
  189. //
  190. try {
  191. Status = KeWaitForSingleObject( RealObject,
  192. UserRequest,
  193. PreviousMode,
  194. Alertable,
  195. Timeout );
  196. } except((GetExceptionCode () == STATUS_MUTANT_LIMIT_EXCEEDED)?
  197. EXCEPTION_EXECUTE_HANDLER :
  198. EXCEPTION_CONTINUE_SEARCH) {
  199. Status = GetExceptionCode();
  200. }
  201. WaitExit:
  202. ObDereferenceObject(WaitObject);
  203. }
  204. ObDereferenceObject(SignalObject);
  205. }
  206. return Status;
  207. }
  208. NTSTATUS
  209. NtWaitForSingleObject (
  210. IN HANDLE Handle,
  211. IN BOOLEAN Alertable,
  212. IN PLARGE_INTEGER Timeout OPTIONAL
  213. )
  214. /*++
  215. Routine Description:
  216. This function waits until the specified object attains a state of
  217. Signaled. An optional timeout can also be specified. If a timeout
  218. is not specified, then the wait will not be satisfied until the
  219. object attains a state of Signaled. If a timeout is specified, and
  220. the object has not attained a state of Signaled when the timeout
  221. expires, then the wait is automatically satisfied. If an explicit
  222. timeout value of zero is specified, then no wait will occur if the
  223. wait cannot be satisfied immediately. The wait can also be specified
  224. as alertable.
  225. Arguments:
  226. Handle - Supplies the handle for the wait object.
  227. Alertable - Supplies a boolean value that specifies whether the wait
  228. is alertable.
  229. Timeout - Supplies an pointer to an absolute or relative time over
  230. which the wait is to occur.
  231. Return Value:
  232. The wait completion status. A value of STATUS_TIMEOUT is returned if a
  233. timeout occurred. A value of STATUS_SUCCESS is returned if the specified
  234. object satisfied the wait. A value of STATUS_ALERTED is returned if the
  235. wait was aborted to deliver an alert to the current thread. A value of
  236. STATUS_USER_APC is returned if the wait was aborted to deliver a user
  237. APC to the current thread.
  238. --*/
  239. {
  240. PVOID Object;
  241. POBJECT_HEADER ObjectHeader;
  242. KPROCESSOR_MODE PreviousMode;
  243. NTSTATUS Status;
  244. LARGE_INTEGER TimeoutValue;
  245. PVOID WaitObject;
  246. PAGED_CODE();
  247. //
  248. // Get previous processor mode and probe and capture timeout argument
  249. // if necessary.
  250. //
  251. PreviousMode = KeGetPreviousMode();
  252. if ((ARGUMENT_PRESENT(Timeout)) && (PreviousMode != KernelMode)) {
  253. try {
  254. TimeoutValue = ProbeAndReadLargeInteger(Timeout);
  255. Timeout = &TimeoutValue;
  256. } except(EXCEPTION_EXECUTE_HANDLER) {
  257. return GetExceptionCode();
  258. }
  259. }
  260. //
  261. // Get a referenced pointer to the specified object with synchronize
  262. // access.
  263. //
  264. Status = ObReferenceObjectByHandle( Handle,
  265. SYNCHRONIZE,
  266. NULL,
  267. PreviousMode,
  268. &Object,
  269. NULL );
  270. //
  271. // If access is granted, then check to determine if the specified object
  272. // can be waited on.
  273. //
  274. if (NT_SUCCESS(Status)) {
  275. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  276. WaitObject = ObjectHeader->Type->DefaultObject;
  277. if ((LONG_PTR)WaitObject >= 0) {
  278. WaitObject = (PVOID)((PCHAR)Object + (ULONG_PTR)WaitObject);
  279. }
  280. //
  281. // Protect the wait call just in case KeWait decides to raise
  282. // For example, a mutant level is exceeded
  283. //
  284. try {
  285. PERFINFO_DECLARE_OBJECT(Object);
  286. Status = KeWaitForSingleObject( WaitObject,
  287. UserRequest,
  288. PreviousMode,
  289. Alertable,
  290. Timeout );
  291. } except((GetExceptionCode () == STATUS_MUTANT_LIMIT_EXCEEDED)?
  292. EXCEPTION_EXECUTE_HANDLER :
  293. EXCEPTION_CONTINUE_SEARCH) {
  294. Status = GetExceptionCode();
  295. }
  296. ObDereferenceObject(Object);
  297. }
  298. return Status;
  299. }
  300. NTSTATUS
  301. NtWaitForMultipleObjects (
  302. IN ULONG Count,
  303. IN HANDLE Handles[],
  304. IN WAIT_TYPE WaitType,
  305. IN BOOLEAN Alertable,
  306. IN PLARGE_INTEGER Timeout OPTIONAL
  307. )
  308. /*++
  309. Routine Description:
  310. This function waits until the specified objects attain a state of
  311. Signaled. The wait can be specified to wait until all of the objects
  312. attain a state of Signaled or until one of the objects attains a state
  313. of Signaled. An optional timeout can also be specified. If a timeout
  314. is not specified, then the wait will not be satisfied until the objects
  315. attain a state of Signaled. If a timeout is specified, and the objects
  316. have not attained a state of Signaled when the timeout expires, then
  317. the wait is automatically satisfied. If an explicit timeout value of
  318. zero is specified, then no wait will occur if the wait cannot be satisfied
  319. immediately. The wait can also be specified as alertable.
  320. Arguments:
  321. Count - Supplies a count of the number of objects that are to be waited
  322. on.
  323. Handles[] - Supplies an array of handles to wait objects.
  324. WaitType - Supplies the type of wait to perform (WaitAll, WaitAny).
  325. Alertable - Supplies a boolean value that specifies whether the wait is
  326. alertable.
  327. Timeout - Supplies a pointer to an optional absolute of relative time over
  328. which the wait is to occur.
  329. Return Value:
  330. The wait completion status. A value of STATUS_TIMEOUT is returned if a
  331. timeout occurred. The index of the object (zero based) in the object
  332. pointer array is returned if an object satisfied the wait. A value of
  333. STATUS_ALERTED is returned if the wait was aborted to deliver an alert
  334. to the current thread. A value of STATUS_USER_APC is returned if the
  335. wait was aborted to deliver a user APC to the current thread.
  336. --*/
  337. {
  338. HANDLE CapturedHandles[MAXIMUM_WAIT_OBJECTS];
  339. ULONG i;
  340. ULONG j;
  341. POBJECT_HEADER ObjectHeader;
  342. PVOID Objects[MAXIMUM_WAIT_OBJECTS];
  343. KPROCESSOR_MODE PreviousMode;
  344. ULONG RefCount;
  345. ULONG Size;
  346. NTSTATUS Status;
  347. LARGE_INTEGER TimeoutValue;
  348. PKWAIT_BLOCK WaitBlockArray;
  349. ACCESS_MASK GrantedAccess;
  350. PVOID WaitObjects[MAXIMUM_WAIT_OBJECTS];
  351. PHANDLE_TABLE HandleTable;
  352. PHANDLE_TABLE_ENTRY HandleEntry;
  353. BOOLEAN InCriticalRegion = FALSE;
  354. PETHREAD CurrentThread;
  355. PAGED_CODE();
  356. //
  357. // If the number of objects is zero or greater than the largest number
  358. // that can be waited on, then return and invalid parameter status.
  359. //
  360. if ((Count == 0) || (Count > MAXIMUM_WAIT_OBJECTS)) {
  361. return STATUS_INVALID_PARAMETER_1;
  362. }
  363. //
  364. // If the wait type is not wait any or wait all, then return an invalid
  365. // parameter status.
  366. //
  367. if ((WaitType != WaitAny) && (WaitType != WaitAll)) {
  368. return STATUS_INVALID_PARAMETER_3;
  369. }
  370. //
  371. // Get previous processor mode and probe and capture input arguments if
  372. // necessary.
  373. //
  374. PreviousMode = KeGetPreviousMode();
  375. try {
  376. if (PreviousMode != KernelMode) {
  377. if (ARGUMENT_PRESENT(Timeout)) {
  378. TimeoutValue = ProbeAndReadLargeInteger(Timeout);
  379. Timeout = &TimeoutValue;
  380. }
  381. ProbeForRead( Handles, Count * sizeof(HANDLE), sizeof(HANDLE) );
  382. }
  383. RtlCopyMemory (CapturedHandles, Handles, Count * sizeof(HANDLE));
  384. } except(EXCEPTION_EXECUTE_HANDLER) {
  385. return GetExceptionCode();
  386. }
  387. //
  388. // If the number of objects to be waited on is greater than the number
  389. // of builtin wait blocks, then allocate an array of wait blocks from
  390. // nonpaged pool. If the wait block array cannot be allocated, then
  391. // return insufficient resources.
  392. //
  393. WaitBlockArray = NULL;
  394. if (Count > THREAD_WAIT_OBJECTS) {
  395. Size = Count * sizeof( KWAIT_BLOCK );
  396. WaitBlockArray = ExAllocatePoolWithTag(NonPagedPool, Size, 'tiaW');
  397. if (WaitBlockArray == NULL) {
  398. return STATUS_INSUFFICIENT_RESOURCES;
  399. }
  400. }
  401. //
  402. // Loop through the array of handles and get a referenced pointer to
  403. // each object.
  404. //
  405. i = 0;
  406. RefCount = 0;
  407. Status = STATUS_SUCCESS;
  408. //
  409. // Protect ourselves from being interrupted while we hold a handle table
  410. // entry lock
  411. //
  412. CurrentThread = PsGetCurrentThread ();
  413. KeEnterCriticalRegionThread(&CurrentThread->Tcb);
  414. InCriticalRegion = TRUE;
  415. do {
  416. //
  417. // Get a pointer to the object table entry. Check if this is a kernel
  418. // handle and if so then use the kernel handle table otherwise use the
  419. // processes handle table. If we are going for a kernel handle we'll
  420. // need to attach to the kernel process otherwise we need to ensure
  421. // that we aren't attached.
  422. //
  423. if (IsKernelHandle( CapturedHandles[i], PreviousMode )) {
  424. HANDLE KernelHandle;
  425. //
  426. // Decode the user supplied handle into a regular handle value
  427. // and get its handle table entry
  428. //
  429. KernelHandle = DecodeKernelHandle( CapturedHandles[i] );
  430. HandleTable = ObpKernelHandleTable;
  431. HandleEntry = ExMapHandleToPointerEx ( HandleTable, KernelHandle, PreviousMode );
  432. } else {
  433. //
  434. // Get the handle table entry
  435. //
  436. HandleTable = PsGetCurrentProcessByThread (CurrentThread)->ObjectTable;
  437. HandleEntry = ExMapHandleToPointerEx ( HandleTable, CapturedHandles[ i ], PreviousMode );
  438. }
  439. //
  440. // Make sure the handle really did translate to a valid
  441. // entry
  442. //
  443. if (HandleEntry != NULL) {
  444. //
  445. // Get the granted access for the handle
  446. //
  447. #if i386
  448. if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
  449. GrantedAccess = ObpTranslateGrantedAccessIndex( HandleEntry->GrantedAccessIndex );
  450. } else {
  451. GrantedAccess = ObpDecodeGrantedAccess(HandleEntry->GrantedAccess);
  452. }
  453. #else
  454. GrantedAccess = ObpDecodeGrantedAccess(HandleEntry->GrantedAccess);
  455. #endif // i386
  456. //
  457. // Make sure the handle as synchronize access to the
  458. // object
  459. //
  460. if ((PreviousMode != KernelMode) &&
  461. (SeComputeDeniedAccesses( GrantedAccess, SYNCHRONIZE ) != 0)) {
  462. Status = STATUS_ACCESS_DENIED;
  463. ExUnlockHandleTableEntry( HandleTable, HandleEntry );
  464. goto ServiceFailed;
  465. } else {
  466. //
  467. // We have a object with proper access so get the header
  468. // and if the default objects points to a real object
  469. // then that is the one we're going to wait on.
  470. // Otherwise we'll find the kernel wait object at an
  471. // offset into the object body
  472. //
  473. ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(HandleEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES);
  474. if ((LONG_PTR)ObjectHeader->Type->DefaultObject < 0) {
  475. RefCount += 1;
  476. Objects[i] = NULL;
  477. WaitObjects[i] = ObjectHeader->Type->DefaultObject;
  478. } else {
  479. ObpIncrPointerCount( ObjectHeader );
  480. RefCount += 1;
  481. Objects[i] = &ObjectHeader->Body;
  482. PERFINFO_DECLARE_OBJECT(Objects[i]);
  483. //
  484. // Compute the address of the kernel wait object.
  485. //
  486. WaitObjects[i] = (PVOID)((PCHAR)&ObjectHeader->Body +
  487. (ULONG_PTR)ObjectHeader->Type->DefaultObject);
  488. }
  489. }
  490. ExUnlockHandleTableEntry( HandleTable, HandleEntry );
  491. } else {
  492. //
  493. // The entry in the handle table isn't in use
  494. //
  495. Status = STATUS_INVALID_HANDLE;
  496. goto ServiceFailed;
  497. }
  498. i += 1;
  499. } while (i < Count);
  500. //
  501. // At this point the WaitObjects[] is set to the kernel wait objects
  502. //
  503. // Now Check to determine if any of the objects are specified more than
  504. // once, but we only need to check this for wait all, with a wait any
  505. // the user can specify the same object multiple times.
  506. //
  507. if (WaitType == WaitAll) {
  508. i = 0;
  509. do {
  510. for (j = i + 1; j < Count; j += 1) {
  511. if (WaitObjects[i] == WaitObjects[j]) {
  512. Status = STATUS_INVALID_PARAMETER_MIX;
  513. goto ServiceFailed;
  514. }
  515. }
  516. i += 1;
  517. } while (i < Count);
  518. }
  519. //
  520. // Wait for the specified objects to attain a state of Signaled or a
  521. // time out to occur. Protect the wait call just in case KeWait decides
  522. // to raise For example, a mutant level is exceeded
  523. //
  524. try {
  525. InCriticalRegion = FALSE;
  526. KeLeaveCriticalRegionThread(&CurrentThread->Tcb);
  527. Status = KeWaitForMultipleObjects( Count,
  528. WaitObjects,
  529. WaitType,
  530. UserRequest,
  531. PreviousMode,
  532. Alertable,
  533. Timeout,
  534. WaitBlockArray );
  535. } except((GetExceptionCode () == STATUS_MUTANT_LIMIT_EXCEEDED)?
  536. EXCEPTION_EXECUTE_HANDLER :
  537. EXCEPTION_CONTINUE_SEARCH) {
  538. Status = GetExceptionCode();
  539. }
  540. //
  541. // If any objects were referenced, then deference them.
  542. //
  543. ServiceFailed:
  544. while (RefCount > 0) {
  545. RefCount -= 1;
  546. if (Objects[RefCount] != NULL) {
  547. ObDereferenceObject(Objects[RefCount]);
  548. }
  549. }
  550. //
  551. // If a wait block array was allocated, then deallocate it.
  552. //
  553. if (WaitBlockArray != NULL) {
  554. ExFreePool(WaitBlockArray);
  555. }
  556. if (InCriticalRegion) {
  557. KeLeaveCriticalRegionThread(&CurrentThread->Tcb);
  558. }
  559. return Status;
  560. }
  561. NTSTATUS
  562. ObWaitForSingleObject (
  563. IN HANDLE Handle,
  564. IN BOOLEAN Alertable,
  565. IN PLARGE_INTEGER Timeout OPTIONAL
  566. )
  567. /*++
  568. Routine Description:
  569. Please refer to NtWaitForSingleObject
  570. Arguments:
  571. Handle - Supplies the handle for the wait object.
  572. Alertable - Supplies a boolean value that specifies whether the wait
  573. is alertable.
  574. Timeout - Supplies an pointer to an absolute or relative time over
  575. which the wait is to occur.
  576. Return Value:
  577. The wait completion status. A value of STATUS_TIMEOUT is returned if a
  578. timeout occurred. A value of STATUS_SUCCESS is returned if the specified
  579. object satisfied the wait. A value of STATUS_ALERTED is returned if the
  580. wait was aborted to deliver an alert to the current thread. A value of
  581. STATUS_USER_APC is returned if the wait was aborted to deliver a user
  582. APC to the current thread.
  583. --*/
  584. {
  585. POBJECT_HEADER ObjectHeader;
  586. PVOID Object;
  587. NTSTATUS Status;
  588. PVOID WaitObject;
  589. PAGED_CODE();
  590. //
  591. // Get a referenced pointer to the specified object with synchronize
  592. // access.
  593. //
  594. Status = ObReferenceObjectByHandle( Handle,
  595. SYNCHRONIZE,
  596. (POBJECT_TYPE)NULL,
  597. KernelMode,
  598. &Object,
  599. NULL );
  600. //
  601. // If access is granted, then check to determine if the specified object
  602. // can be waited on.
  603. //
  604. if (NT_SUCCESS( Status ) != FALSE) {
  605. ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
  606. if ((LONG_PTR)ObjectHeader->Type->DefaultObject < 0) {
  607. WaitObject = (PVOID)ObjectHeader->Type->DefaultObject;
  608. } else {
  609. WaitObject = (PVOID)((PCHAR)Object + (ULONG_PTR)ObjectHeader->Type->DefaultObject);
  610. }
  611. //
  612. // Protect the wait call just in case KeWait decides
  613. // to raise For example, a mutant level is exceeded
  614. //
  615. try {
  616. Status = KeWaitForSingleObject( WaitObject,
  617. UserRequest,
  618. KernelMode,
  619. Alertable,
  620. Timeout );
  621. } except((GetExceptionCode () == STATUS_MUTANT_LIMIT_EXCEEDED)?
  622. EXCEPTION_EXECUTE_HANDLER :
  623. EXCEPTION_CONTINUE_SEARCH) {
  624. Status = GetExceptionCode();
  625. }
  626. ObDereferenceObject(Object);
  627. }
  628. return Status;
  629. }