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
),
78 /* Make a local copy of the timeout on the stack */
79 SafeTimeOut
= ProbeForReadLargeInteger(TimeOut
);
80 TimeOut
= &SafeTimeOut
;
85 * Make a copy so we don't have to guard with SEH later and keep
86 * track of what objects we referenced if dereferencing pointers
89 RtlCopyMemory(Handles
,
91 ObjectCount
* sizeof(HANDLE
));
95 Status
= _SEH_GetExceptionCode();
99 if(!NT_SUCCESS(Status
)) goto Quickie
;
101 /* Check if we can use the internal Wait Array */
102 if (ObjectCount
> THREAD_WAIT_OBJECTS
)
104 /* Allocate from Pool */
105 WaitBlockArray
= ExAllocatePoolWithTag(NonPagedPool
,
106 ObjectCount
* sizeof(KWAIT_BLOCK
),
113 /* Use the right Executive Handle */
114 if(ObIsKernelHandle(Handles
[i
], PreviousMode
))
116 /* Use the System Handle Table and decode */
117 HandleTable
= ObpKernelHandleTable
;
118 Handles
[i
] = ObKernelHandleToHandle(Handles
[i
]);
122 /* Use the Process' Handle table and get the Ex Handle */
123 HandleTable
= PsGetCurrentProcess()->ObjectTable
;
126 /* Get a pointer to it */
127 if (!(HandleEntry
= ExMapHandleToPointer(HandleTable
, Handles
[i
])))
129 DPRINT1("Invalid handle\n");
130 Status
= STATUS_INVALID_HANDLE
;
134 /* Check for synchronize access */
135 GrantedAccess
= HandleEntry
->u2
.GrantedAccess
;
136 if ((PreviousMode
!= KernelMode
) && (!(GrantedAccess
& SYNCHRONIZE
)))
138 /* Unlock the entry and fail */
139 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
140 Status
= STATUS_ACCESS_DENIED
;
141 DPRINT1("Handle doesn't have SYNCH access\n");
145 /* Get the Object Header */
146 ObjectHeader
= EX_HTE_TO_HDR(HandleEntry
);
148 /* Get default Object */
149 DefaultObject
= ObjectHeader
->Type
->DefaultObject
;
151 /* Check if it's the internal offset */
152 if (IsPointerOffset(DefaultObject
))
154 /* Increase reference count */
155 InterlockedIncrement(&ObjectHeader
->PointerCount
);
158 /* Save the Object and Wait Object, this is a relative offset */
159 Objects
[i
] = &ObjectHeader
->Body
;
160 WaitObjects
[i
] = (PVOID
)((ULONG_PTR
)&ObjectHeader
->Body
+
161 (ULONG_PTR
)DefaultObject
);
165 /* This is our internal Object */
168 WaitObjects
[i
] = DefaultObject
;
171 /* Unlock the Handle Table Entry */
172 ExUnlockHandleTableEntry(HandleTable
, HandleEntry
);
176 } while (i
< ObjectCount
);
178 /* For a Waitall, we can't have the same object more then once */
179 if (WaitType
== WaitAll
)
181 /* Clear the main loop variable */
187 /* Check the current and forward object */
188 for (j
= i
+ 1; j
< ObjectCount
; j
++)
190 /* Make sure they don't match */
191 if (WaitObjects
[i
] == WaitObjects
[j
])
194 Status
= STATUS_INVALID_PARAMETER_MIX
;
195 DPRINT1("Objects duplicated with WaitAll\n");
202 } while (i
< ObjectCount
);
205 /* Now we can finally wait. Use SEH since it can raise an exception */
208 /* We're done playing with handles */
210 KeLeaveCriticalRegion();
212 /* Do the kernel wait */
213 Status
= KeWaitForMultipleObjects(ObjectCount
,
224 Status
= _SEH_GetExceptionCode();
229 /* First derefence */
230 while (ReferencedObjects
)
233 if (Objects
[ReferencedObjects
])
235 ObDereferenceObject(Objects
[ReferencedObjects
]);
239 /* Free wait block array */
240 if (WaitBlockArray
) ExFreePool(WaitBlockArray
);
242 /* Re-enable APCs if needed */
243 if (LockInUse
) KeLeaveCriticalRegion();
246 DPRINT1("Returning: %x\n", Status
);
255 NtWaitForSingleObject(IN HANDLE ObjectHandle
,
256 IN BOOLEAN Alertable
,
257 IN PLARGE_INTEGER TimeOut OPTIONAL
)
259 PVOID Object
, WaitableObject
;
260 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
261 LARGE_INTEGER SafeTimeOut
;
262 NTSTATUS Status
= STATUS_SUCCESS
;
264 DPRINT("NtWaitForSingleObject(ObjectHandle %x, Alertable %d, TimeOut %x)\n",
265 ObjectHandle
,Alertable
,TimeOut
);
267 /* Capture timeout */
268 if(TimeOut
&& PreviousMode
!= KernelMode
)
272 /* Make a copy on the stack */
273 SafeTimeOut
= ProbeForReadLargeInteger(TimeOut
);
274 TimeOut
= &SafeTimeOut
;
278 Status
= _SEH_GetExceptionCode();
282 if(!NT_SUCCESS(Status
)) return Status
;
286 Status
= ObReferenceObjectByHandle(ObjectHandle
,
292 if (NT_SUCCESS(Status
))
294 /* Get the Waitable Object */
295 WaitableObject
= BODY_TO_HEADER(Object
)->Type
->DefaultObject
;
297 /* Is it an offset for internal objects? */
298 if (IsPointerOffset(WaitableObject
))
300 /* Turn it into a pointer */
301 WaitableObject
= (PVOID
)((ULONG_PTR
)Object
+
302 (ULONG_PTR
)WaitableObject
);
305 /* Now wait. Also SEH this since it can also raise an exception */
308 Status
= KeWaitForSingleObject(WaitableObject
,
316 Status
= _SEH_GetExceptionCode();
320 /* Dereference the Object */
321 ObDereferenceObject(Object
);
324 /* Return the status */
330 NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal
,
331 IN HANDLE WaitableObjectHandle
,
332 IN BOOLEAN Alertable
,
333 IN PLARGE_INTEGER TimeOut OPTIONAL
)
335 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
339 PVOID WaitableObject
;
340 LARGE_INTEGER SafeTimeOut
;
341 OBJECT_HANDLE_INFORMATION HandleInfo
;
342 NTSTATUS Status
= STATUS_SUCCESS
;
344 /* Capture timeout */
345 DPRINT("NtSignalAndWaitForSingleObject\n");
346 if(TimeOut
&& PreviousMode
!= KernelMode
)
350 /* Make a copy on the stack */
351 SafeTimeOut
= ProbeForReadLargeInteger(TimeOut
);
352 TimeOut
= &SafeTimeOut
;
356 Status
= _SEH_GetExceptionCode();
360 if(!NT_SUCCESS(Status
)) return Status
;
363 /* Start by getting the signal object*/
364 Status
= ObReferenceObjectByHandle(ObjectHandleToSignal
,
370 if (!NT_SUCCESS(Status
))
375 /* Now get the wait object */
376 Status
= ObReferenceObjectByHandle(WaitableObjectHandle
,
382 if (!NT_SUCCESS(Status
))
384 ObDereferenceObject(SignalObj
);
388 /* Get the real waitable object */
389 WaitableObject
= BODY_TO_HEADER(WaitObj
)->Type
->DefaultObject
;
391 /* Handle internal offset */
392 if (IsPointerOffset(WaitableObject
))
394 /* Get real pointer */
395 WaitableObject
= (PVOID
)((ULONG_PTR
)WaitObj
+
396 (ULONG_PTR
)WaitableObject
);
399 /* Check Signal Object Type */
400 Type
= BODY_TO_HEADER(WaitObj
)->Type
;
401 if (Type
== ExEventObjectType
)
404 /* FIXME: Check permissions */
405 KeSetEvent(SignalObj
, EVENT_INCREMENT
, TRUE
);
407 else if (Type
== ExMutantObjectType
)
409 /* Release the Mutant. This can raise an exception*/
412 KeReleaseMutant(SignalObj
, MUTANT_INCREMENT
, FALSE
, TRUE
);
416 Status
= _SEH_GetExceptionCode();
421 else if (Type
== ExSemaphoreObjectType
)
423 /* Release the Semaphore. This can raise an exception*/
424 /* FIXME: Check permissions */
427 KeReleaseSemaphore(SignalObj
, SEMAPHORE_INCREMENT
, 1, TRUE
);
431 Status
= _SEH_GetExceptionCode();
438 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
439 DPRINT1("Waiting on invalid object type\n");
443 /* Now wait. Also SEH this since it can also raise an exception */
446 Status
= KeWaitForSingleObject(WaitableObject
,
454 Status
= _SEH_GetExceptionCode();
458 /* We're done here */
460 ObDereferenceObject(SignalObj
);
461 ObDereferenceObject(WaitObj
);