test: obwait.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# obwait.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004 Copyright (c) 1992  Microsoft Corporation
    00005
    00006 Module Name:
    00007
    00008     obwait.c
    00009
    00010 Abstract:
    00011
    00012     This module implements the generic wait system services.
    00013
    00014 Author:
    00015
    00016     Steve Wood (stevewo) 12-May-1989
    00017
    00018 Revision History:
    00019
    00020 --*/
    00021
    00022 #include "obp.h"
    00023
    00024 #ifdef ALLOC_PRAGMA
    00025 #pragma alloc_text(PAGE, NtWaitForSingleObject)
    00026 #endif
    00027
    00028 //
    00029 //  We special case these three object types in the wait routine
    00030 //
    00031
    00032 extern POBJECT_TYPE ExEventObjectType;
    00033 extern POBJECT_TYPE ExMutantObjectType;
    00034 extern POBJECT_TYPE ExSemaphoreObjectType;
    00035
    00036
    00037 NTSTATUS
    00038 NtSignalAndWaitForSingleObject (
    00039     IN HANDLE SignalHandle,
    00040     IN HANDLE WaitHandle,
    00041     IN BOOLEAN Alertable,
    00042     IN PLARGE_INTEGER Timeout OPTIONAL
    00043     )
    00044
    00045 /*++
    00046
    00047 Routine Description:
    00048
    00049     This function atomically signals the specified signal object and then
    00050     waits until the specified wait object attains a state of Signaled.  An
    00051     optional timeout can also be specified.  If a timeout is not specified,
    00052     then the wait will not be satisfied until the wait object attains a
    00053     state of Signaled.  If a timeout is specified, and the wait object has
    00054     not attained a state of Signaled when the timeout expires, then the
    00055     wait is automatically satisfied.  If an explicit timeout value of zero
    00056     is specified, then no wait will occur if the wait cannot be satisfied
    00057     immediately.  The wait can also be specified as alertable.
    00058
    00059 Arguments:
    00060
    00061     SignalHandle - Supplies the handle of the signal object.
    00062
    00063     WaitHandle  - Supplies the handle for the wait object.
    00064
    00065     Alertable - Supplies a boolean value that specifies whether the wait
    00066         is alertable.
    00067
    00068     Timeout - Supplies an pointer to an absolute or relative time over
    00069         which the wait is to occur.
    00070
    00071 Return Value:
    00072
    00073     The wait completion status.  A value of STATUS_TIMEOUT is returned if a
    00074     timeout occurred.  A value of STATUS_SUCCESS is returned if the specified
    00075     object satisfied the wait.  A value of STATUS_ALERTED is returned if the
    00076     wait was aborted to deliver an alert to the current thread.  A value of
    00077     STATUS_USER_APC is returned if the wait was aborted to deliver a user
    00078     APC to the current thread.
    00079
    00080 --*/
    00081
    00082 {
    00083     OBJECT_HANDLE_INFORMATION HandleInformation;
    00084     KPROCESSOR_MODE PreviousMode;
    00085     PVOID RealObject;
    00086     PVOID SignalObject;
    00087     POBJECT_HEADER SignalObjectHeader;
    00088     NTSTATUS Status;
    00089     LARGE_INTEGER TimeoutValue;
    00090     PVOID WaitObject;
    00091     POBJECT_HEADER WaitObjectHeader;
    00092
    00093     //
    00094     //  Establish an exception handler and probe the specified timeout value
    00095     //  if necessary.  If the probe fails, then return the exception code as
    00096     //  the service status.
    00097     //
    00098
    00099     PreviousMode = KeGetPreviousMode();
    00100
    00101     if ((ARGUMENT_PRESENT(Timeout)) && (PreviousMode != KernelMode)) {
    00102
    00103         try {
    00104
    00105             TimeoutValue = ProbeAndReadLargeInteger(Timeout);
    00106             Timeout = &TimeoutValue;
    00107
    00108         } except(EXCEPTION_EXECUTE_HANDLER) {
    00109
    00110             return GetExceptionCode();
    00111         }
    00112     }
    00113
    00114     //
    00115     //  Reference the signal object by handle.
    00116     //
    00117
    00118     Status = ObReferenceObjectByHandle( SignalHandle,
    00119                                         0,
    00120                                         NULL,
    00121                                         PreviousMode,
    00122                                         &SignalObject,
    00123                                         &HandleInformation );
    00124
    00125     //
    00126     //  If the reference was successful, then reference the wait object by
    00127     //  handle.
    00128     //
    00129
    00130     if (NT_SUCCESS(Status)) {
    00131
    00132         Status = ObReferenceObjectByHandle( WaitHandle,
    00133                                             SYNCHRONIZE,
    00134                                             NULL,
    00135                                             PreviousMode,
    00136                                             &WaitObject,
    00137                                             NULL );
    00138
    00139         //
    00140         //  If the reference was successful, then determine the real wait
    00141         //  object, check the signal object access, signal the signal object,
    00142         //  and wait for the real wait object.
    00143         //
    00144
    00145         if (NT_SUCCESS(Status)) {
    00146
    00147             WaitObjectHeader = OBJECT_TO_OBJECT_HEADER(WaitObject);
    00148             RealObject = WaitObjectHeader->Type->DefaultObject;
    00149
    00150             if ((LONG_PTR)RealObject >= 0) {
    00151
    00152                 RealObject = (PVOID)((PCHAR)WaitObject + (ULONG_PTR)RealObject);
    00153             }
    00154
    00155             //
    00156             //  If the signal object is an event, then check for modify access
    00157             //  and set the event.  Otherwise, if the signal object is a
    00158             //  mutant, then attempt to release ownership of the mutant.
    00159             //  Otherwise, if the object is a semaphore, then check for modify
    00160             //  access and release the semaphore.  Otherwise, the signal objet
    00161             //  is invalid.
    00162             //
    00163
    00164             SignalObjectHeader = OBJECT_TO_OBJECT_HEADER(SignalObject);
    00165             Status = STATUS_ACCESS_DENIED;
    00166
    00167             if (SignalObjectHeader->Type == ExEventObjectType) {
    00168
    00169                 //
    00170                 //  Check for access to the specified event object,
    00171                 //
    00172
    00173                 if ((PreviousMode != KernelMode) &&
    00174                     (SeComputeDeniedAccesses( HandleInformation.GrantedAccess,
    00175                                               EVENT_MODIFY_STATE) != 0 )) {
    00176
    00177                     goto WaitExit;
    00178                 }
    00179
    00180                 //
    00181                 //  Set the specified event and wait atomically.
    00182                 //
    00183
    00184                 KeSetEvent((PKEVENT)SignalObject, EVENT_INCREMENT, TRUE);
    00185
    00186             } else if (SignalObjectHeader->Type == ExMutantObjectType) {
    00187
    00188                 //
    00189                 //  Release the specified mutant and wait atomically.
    00190                 //
    00191                 //  N.B. The release will only be successful if the current
    00192                 //       thread is the owner of the mutant.
    00193                 //
    00194
    00195                 try {
    00196
    00197                     KeReleaseMutant( (PKMUTANT)SignalObject,
    00198                                      MUTANT_INCREMENT,
    00199                                      FALSE,
    00200                                      TRUE );
    00201
    00202                 } except(EXCEPTION_EXECUTE_HANDLER) {
    00203
    00204                     Status = GetExceptionCode();
    00205
    00206                     goto WaitExit;
    00207                 }
    00208
    00209             } else if (SignalObjectHeader->Type == ExSemaphoreObjectType) {
    00210
    00211                 //
    00212                 //  Check for access to the specified semaphore object,
    00213                 //
    00214
    00215                 if ((PreviousMode != KernelMode) &&
    00216                     (SeComputeDeniedAccesses( HandleInformation.GrantedAccess,
    00217                                               SEMAPHORE_MODIFY_STATE) != 0 )) {
    00218
    00219                     goto WaitExit;
    00220                 }
    00221
    00222                 //
    00223                 //  Release the specified semaphore and wait atomically.
    00224                 //
    00225
    00226                 try {
    00227
    00228                     //
    00229                     //  Release the specified semaphore and wait atomically.
    00230                     //
    00231
    00232                     KeReleaseSemaphore( (PKSEMAPHORE)SignalObject,
    00233                                         SEMAPHORE_INCREMENT,
    00234                                         1,
    00235                                         TRUE );
    00236
    00237                 } except(EXCEPTION_EXECUTE_HANDLER) {
    00238
    00239                     Status = GetExceptionCode();
    00240
    00241                     goto WaitExit;
    00242                 }
    00243
    00244             } else {
    00245
    00246                 Status = STATUS_OBJECT_TYPE_MISMATCH;
    00247
    00248                 goto WaitExit;
    00249             }
    00250
    00251             //
    00252             //  Protect the wait call just in case KeWait decides to raise
    00253             //  For example, a mutant level is exceeded
    00254             //
    00255
    00256             try {
    00257
    00258                 Status = KeWaitForSingleObject( RealObject,
    00259                                                 UserRequest,
    00260                                                 PreviousMode,
    00261                                                 Alertable,
    00262                                                 Timeout );
    00263
    00264             } except(EXCEPTION_EXECUTE_HANDLER) {
    00265
    00266                 Status = GetExceptionCode();
    00267             }
    00268
    00269 WaitExit:
    00270
    00271             ObDereferenceObject(WaitObject);
    00272         }
    00273
    00274         ObDereferenceObject(SignalObject);
    00275     }
    00276
    00277     return Status;
    00278 }
    00279
    00280
    00281 NTSTATUS
    00282 NtWaitForSingleObject (
    00283     IN HANDLE Handle,
    00284     IN BOOLEAN Alertable,
    00285     IN PLARGE_INTEGER Timeout OPTIONAL
    00286     )
    00287
    00288 /*++
    00289
    00290 Routine Description:
    00291
    00292     This function waits until the specified object attains a state of
    00293     Signaled.  An optional timeout can also be specified.  If a timeout
    00294     is not specified, then the wait will not be satisfied until the
    00295     object attains a state of Signaled.  If a timeout is specified, and
    00296     the object has not attained a state of Signaled when the timeout
    00297     expires, then the wait is automatically satisfied.  If an explicit
    00298     timeout value of zero is specified, then no wait will occur if the
    00299     wait cannot be satisfied immediately.  The wait can also be specified
    00300     as alertable.
    00301
    00302 Arguments:
    00303
    00304     Handle  - Supplies the handle for the wait object.
    00305
    00306     Alertable - Supplies a boolean value that specifies whether the wait
    00307         is alertable.
    00308
    00309     Timeout - Supplies an pointer to an absolute or relative time over
    00310         which the wait is to occur.
    00311
    00312 Return Value:
    00313
    00314     The wait completion status. A value of STATUS_TIMEOUT is returned if a
    00315     timeout occurred.  A value of STATUS_SUCCESS is returned if the specified
    00316     object satisfied the wait.  A value of STATUS_ALERTED is returned if the
    00317     wait was aborted to deliver an alert to the current thread. A value of
    00318     STATUS_USER_APC is returned if the wait was aborted to deliver a user
    00319     APC to the current thread.
    00320
    00321 --*/
    00322
    00323 {
    00324     PVOID Object;
    00325     POBJECT_HEADER ObjectHeader;
    00326     KPROCESSOR_MODE PreviousMode;
    00327     NTSTATUS Status;
    00328     LARGE_INTEGER TimeoutValue;
    00329     PVOID WaitObject;
    00330
    00331     PAGED_CODE();
    00332
    00333     //
    00334     //  Get previous processor mode and probe and capture timeout argument
    00335     //  if necessary.
    00336     //
    00337
    00338     PreviousMode = KeGetPreviousMode();
    00339
    00340     if ((ARGUMENT_PRESENT(Timeout)) && (PreviousMode != KernelMode)) {
    00341
    00342         try {
    00343
    00344             TimeoutValue = ProbeAndReadLargeInteger(Timeout);
    00345             Timeout = &TimeoutValue;
    00346
    00347         } except(EXCEPTION_EXECUTE_HANDLER) {
    00348
    00349             return GetExceptionCode();
    00350         }
    00351     }
    00352
    00353     //
    00354     //  Get a referenced pointer to the specified object with synchronize
    00355     //  access.
    00356     //
    00357
    00358     Status = ObReferenceObjectByHandle( Handle,
    00359                                         SYNCHRONIZE,
    00360                                         NULL,
    00361                                         PreviousMode,
    00362                                         &Object,
    00363                                         NULL );
    00364
    00365     //
    00366     //  If access is granted, then check to determine if the specified object
    00367     //  can be waited on.
    00368     //
    00369
    00370     if (NT_SUCCESS(Status)) {
    00371
    00372         ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    00373         WaitObject = ObjectHeader->Type->DefaultObject;
    00374
    00375         if ((LONG_PTR)WaitObject >= 0) {
    00376
    00377             WaitObject = (PVOID)((PCHAR)Object + (ULONG_PTR)WaitObject);
    00378         }
    00379
    00380         //
    00381         //  Protect the wait call just in case KeWait decides to raise
    00382         //  For example, a mutant level is exceeded
    00383         //
    00384
    00385         try {
    00386
    00387             Status = KeWaitForSingleObject( WaitObject,
    00388                                             UserRequest,
    00389                                             PreviousMode,
    00390                                             Alertable,
    00391                                             Timeout );
    00392
    00393         } except(EXCEPTION_EXECUTE_HANDLER) {
    00394
    00395             Status = GetExceptionCode();
    00396         }
    00397
    00398         ObDereferenceObject(Object);
    00399     }
    00400
    00401     return Status;
    00402 }
    00403
    00404
    00405 NTSTATUS
    00406 NtWaitForMultipleObjects (
    00407     IN ULONG Count,
    00408     IN HANDLE Handles[],
    00409     IN WAIT_TYPE WaitType,
    00410     IN BOOLEAN Alertable,
    00411     IN PLARGE_INTEGER Timeout OPTIONAL
    00412     )
    00413
    00414 /*++
    00415
    00416 Routine Description:
    00417
    00418     This function waits until the specified objects attain a state of
    00419     Signaled.  The wait can be specified to wait until all of the objects
    00420     attain a state of Signaled or until one of the objects attains a state
    00421     of Signaled.  An optional timeout can also be specified.  If a timeout
    00422     is not specified, then the wait will not be satisfied until the objects
    00423     attain a state of Signaled.  If a timeout is specified, and the objects
    00424     have not attained a state of Signaled when the timeout expires, then
    00425     the wait is automatically satisfied.  If an explicit timeout value of
    00426     zero is specified, then no wait will occur if the wait cannot be satisfied
    00427     immediately.  The wait can also be specified as alertable.
    00428
    00429 Arguments:
    00430
    00431     Count - Supplies a count of the number of objects that are to be waited
    00432         on.
    00433
    00434     Handles[] - Supplies an array of handles to wait objects.
    00435
    00436     WaitType - Supplies the type of wait to perform (WaitAll, WaitAny).
    00437
    00438     Alertable - Supplies a boolean value that specifies whether the wait is
    00439         alertable.
    00440
    00441     Timeout - Supplies a pointer to an optional absolute of relative time over
    00442         which the wait is to occur.
    00443
    00444 Return Value:
    00445
    00446     The wait completion status.  A value of STATUS_TIMEOUT is returned if a
    00447     timeout occurred.  The index of the object (zero based) in the object
    00448     pointer array is returned if an object satisfied the wait.  A value of
    00449     STATUS_ALERTED is returned if the wait was aborted to deliver an alert
    00450     to the current thread.  A value of STATUS_USER_APC is returned if the
    00451     wait was aborted to deliver a user APC to the current thread.
    00452
    00453 --*/
    00454
    00455 {
    00456     HANDLE CapturedHandles[MAXIMUM_WAIT_OBJECTS];
    00457     ULONG i;
    00458     ULONG j;
    00459     POBJECT_HEADER ObjectHeader;
    00460     PVOID Objects[MAXIMUM_WAIT_OBJECTS];
    00461     KPROCESSOR_MODE PreviousMode;
    00462     ULONG RefCount;
    00463     ULONG Size;
    00464     NTSTATUS Status;
    00465     LARGE_INTEGER TimeoutValue;
    00466     PKWAIT_BLOCK WaitBlockArray;
    00467     ACCESS_MASK GrantedAccess;
    00468     PVOID WaitObjects[MAXIMUM_WAIT_OBJECTS];
    00469     PHANDLE_TABLE HandleTable;
    00470     PHANDLE_TABLE_ENTRY HandleEntry;
    00471     BOOLEAN AttachedToProcess = FALSE;
    00472     BOOLEAN InCriticalRegion = FALSE;
    00473     KAPC_STATE ApcState;
    00474
    00475     PAGED_CODE();
    00476
    00477     //
    00478     //  Protect ourselves from being interrupted while we hold a handle table
    00479     //  entry lock
    00480     //
    00481
    00482     KeEnterCriticalRegion();
    00483     InCriticalRegion = TRUE;
    00484
    00485     try {
    00486
    00487         //
    00488         //  If the number of objects is zero or greater than the largest number
    00489         //  that can be waited on, then return and invalid parameter status.
    00490         //
    00491
    00492         if ((Count == 0) || (Count > MAXIMUM_WAIT_OBJECTS)) {
    00493
    00494             Status = STATUS_INVALID_PARAMETER_1;
    00495             leave;
    00496         }
    00497
    00498         //
    00499         //  If the wait type is not wait any or wait all, then return an invalid
    00500         //  parameter status.
    00501         //
    00502
    00503         if ((WaitType != WaitAny) && (WaitType != WaitAll)) {
    00504
    00505             Status = STATUS_INVALID_PARAMETER_3;
    00506             leave;
    00507         }
    00508
    00509         //
    00510         //  Get previous processor mode and probe and capture input arguments if
    00511         //  necessary.
    00512         //
    00513
    00514         PreviousMode = KeGetPreviousMode();
    00515
    00516         try {
    00517
    00518             if (PreviousMode != KernelMode) {
    00519
    00520                 if (ARGUMENT_PRESENT(Timeout)) {
    00521
    00522                     TimeoutValue = ProbeAndReadLargeInteger(Timeout);
    00523                     Timeout = &TimeoutValue;
    00524                 }
    00525
    00526                 ProbeForRead( Handles, Count * sizeof(HANDLE), sizeof(HANDLE) );
    00527             }
    00528
    00529             i= 0;
    00530
    00531             do {
    00532
    00533                 CapturedHandles[i] = Handles[i];
    00534                 i += 1;
    00535
    00536             } while (i < Count);
    00537
    00538         } except(EXCEPTION_EXECUTE_HANDLER) {
    00539
    00540             Status = GetExceptionCode();
    00541             leave;
    00542         }
    00543
    00544         //
    00545         //  If the number of objects to be waited on is greater than the number
    00546         //  of builtin wait blocks, then allocate an array of wait blocks from
    00547         //  nonpaged pool. If the wait block array cannot be allocated, then
    00548         //  return insufficient resources.
    00549         //
    00550
    00551         WaitBlockArray = NULL;
    00552
    00553         if (Count > THREAD_WAIT_OBJECTS) {
    00554
    00555             Size = Count * sizeof( KWAIT_BLOCK );
    00556             WaitBlockArray = ExAllocatePoolWithTag(NonPagedPool, Size, 'tiaW');
    00557
    00558             if (WaitBlockArray == NULL) {
    00559
    00560                 Status = STATUS_INSUFFICIENT_RESOURCES;
    00561                 leave;
    00562             }
    00563         }
    00564
    00565         //
    00566         //  Loop through the array of handles and get a referenced pointer to
    00567         //  each object.
    00568         //
    00569
    00570         i = 0;
    00571         RefCount = 0;
    00572
    00573         Status = STATUS_SUCCESS;
    00574
    00575         do {
    00576
    00577     #if DBG
    00578             //
    00579             //  On checked builds, check that if the Kernel handle bit is set,
    00580             //  then we're coming from Kernel mode.  We should probably fail the
    00581             //  call if bit set && !Kmode
    00582             //
    00583
    00584             if ((CapturedHandles[i] != NtCurrentThread()) &&
    00585                 (CapturedHandles[i] != NtCurrentProcess())) {
    00586
    00587                 ASSERT((CapturedHandles[i] < 0) ? (PreviousMode == KernelMode) : TRUE);
    00588             }
    00589     #endif
    00590
    00591             //
    00592             //  Get a pointer to the object table entry.  Check if this is a kernel
    00593             //  handle and if so then use the kernel handle table otherwise use the
    00594             //  processes handle table.  If we are going for a kernel handle we'll
    00595             //  need to attach to the kernel process otherwise we need to ensure
    00596             //  that we aren't attached.
    00597             //
    00598
    00599             if (IsKernelHandle( CapturedHandles[i], PreviousMode )) {
    00600
    00601                 HANDLE KernelHandle;
    00602
    00603                 //
    00604                 //  If we aren't already attached to the system process do so now
    00605                 //  and remember that we are
    00606                 //
    00607
    00608                 if (PsGetCurrentProcess() != PsInitialSystemProcess) {
    00609                     KeStackAttachProcess (&PsInitialSystemProcess->Pcb, &ApcState);
    00610                     AttachedToProcess = TRUE;
    00611                 }
    00612
    00613                 //
    00614                 //  Decode the user supplied handle into a regular handle value
    00615                 //  and get its handle table entry
    00616                 //
    00617
    00618                 KernelHandle = DecodeKernelHandle( CapturedHandles[i] );
    00619
    00620                 HandleTable = ObpKernelHandleTable;
    00621                 HandleEntry = ExMapHandleToPointer( HandleTable, KernelHandle );
    00622
    00623             } else {
    00624
    00625                 //
    00626                 //  If we are attached to the system process then go back to the
    00627                 //  original callers process
    00628                 //
    00629
    00630                 if (AttachedToProcess) {
    00631                     KeUnstackDetachProcess(&ApcState);
    00632                     AttachedToProcess = FALSE;
    00633                 }
    00634
    00635                 //
    00636                 //  Get the handle table entry
    00637                 //
    00638
    00639                 HandleTable = ObpGetObjectTable();
    00640                 HandleEntry = ExMapHandleToPointer( HandleTable, CapturedHandles[ i ] );
    00641             }
    00642
    00643             //
    00644             //  Make sure the handle really did translate to a valid
    00645             //  entry
    00646             //
    00647
    00648             if (HandleEntry != NULL) {
    00649
    00650                 //
    00651                 //  Get the granted access for the handle
    00652                 //
    00653
    00654     #if i386 && !FPO
    00655
    00656                 if (NtGlobalFlag & FLG_KERNEL_STACK_TRACE_DB) {
    00657
    00658                     if (PreviousMode != KernelMode) {
    00659
    00660                         GrantedAccess = ObpTranslateGrantedAccessIndex( HandleEntry->GrantedAccessIndex );
    00661                     }
    00662
    00663                 } else {
    00664
    00665                     GrantedAccess = HandleEntry->GrantedAccess;
    00666                 }
    00667
    00668     #else
    00669                 GrantedAccess = HandleEntry->GrantedAccess;
    00670
    00671     #endif // i386 && !FPO
    00672
    00673                 //
    00674                 //  Make sure the handle as synchronize access to the
    00675                 //  object
    00676                 //
    00677
    00678                 if ((PreviousMode != KernelMode) &&
    00679                     (SeComputeDeniedAccesses( GrantedAccess, SYNCHRONIZE ) != 0)) {
    00680
    00681                     Status = STATUS_ACCESS_DENIED;
    00682
    00683                     ExUnlockHandleTableEntry( HandleTable, HandleEntry );
    00684
    00685                     goto ServiceFailed;
    00686
    00687                 } else {
    00688
    00689                     //
    00690                     //  We have a object with proper access so get the header
    00691                     //  and if the default objects points to a real object
    00692                     //  then that is the one we're going to wait on.
    00693                     //  Otherwise we'll find the kernel wait object at an
    00694                     //  offset into the object body
    00695                     //
    00696
    00697                     ObjectHeader = (POBJECT_HEADER)(((ULONG_PTR)(HandleEntry->Object)) & ~OBJ_HANDLE_ATTRIBUTES);
    00698
    00699                     if ((LONG_PTR)ObjectHeader->Type->DefaultObject < 0) {
    00700
    00701                         RefCount += 1;
    00702                         Objects[i] = NULL;
    00703                         WaitObjects[i] = ObjectHeader->Type->DefaultObject;
    00704
    00705                     } else {
    00706
    00707                         ObpIncrPointerCount( ObjectHeader );
    00708                         RefCount += 1;
    00709                         Objects[i] = &ObjectHeader->Body;
    00710
    00711                         //
    00712                         //  Compute the address of the kernel wait object.
    00713                         //
    00714
    00715                         WaitObjects[i] = (PVOID)((PCHAR)&ObjectHeader->Body +
    00716                                                  (ULONG_PTR)ObjectHeader->Type->DefaultObject);
    00717                     }
    00718                 }
    00719
    00720                 ExUnlockHandleTableEntry( HandleTable, HandleEntry );
    00721
    00722             } else {
    00723
    00724                 //
    00725                 //  The entry in the handle table isn't in use
    00726                 //
    00727
    00728                 Status = STATUS_INVALID_HANDLE;
    00729
    00730                 goto ServiceFailed;
    00731             }
    00732
    00733             i += 1;
    00734
    00735         } while (i < Count);
    00736
    00737         //
    00738         //  At this point the WaitObjects[] is set to the kernel wait objects
    00739         //
    00740         //  Now Check to determine if any of the objects are specified more than
    00741         //  once, but we only need to check this for wait all, with a wait any
    00742         //  the user can specify the same object multiple times.
    00743         //
    00744
    00745         if (WaitType == WaitAll) {
    00746
    00747             i = 0;
    00748
    00749             do {
    00750
    00751                 for (j = i + 1; j < Count; j += 1) {
    00752
    00753                     if (WaitObjects[i] == WaitObjects[j]) {
    00754
    00755                         Status = STATUS_INVALID_PARAMETER_MIX;
    00756
    00757                         goto ServiceFailed;
    00758                     }
    00759                 }
    00760
    00761                 i += 1;
    00762
    00763             } while (i < Count);
    00764         }
    00765
    00766         //
    00767         //  Wait for the specified objects to attain a state of Signaled or a
    00768         //  time out to occur.  Protect the wait call just in case KeWait decides
    00769         //  to raise For example, a mutant level is exceeded
    00770         //
    00771
    00772         try {
    00773
    00774             InCriticalRegion = FALSE;
    00775             KeLeaveCriticalRegion();
    00776             Status = KeWaitForMultipleObjects( Count,
    00777                                                WaitObjects,
    00778                                                WaitType,
    00779                                                UserRequest,
    00780                                                PreviousMode,
    00781                                                Alertable,
    00782                                                Timeout,
    00783                                                WaitBlockArray );
    00784
    00785         } except(EXCEPTION_EXECUTE_HANDLER) {
    00786
    00787             Status = GetExceptionCode();
    00788         }
    00789
    00790         //
    00791         //  If any objects were referenced, then deference them.
    00792         //
    00793
    00794     ServiceFailed:
    00795
    00796         while (RefCount > 0) {
    00797
    00798             RefCount -= 1;
    00799
    00800             if (Objects[RefCount] != NULL) {
    00801
    00802                 ObDereferenceObject(Objects[RefCount]);
    00803             }
    00804         }
    00805
    00806         //
    00807         //  If are attached to the system process then return back to our callers
    00808         //  process
    00809
    00810         if (AttachedToProcess) {
    00811             KeUnstackDetachProcess(&ApcState);
    00812             AttachedToProcess = FALSE;
    00813         }
    00814
    00815         //
    00816         //  If a wait block array was allocated, then deallocate it.
    00817         //
    00818
    00819         if (WaitBlockArray != NULL) {
    00820
    00821             ExFreePool(WaitBlockArray);
    00822         }
    00823
    00824     } finally {
    00825
    00826         if ( InCriticalRegion ) {
    00827
    00828             KeLeaveCriticalRegion();
    00829         }
    00830     }
    00831
    00832     return Status;
    00833 }
    00834
    00835
    00836 NTSTATUS
    00837 ObWaitForSingleObject (
    00838     IN HANDLE Handle,
    00839     IN BOOLEAN Alertable,
    00840     IN PLARGE_INTEGER Timeout OPTIONAL
    00841     )
    00842
    00843 /*++
    00844
    00845 Routine Description:
    00846
    00847     Please refer to NtWaitForSingleObject
    00848
    00849 Arguments:
    00850
    00851     Handle  - Supplies the handle for the wait object.
    00852
    00853     Alertable - Supplies a boolean value that specifies whether the wait
    00854         is alertable.
    00855
    00856     Timeout - Supplies an pointer to an absolute or relative time over
    00857         which the wait is to occur.
    00858
    00859 Return Value:
    00860
    00861     The wait completion status. A value of STATUS_TIMEOUT is returned if a
    00862     timeout occurred.  A value of STATUS_SUCCESS is returned if the specified
    00863     object satisfied the wait.  A value of STATUS_ALERTED is returned if the
    00864     wait was aborted to deliver an alert to the current thread. A value of
    00865     STATUS_USER_APC is returned if the wait was aborted to deliver a user
    00866     APC to the current thread.
    00867
    00868 --*/
    00869
    00870 {
    00871     POBJECT_HEADER ObjectHeader;
    00872     PVOID Object;
    00873     NTSTATUS Status;
    00874     PVOID WaitObject;
    00875
    00876     PAGED_CODE();
    00877
    00878     //
    00879     //  Get a referenced pointer to the specified object with synchronize
    00880     //  access.
    00881     //
    00882
    00883     Status = ObReferenceObjectByHandle( Handle,
    00884                                         SYNCHRONIZE,
    00885                                         (POBJECT_TYPE)NULL,
    00886                                         KernelMode,
    00887                                         &Object,
    00888                                         NULL );
    00889
    00890     //
    00891     //  If access is granted, then check to determine if the specified object
    00892     //  can be waited on.
    00893     //
    00894
    00895     if (NT_SUCCESS( Status ) != FALSE) {
    00896
    00897         ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    00898
    00899         if ((LONG_PTR)ObjectHeader->Type->DefaultObject < 0) {
    00900
    00901             WaitObject = (PVOID)ObjectHeader->Type->DefaultObject;
    00902
    00903         } else {
    00904
    00905             WaitObject = (PVOID)((PCHAR)Object + (ULONG_PTR)ObjectHeader->Type->DefaultObject);
    00906         }
    00907
    00908         //
    00909         //  Protect the wait call just in case KeWait decides
    00910         //  to raise For example, a mutant level is exceeded
    00911         //
    00912
    00913         try {
    00914
    00915             Status = KeWaitForSingleObject( WaitObject,
    00916                                             UserRequest,
    00917                                             KernelMode,
    00918                                             Alertable,
    00919                                             Timeout );
    00920
    00921         } except(EXCEPTION_EXECUTE_HANDLER) {
    00922
    00923             Status = GetExceptionCode();
    00924         }
    00925
    00926         ObDereferenceObject(Object);
    00927     }
    00928
    00929     return Status;
    00930 }