ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

obwait.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            ntoskrnl/ob/obwait.c
00005  * PURPOSE:         Handles Waiting on Objects
00006  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
00007  *                  Thomas Weidenmueller (w3seek@reactos.org)
00008  */
00009 
00010 /* INCLUDES ******************************************************************/
00011 
00012 #include <ntoskrnl.h>
00013 #define NDEBUG
00014 #include <debug.h>
00015 
00016 /* FUNCTIONS *****************************************************************/
00017 
00018 /*++
00019 * @name NtWaitForMultipleObjects
00020 * @implemented NT4
00021 *
00022 *     The NtWaitForMultipleObjects routine <FILLMEIN>
00023 *
00024 * @param ObjectCount
00025 *        <FILLMEIN>
00026 *
00027 * @param HandleArray
00028 *        <FILLMEIN>
00029 *
00030 * @param WaitType
00031 *        <FILLMEIN>
00032 *
00033 * @param Alertable
00034 *        <FILLMEIN>
00035 *
00036 * @param TimeOut
00037 *        <FILLMEIN>
00038 *
00039 * @return STATUS_SUCCESS or appropriate error value.
00040 *
00041 * @remarks None.
00042 *
00043 *--*/
00044 NTSTATUS
00045 NTAPI
00046 NtWaitForMultipleObjects(IN ULONG ObjectCount,
00047                          IN PHANDLE HandleArray,
00048                          IN WAIT_TYPE WaitType,
00049                          IN BOOLEAN Alertable,
00050                          IN PLARGE_INTEGER TimeOut OPTIONAL)
00051 {
00052     PKWAIT_BLOCK WaitBlockArray = NULL;
00053     HANDLE Handles[MAXIMUM_WAIT_OBJECTS], KernelHandle;
00054     PVOID Objects[MAXIMUM_WAIT_OBJECTS];
00055     PVOID WaitObjects[MAXIMUM_WAIT_OBJECTS];
00056     ULONG i = 0, ReferencedObjects = 0, j;
00057     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00058     LARGE_INTEGER SafeTimeOut;
00059     BOOLEAN LockInUse;
00060     PHANDLE_TABLE_ENTRY HandleEntry;
00061     POBJECT_HEADER ObjectHeader;
00062     PHANDLE_TABLE HandleTable;
00063     ACCESS_MASK GrantedAccess;
00064     PVOID DefaultObject;
00065     NTSTATUS Status;
00066     PAGED_CODE();
00067 
00068     /* Enter a critical region since we'll play with handles */
00069     LockInUse = TRUE;
00070     KeEnterCriticalRegion();
00071 
00072     /* Check for valid Object Count */
00073     if ((ObjectCount > MAXIMUM_WAIT_OBJECTS) || !(ObjectCount))
00074     {
00075         /* Fail */
00076         Status = STATUS_INVALID_PARAMETER_1;
00077         goto Quickie;
00078     }
00079 
00080     /* Check for valid Wait Type */
00081     if ((WaitType != WaitAll) && (WaitType != WaitAny))
00082     {
00083         /* Fail */
00084         Status = STATUS_INVALID_PARAMETER_3;
00085         goto Quickie;
00086     }
00087 
00088     /* Enter SEH */
00089     _SEH2_TRY
00090     {
00091         /* Check if the call came from user mode */
00092         if (PreviousMode != KernelMode)
00093         {
00094             /* Check if we have a timeout */
00095             if (TimeOut)
00096             {
00097                 /* Make a local copy of the timeout on the stack */
00098                 SafeTimeOut = ProbeForReadLargeInteger(TimeOut);
00099                 TimeOut = &SafeTimeOut;
00100             }
00101 
00102             /* Probe all the handles */
00103             ProbeForRead(HandleArray,
00104                          ObjectCount * sizeof(HANDLE),
00105                          sizeof(HANDLE));
00106         }
00107 
00108        /*
00109         * Make a copy so we don't have to guard with SEH later and keep
00110         * track of what objects we referenced if dereferencing pointers
00111         * suddenly fails
00112         */
00113         RtlCopyMemory(Handles,
00114                       HandleArray,
00115                       ObjectCount * sizeof(HANDLE));
00116     }
00117     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00118     {
00119         /* Return the exception code */
00120         Status = _SEH2_GetExceptionCode();
00121         _SEH2_YIELD(goto Quickie);
00122     }
00123     _SEH2_END;
00124 
00125     /* Check if we can use the internal Wait Array */
00126     if (ObjectCount > THREAD_WAIT_OBJECTS)
00127     {
00128         /* Allocate from Pool */
00129         WaitBlockArray = ExAllocatePoolWithTag(NonPagedPool,
00130                                                ObjectCount *
00131                                                sizeof(KWAIT_BLOCK),
00132                                                TAG_WAIT);
00133         if (!WaitBlockArray)
00134         {
00135             /* Fail */
00136             Status = STATUS_INSUFFICIENT_RESOURCES;
00137             goto Quickie;
00138         }
00139     }
00140 
00141     /* Start the loop */
00142     do
00143     {
00144         /* Use the right Executive Handle */
00145         if (ObIsKernelHandle(Handles[i], PreviousMode))
00146         {
00147             /* Use the System Handle Table and decode */
00148             HandleTable = ObpKernelHandleTable;
00149             KernelHandle = ObKernelHandleToHandle(Handles[i]);
00150 
00151             /* Get a pointer to it */
00152             HandleEntry = ExMapHandleToPointer(HandleTable, KernelHandle);
00153         }
00154         else
00155         {
00156             /* Use the Process' Handle table and get the Ex Handle */
00157             HandleTable = PsGetCurrentProcess()->ObjectTable;
00158 
00159             /* Get a pointer to it */
00160             HandleEntry = ExMapHandleToPointer(HandleTable, Handles[i]);
00161         }
00162 
00163         /* Check if we have an entry */
00164         if (!HandleEntry)
00165         {
00166             /* Fail, handle is invalid */
00167             Status = STATUS_INVALID_HANDLE;
00168             goto Quickie;
00169         }
00170 
00171         /* Check for synchronize access */
00172         GrantedAccess = HandleEntry->GrantedAccess;
00173         if ((PreviousMode != KernelMode) && (!(GrantedAccess & SYNCHRONIZE)))
00174         {
00175             /* Unlock the entry and fail */
00176             ExUnlockHandleTableEntry(HandleTable, HandleEntry);
00177             Status = STATUS_ACCESS_DENIED;
00178             goto Quickie;
00179         }
00180 
00181         /* Get the Object Header */
00182         ObjectHeader = ObpGetHandleObject(HandleEntry);
00183 
00184         /* Get default Object */
00185         DefaultObject = ObjectHeader->Type->DefaultObject;
00186 
00187         /* Check if it's the internal offset */
00188         if (IsPointerOffset(DefaultObject))
00189         {
00190             /* Increase reference count */
00191             InterlockedIncrement(&ObjectHeader->PointerCount);
00192             ReferencedObjects++;
00193 
00194             /* Save the Object and Wait Object, this is a relative offset */
00195             Objects[i] = &ObjectHeader->Body;
00196             WaitObjects[i] = (PVOID)((ULONG_PTR)&ObjectHeader->Body +
00197                                      (ULONG_PTR)DefaultObject);
00198         }
00199         else
00200         {
00201             /* This is our internal Object */
00202             ReferencedObjects++;
00203             Objects[i] = NULL;
00204             WaitObjects[i] = DefaultObject;
00205         }
00206 
00207         /* Unlock the Handle Table Entry */
00208         ExUnlockHandleTableEntry(HandleTable, HandleEntry);
00209 
00210         /* Keep looping */
00211         i++;
00212     } while (i < ObjectCount);
00213 
00214     /* For a Waitall, we can't have the same object more then once */
00215     if (WaitType == WaitAll)
00216     {
00217         /* Clear the main loop variable */
00218         i = 0;
00219 
00220         /* Start the loop */
00221         do
00222         {
00223             /* Check the current and forward object */
00224             for (j = i + 1; j < ObjectCount; j++)
00225             {
00226                 /* Make sure they don't match */
00227                 if (WaitObjects[i] == WaitObjects[j])
00228                 {
00229                     /* Fail */
00230                     Status = STATUS_INVALID_PARAMETER_MIX;
00231                     goto Quickie;
00232                 }
00233             }
00234 
00235             /* Keep looping */
00236             i++;
00237         } while (i < ObjectCount);
00238     }
00239 
00240     /* Now we can finally wait. Use SEH since it can raise an exception */
00241     _SEH2_TRY
00242     {
00243         /* We're done playing with handles */
00244         LockInUse = FALSE;
00245         KeLeaveCriticalRegion();
00246 
00247         /* Do the kernel wait */
00248         Status = KeWaitForMultipleObjects(ObjectCount,
00249                                           WaitObjects,
00250                                           WaitType,
00251                                           UserRequest,
00252                                           PreviousMode,
00253                                           Alertable,
00254                                           TimeOut,
00255                                           WaitBlockArray);
00256     }
00257     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00258     {
00259         /* Get the exception code */
00260         Status = _SEH2_GetExceptionCode();
00261     }
00262     _SEH2_END;
00263 
00264 Quickie:
00265     /* First derefence */
00266     while (ReferencedObjects)
00267     {
00268         /* Decrease the number of objects */
00269         ReferencedObjects--;
00270 
00271         /* Check if we had a valid object in this position */
00272         if (Objects[ReferencedObjects])
00273         {
00274             /* Dereference it */
00275             ObDereferenceObject(Objects[ReferencedObjects]);
00276         }
00277     }
00278 
00279     /* Free wait block array */
00280     if (WaitBlockArray) ExFreePoolWithTag(WaitBlockArray, TAG_WAIT);
00281 
00282     /* Re-enable APCs if needed */
00283     if (LockInUse) KeLeaveCriticalRegion();
00284 
00285     /* Return status */
00286     return Status;
00287 }
00288 
00289 /*++
00290 * @name NtWaitForMultipleObjects32
00291 * @implemented NT5.1
00292 *
00293 *     The NtWaitForMultipleObjects32 routine <FILLMEIN>
00294 *
00295 * @param ObjectCount
00296 *        <FILLMEIN>
00297 *
00298 * @param HandleArray
00299 *        <FILLMEIN>
00300 *
00301 * @param WaitType
00302 *        <FILLMEIN>
00303 *
00304 * @param Alertable
00305 *        <FILLMEIN>
00306 *
00307 * @param TimeOut
00308 *        <FILLMEIN>
00309 *
00310 * @return STATUS_SUCCESS or appropriate error value.
00311 *
00312 * @remarks None.
00313 *
00314 *--*/
00315 NTSTATUS
00316 NTAPI
00317 NtWaitForMultipleObjects32(IN ULONG ObjectCount,
00318                            IN PLONG Handles,
00319                            IN WAIT_TYPE WaitType,
00320                            IN BOOLEAN Alertable,
00321                            IN PLARGE_INTEGER TimeOut OPTIONAL)
00322 {
00323     /* FIXME WOW64 */
00324     return NtWaitForMultipleObjects(ObjectCount,
00325                                     (PHANDLE)Handles,
00326                                     WaitType,
00327                                     Alertable,
00328                                     TimeOut);
00329 }
00330 
00331 /*++
00332 * @name NtWaitForSingleObject
00333 * @implemented NT4
00334 *
00335 *     The NtWaitForSingleObject routine <FILLMEIN>
00336 *
00337 * @param ObjectHandle
00338 *        <FILLMEIN>
00339 *
00340 * @param Alertable
00341 *        <FILLMEIN>
00342 *
00343 * @param TimeOut
00344 *        <FILLMEIN>
00345 *
00346 * @return STATUS_SUCCESS or appropriate error value.
00347 *
00348 * @remarks None.
00349 *
00350 *--*/
00351 NTSTATUS
00352 NTAPI
00353 NtWaitForSingleObject(IN HANDLE ObjectHandle,
00354                       IN BOOLEAN Alertable,
00355                       IN PLARGE_INTEGER TimeOut  OPTIONAL)
00356 {
00357     PVOID Object, WaitableObject;
00358     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00359     LARGE_INTEGER SafeTimeOut;
00360     NTSTATUS Status;
00361 
00362     /* Check if we came with a timeout from user mode */
00363     if ((TimeOut) && (PreviousMode != KernelMode))
00364     {
00365         /* Enter SEH for proving */
00366         _SEH2_TRY
00367         {
00368             /* Make a copy on the stack */
00369             SafeTimeOut = ProbeForReadLargeInteger(TimeOut);
00370             TimeOut = &SafeTimeOut;
00371         }
00372         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00373         {
00374             /* Return the exception code */
00375             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00376         }
00377         _SEH2_END;
00378     }
00379 
00380     /* Get the Object */
00381     Status = ObReferenceObjectByHandle(ObjectHandle,
00382                                        SYNCHRONIZE,
00383                                        NULL,
00384                                        PreviousMode,
00385                                        &Object,
00386                                        NULL);
00387     if (NT_SUCCESS(Status))
00388     {
00389         /* Get the Waitable Object */
00390         WaitableObject = OBJECT_TO_OBJECT_HEADER(Object)->Type->DefaultObject;
00391 
00392         /* Is it an offset for internal objects? */
00393         if (IsPointerOffset(WaitableObject))
00394         {
00395             /* Turn it into a pointer */
00396             WaitableObject = (PVOID)((ULONG_PTR)Object +
00397                                      (ULONG_PTR)WaitableObject);
00398         }
00399 
00400         /* SEH this since it can also raise an exception */
00401         _SEH2_TRY
00402         {
00403             /* Ask the kernel to do the wait */
00404             Status = KeWaitForSingleObject(WaitableObject,
00405                                            UserRequest,
00406                                            PreviousMode,
00407                                            Alertable,
00408                                            TimeOut);
00409         }
00410         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00411         {
00412             /* Get the exception code */
00413             Status = _SEH2_GetExceptionCode();
00414         }
00415         _SEH2_END;
00416 
00417         /* Dereference the Object */
00418         ObDereferenceObject(Object);
00419     }
00420 
00421     /* Return the status */
00422     return Status;
00423 }
00424 
00425 /*++
00426 * @name NtSignalAndWaitForSingleObject
00427 * @implemented NT4
00428 *
00429 *     The NtSignalAndWaitForSingleObject routine <FILLMEIN>
00430 *
00431 * @param ObjectHandleToSignal
00432 *        <FILLMEIN>
00433 *
00434 * @param WaitableObjectHandle
00435 *        <FILLMEIN>
00436 *
00437 * @param Alertable
00438 *        <FILLMEIN>
00439 *
00440 * @param TimeOut
00441 *        <FILLMEIN>
00442 *
00443 * @return STATUS_SUCCESS or appropriate error value.
00444 *
00445 * @remarks None.
00446 *
00447 *--*/
00448 NTSTATUS
00449 NTAPI
00450 NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal,
00451                                IN HANDLE WaitableObjectHandle,
00452                                IN BOOLEAN Alertable,
00453                                IN PLARGE_INTEGER TimeOut OPTIONAL)
00454 {
00455     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00456     POBJECT_TYPE Type;
00457     PVOID SignalObj, WaitObj, WaitableObject;
00458     LARGE_INTEGER SafeTimeOut;
00459     OBJECT_HANDLE_INFORMATION HandleInfo;
00460     NTSTATUS Status;
00461 
00462     /* Check if we came with a timeout from user mode */
00463     if ((TimeOut) && (PreviousMode != KernelMode))
00464     {
00465         /* Enter SEH for probing */
00466         _SEH2_TRY
00467         {
00468             /* Make a copy on the stack */
00469             SafeTimeOut = ProbeForReadLargeInteger(TimeOut);
00470             TimeOut = &SafeTimeOut;
00471         }
00472         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00473         {
00474             /* Return the exception code */
00475             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00476         }
00477         _SEH2_END;
00478     }
00479 
00480     /* Start by getting the signal object*/
00481     Status = ObReferenceObjectByHandle(ObjectHandleToSignal,
00482                                        0,
00483                                        NULL,
00484                                        PreviousMode,
00485                                        &SignalObj,
00486                                        &HandleInfo);
00487     if (!NT_SUCCESS(Status)) return Status;
00488 
00489     /* Now get the wait object */
00490     Status = ObReferenceObjectByHandle(WaitableObjectHandle,
00491                                        SYNCHRONIZE,
00492                                        NULL,
00493                                        PreviousMode,
00494                                        &WaitObj,
00495                                        NULL);
00496     if (!NT_SUCCESS(Status))
00497     {
00498         /* Failed to reference the wait object */
00499         ObDereferenceObject(SignalObj);
00500         return Status;
00501     }
00502 
00503     /* Get the real waitable object */
00504     WaitableObject = OBJECT_TO_OBJECT_HEADER(WaitObj)->Type->DefaultObject;
00505 
00506     /* Handle internal offset */
00507     if (IsPointerOffset(WaitableObject))
00508     {
00509         /* Get real pointer */
00510         WaitableObject = (PVOID)((ULONG_PTR)WaitObj +
00511                                  (ULONG_PTR)WaitableObject);
00512     }
00513 
00514     /* Check Signal Object Type */
00515     Type = OBJECT_TO_OBJECT_HEADER(SignalObj)->Type;
00516     if (Type == ExEventObjectType)
00517     {
00518         /* Check if we came from user-mode without the right access */
00519         if ((PreviousMode != KernelMode) &&
00520             !(HandleInfo.GrantedAccess & EVENT_MODIFY_STATE))
00521         {
00522             /* Fail: lack of rights */
00523             Status = STATUS_ACCESS_DENIED;
00524             goto Quickie;
00525         }
00526 
00527         /* Set the Event */
00528         KeSetEvent(SignalObj, EVENT_INCREMENT, TRUE);
00529     }
00530     else if (Type == ExMutantObjectType)
00531     {
00532         /* This can raise an exception */
00533         _SEH2_TRY
00534         {
00535             /* Release the mutant */
00536             KeReleaseMutant(SignalObj, MUTANT_INCREMENT, FALSE, TRUE);
00537         }
00538         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00539         {
00540             /* Get the exception code */
00541             Status = _SEH2_GetExceptionCode();
00542         }
00543         _SEH2_END;
00544     }
00545     else if (Type == ExSemaphoreObjectType)
00546     {
00547         /* Check if we came from user-mode without the right access */
00548         if ((PreviousMode != KernelMode) &&
00549             !(HandleInfo.GrantedAccess & SEMAPHORE_MODIFY_STATE))
00550         {
00551             /* Fail: lack of rights */
00552             Status = STATUS_ACCESS_DENIED;
00553             goto Quickie;
00554         }
00555 
00556         /* This can raise an exception*/
00557         _SEH2_TRY
00558         {
00559             /* Release the semaphore */
00560             KeReleaseSemaphore(SignalObj, SEMAPHORE_INCREMENT, 1, TRUE);
00561         }
00562         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00563         {
00564             /* Get the exception code */
00565             Status = _SEH2_GetExceptionCode();
00566         }
00567         _SEH2_END;
00568     }
00569     else
00570     {
00571         /* This isn't a valid object to be waiting on */
00572         Status = STATUS_OBJECT_TYPE_MISMATCH;
00573     }
00574 
00575     /* Make sure we didn't fail */
00576     if (NT_SUCCESS(Status))
00577     {
00578         /* SEH this since it can also raise an exception */
00579         _SEH2_TRY
00580         {
00581             /* Perform the wait now */
00582             Status = KeWaitForSingleObject(WaitableObject,
00583                                            UserRequest,
00584                                            PreviousMode,
00585                                            Alertable,
00586                                            TimeOut);
00587         }
00588         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00589         {
00590             /* Get the exception code */
00591             Status = _SEH2_GetExceptionCode();
00592         }
00593         _SEH2_END;
00594     }
00595 
00596     /* We're done here, dereference both objects */
00597 Quickie:
00598     ObDereferenceObject(SignalObj);
00599     ObDereferenceObject(WaitObj);
00600     return Status;
00601 }
00602 
00603 /* EOF */

Generated on Sun May 27 2012 04:37:40 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.