2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ob/wait.c
5 * PURPOSE: Handles Waiting on Objects
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 * David Welch (welch@mcmail.com)
11 /* INCLUDES ******************************************************************/
15 #include <internal/debug.h>
17 #define TAG_WAIT TAG('W', 'a', 'i', 't')
19 /* FUNCTIONS *****************************************************************/
23 NtWaitForMultipleObjects(IN ULONG ObjectCount
,
24 IN PHANDLE HandleArray
,
25 IN WAIT_TYPE WaitType
,
27 IN PLARGE_INTEGER TimeOut OPTIONAL
)
29 PKWAIT_BLOCK WaitBlockArray
= NULL
;
30 HANDLE Handles
[MAXIMUM_WAIT_OBJECTS
];
31 PVOID Objects
[MAXIMUM_WAIT_OBJECTS
];
32 PVOID WaitObjects
[MAXIMUM_WAIT_OBJECTS
];
33 ULONG i
= 0, ReferencedObjects
= 0, j
;
34 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
35 LARGE_INTEGER SafeTimeOut
;
37 PHANDLE_TABLE_ENTRY HandleEntry
;
38 POBJECT_HEADER ObjectHeader
;
39 PHANDLE_TABLE HandleTable
;
40 ACCESS_MASK GrantedAccess
;
42 NTSTATUS Status
= STATUS_SUCCESS
;
44 DPRINT("NtWaitForMultipleObjects(ObjectCount %lu HandleArray[] %x, Alertable %d, "
45 "TimeOut %x)\n", ObjectCount
, HandleArray
, Alertable
, TimeOut
);
47 /* Enter a critical region since we'll play with handles */
49 KeEnterCriticalRegion();
51 /* Check for valid Object Count */
52 if ((ObjectCount
> MAXIMUM_WAIT_OBJECTS
) || !ObjectCount
)
54 Status
= STATUS_INVALID_PARAMETER_1
;
55 DPRINT1("No object count, or too many objects\n");
59 /* Check for valid Wait Type */
60 if ((WaitType
!= WaitAll
) && (WaitType
!= WaitAny
))
62 Status
= STATUS_INVALID_PARAMETER_3
;
63 DPRINT1("Invalid wait type\n");
67 /* Capture arguments */
70 if(PreviousMode
!= KernelMode
)
72 ProbeForRead(HandleArray
,
73 ObjectCount
* sizeof(HANDLE
),
79 sizeof(LARGE_INTEGER
),
82 /* Make a local copy of the timeout on the stack */
83 SafeTimeOut
= *TimeOut
;
84 TimeOut
= &SafeTimeOut
;
89 * Make a copy so we don't have to guard with SEH later and keep
90 * track of what objects we referenced if dereferencing pointers
93 RtlCopyMemory(Handles
,
95 ObjectCount
* sizeof(HANDLE
));
99 Status
= _SEH_GetExceptionCode();
103 if(!NT_SUCCESS(Status
)) goto Quickie
;
105 /* Check if we can use the internal Wait Array */
106 if (ObjectCount
> THREAD_WAIT_OBJECTS
)
108 /* Allocate from Pool */
109 WaitBlockArray
= ExAllocatePoolWithTag(NonPagedPool
,
110 ObjectCount
* sizeof(KWAIT_BLOCK
),
117 /* Use the right Executive Handle */
118 if(ObIsKernelHandle(Handles
[i
], PreviousMode
))
120 /* Use the System Handle Table and decode */
121 HandleTable
= ObpKernelHandleTable
;
122 Handles
[i
] = ObKernelHandleToHandle(Handles
[i
]);
126 /* Use the Process' Handle table and get the Ex Handle */
127 HandleTable
= PsGetCurrentProcess()->ObjectTable
;
130 /* Get a pointer to it */
131 if (!(HandleEntry
= ExMapHandleToPointer(HandleTable
, Handles
[i
])))
133 DPRINT1("Invalid handle\n");
134 Status
= STATUS_INVALID_HANDLE
;
138 /* Check for synchronize access */
139 GrantedAccess
= HandleEntry
->u2
.GrantedAccess
;
140 if ((PreviousMode
!= KernelMode
) && (!(GrantedAccess
& SYNCHRONIZE
)))
142 /* Unlock the entry and fail */
143 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
144 Status
= STATUS_ACCESS_DENIED
;
145 DPRINT1("Handle doesn't have SYNCH access\n");
149 /* Get the Object Header */
150 ObjectHeader
= EX_HTE_TO_HDR(HandleEntry
);
152 /* Get default Object */
153 DefaultObject
= ObjectHeader
->Type
->DefaultObject
;
155 /* Check if it's the internal offset */
156 if ((LONG_PTR
)DefaultObject
>= 0)
158 /* Increase reference count */
159 InterlockedIncrement(&ObjectHeader
->PointerCount
);
162 /* Save the Object and Wait Object, this is a relative offset */
163 Objects
[i
] = &ObjectHeader
->Body
;
164 WaitObjects
[i
] = (PVOID
)((ULONG_PTR
)&ObjectHeader
->Body
+
165 (ULONG_PTR
)DefaultObject
);
169 /* This is our internal Object */
172 WaitObjects
[i
] = DefaultObject
;
175 /* Unlock the Handle Table Entry */
176 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
180 } while (i
< ObjectCount
);
182 /* For a Waitall, we can't have the same object more then once */
183 if (WaitType
== WaitAll
)
185 /* Clear the main loop variable */
191 /* Check the current and forward object */
192 for (j
= i
+ 1; j
< ObjectCount
; j
++)
194 /* Make sure they don't match */
195 if (WaitObjects
[i
] == WaitObjects
[j
])
198 Status
= STATUS_INVALID_PARAMETER_MIX
;
199 DPRINT1("Objects duplicated with WaitAll\n");
206 } while (i
< ObjectCount
);
209 /* Now we can finally wait. Use SEH since it can raise an exception */
212 /* We're done playing with handles */
214 KeLeaveCriticalRegion();
216 /* Do the kernel wait */
217 Status
= KeWaitForMultipleObjects(ObjectCount
,
228 Status
= _SEH_GetExceptionCode();
233 /* First derefence */
234 while (ReferencedObjects
)
237 if (Objects
[ReferencedObjects
])
239 ObDereferenceObject(Objects
[ReferencedObjects
]);
243 /* Free wait block array */
244 if (WaitBlockArray
) ExFreePool(WaitBlockArray
);
246 /* Re-enable APCs if needed */
247 if (LockInUse
) KeLeaveCriticalRegion();
250 DPRINT1("Returning: %x\n", Status
);
259 NtWaitForSingleObject(IN HANDLE ObjectHandle
,
260 IN BOOLEAN Alertable
,
261 IN PLARGE_INTEGER TimeOut OPTIONAL
)
263 PVOID Object
, WaitableObject
;
264 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
265 LARGE_INTEGER SafeTimeOut
;
266 NTSTATUS Status
= STATUS_SUCCESS
;
268 DPRINT("NtWaitForSingleObject(ObjectHandle %x, Alertable %d, TimeOut %x)\n",
269 ObjectHandle
,Alertable
,TimeOut
);
271 /* Capture timeout */
272 if(TimeOut
&& PreviousMode
!= KernelMode
)
276 ProbeForRead(TimeOut
,
277 sizeof(LARGE_INTEGER
),
279 /* Make a copy on the stack */
280 SafeTimeOut
= *TimeOut
;
281 TimeOut
= &SafeTimeOut
;
285 Status
= _SEH_GetExceptionCode();
289 if(!NT_SUCCESS(Status
)) return Status
;
293 Status
= ObReferenceObjectByHandle(ObjectHandle
,
299 if (NT_SUCCESS(Status
))
301 /* Get the Waitable Object */
302 WaitableObject
= BODY_TO_HEADER(Object
)->Type
->DefaultObject
;
304 /* Is it an offset for internal objects? */
305 if ((LONG_PTR
)WaitableObject
>= 0)
307 /* Turn it into a pointer */
308 WaitableObject
= (PVOID
)((ULONG_PTR
)Object
+
309 (ULONG_PTR
)WaitableObject
);
312 /* Now wait. Also SEH this since it can also raise an exception */
315 Status
= KeWaitForSingleObject(WaitableObject
,
323 Status
= _SEH_GetExceptionCode();
327 /* Dereference the Object */
328 ObDereferenceObject(Object
);
331 /* Return the status */
337 NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal
,
338 IN HANDLE WaitableObjectHandle
,
339 IN BOOLEAN Alertable
,
340 IN PLARGE_INTEGER TimeOut OPTIONAL
)
342 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
346 PVOID WaitableObject
;
347 LARGE_INTEGER SafeTimeOut
;
348 OBJECT_HANDLE_INFORMATION HandleInfo
;
349 NTSTATUS Status
= STATUS_SUCCESS
;
351 /* Capture timeout */
352 DPRINT("NtSignalAndWaitForSingleObject\n");
353 if(TimeOut
&& PreviousMode
!= KernelMode
)
357 ProbeForRead(TimeOut
,
358 sizeof(LARGE_INTEGER
),
360 /* Make a copy on the stack */
361 SafeTimeOut
= *TimeOut
;
362 TimeOut
= &SafeTimeOut
;
366 Status
= _SEH_GetExceptionCode();
370 if(!NT_SUCCESS(Status
)) return Status
;
373 /* Start by getting the signal object*/
374 Status
= ObReferenceObjectByHandle(ObjectHandleToSignal
,
380 if (!NT_SUCCESS(Status
))
385 /* Now get the wait object */
386 Status
= ObReferenceObjectByHandle(WaitableObjectHandle
,
392 if (!NT_SUCCESS(Status
))
394 ObDereferenceObject(SignalObj
);
398 /* Get the real waitable object */
399 WaitableObject
= BODY_TO_HEADER(WaitObj
)->Type
->DefaultObject
;
401 /* Handle internal offset */
402 if ((LONG_PTR
)WaitableObject
>= 0)
404 /* Get real pointer */
405 WaitableObject
= (PVOID
)((ULONG_PTR
)WaitObj
+
406 (ULONG_PTR
)WaitableObject
);
409 /* Check Signal Object Type */
410 Type
= BODY_TO_HEADER(WaitObj
)->Type
;
411 if (Type
== ExEventObjectType
)
414 /* FIXME: Check permissions */
415 KeSetEvent(SignalObj
, EVENT_INCREMENT
, TRUE
);
417 else if (Type
== ExMutantObjectType
)
419 /* Release the Mutant. This can raise an exception*/
422 KeReleaseMutant(SignalObj
, MUTANT_INCREMENT
, FALSE
, TRUE
);
426 Status
= _SEH_GetExceptionCode();
431 else if (Type
== ExSemaphoreObjectType
)
433 /* Release the Semaphore. This can raise an exception*/
434 /* FIXME: Check permissions */
437 KeReleaseSemaphore(SignalObj
, SEMAPHORE_INCREMENT
, 1, TRUE
);
441 Status
= _SEH_GetExceptionCode();
448 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
449 DPRINT1("Waiting on invalid object type\n");
453 /* Now wait. Also SEH this since it can also raise an exception */
456 Status
= KeWaitForSingleObject(WaitableObject
,
464 Status
= _SEH_GetExceptionCode();
468 /* We're done here */
470 ObDereferenceObject(SignalObj
);
471 ObDereferenceObject(WaitObj
);