Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenobwait.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
1.7.6.1
|