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
)
188 /* Check the current and forward object */
189 for (i
= 0, j
= i
+ 1; j
< ObjectCount
; j
++)
191 /* Make sure they don't match */
192 if (WaitObjects
[i
] == WaitObjects
[j
])
195 Status
= STATUS_INVALID_PARAMETER_MIX
;
196 DPRINT1("Objects duplicated with WaitAll\n");
203 } while (i
< ObjectCount
);
206 /* Now we can finally wait. Use SEH since it can raise an exception */
209 /* We're done playing with handles */
211 KeLeaveCriticalRegion();
213 /* Do the kernel wait */
214 Status
= KeWaitForMultipleObjects(ObjectCount
,
225 Status
= _SEH_GetExceptionCode();
230 /* First derefence */
231 while (ReferencedObjects
)
234 if (Objects
[ReferencedObjects
])
236 ObDereferenceObject(Objects
[ReferencedObjects
]);
240 /* Free wait block array */
241 if (WaitBlockArray
) ExFreePool(WaitBlockArray
);
243 /* Re-enable APCs if needed */
244 if (LockInUse
) KeLeaveCriticalRegion();
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 ProbeForRead(TimeOut
,
273 sizeof(LARGE_INTEGER
),
275 /* Make a copy on the stack */
276 SafeTimeOut
= *TimeOut
;
277 TimeOut
= &SafeTimeOut
;
281 Status
= _SEH_GetExceptionCode();
285 if(!NT_SUCCESS(Status
)) return Status
;
289 Status
= ObReferenceObjectByHandle(ObjectHandle
,
295 if (NT_SUCCESS(Status
))
297 /* Get the Waitable Object */
298 WaitableObject
= BODY_TO_HEADER(Object
)->Type
->DefaultObject
;
300 /* Is it an offset for internal objects? */
301 if ((LONG_PTR
)WaitableObject
>= 0)
303 /* Turn it into a pointer */
304 WaitableObject
= (PVOID
)((ULONG_PTR
)Object
+
305 (ULONG_PTR
)WaitableObject
);
308 /* Now wait. Also SEH this since it can also raise an exception */
311 Status
= KeWaitForSingleObject(WaitableObject
,
319 Status
= _SEH_GetExceptionCode();
323 /* Dereference the Object */
324 ObDereferenceObject(Object
);
327 /* Return the status */
333 NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal
,
334 IN HANDLE WaitableObjectHandle
,
335 IN BOOLEAN Alertable
,
336 IN PLARGE_INTEGER TimeOut OPTIONAL
)
338 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
342 PVOID WaitableObject
;
343 LARGE_INTEGER SafeTimeOut
;
344 OBJECT_HANDLE_INFORMATION HandleInfo
;
345 NTSTATUS Status
= STATUS_SUCCESS
;
347 /* Capture timeout */
348 DPRINT("NtSignalAndWaitForSingleObject\n");
349 if(TimeOut
&& PreviousMode
!= KernelMode
)
353 ProbeForRead(TimeOut
,
354 sizeof(LARGE_INTEGER
),
356 /* Make a copy on the stack */
357 SafeTimeOut
= *TimeOut
;
358 TimeOut
= &SafeTimeOut
;
362 Status
= _SEH_GetExceptionCode();
366 if(!NT_SUCCESS(Status
)) return Status
;
369 /* Start by getting the signal object*/
370 Status
= ObReferenceObjectByHandle(ObjectHandleToSignal
,
376 if (!NT_SUCCESS(Status
))
381 /* Now get the wait object */
382 Status
= ObReferenceObjectByHandle(WaitableObjectHandle
,
388 if (!NT_SUCCESS(Status
))
390 ObDereferenceObject(SignalObj
);
394 /* Get the real waitable object */
395 WaitableObject
= BODY_TO_HEADER(WaitObj
)->Type
->DefaultObject
;
397 /* Handle internal offset */
398 if ((LONG_PTR
)WaitableObject
>= 0)
400 /* Get real pointer */
401 WaitableObject
= (PVOID
)((ULONG_PTR
)WaitObj
+
402 (ULONG_PTR
)WaitableObject
);
405 /* Check Signal Object Type */
406 Type
= BODY_TO_HEADER(WaitObj
)->Type
;
407 if (Type
== ExEventObjectType
)
410 /* FIXME: Check permissions */
411 KeSetEvent(SignalObj
, EVENT_INCREMENT
, TRUE
);
413 else if (Type
== ExMutantObjectType
)
415 /* Release the Mutant. This can raise an exception*/
418 KeReleaseMutant(SignalObj
, MUTANT_INCREMENT
, FALSE
, TRUE
);
422 Status
= _SEH_GetExceptionCode();
427 else if (Type
== ExSemaphoreObjectType
)
429 /* Release the Semaphore. This can raise an exception*/
430 /* FIXME: Check permissions */
433 KeReleaseSemaphore(SignalObj
, SEMAPHORE_INCREMENT
, 1, TRUE
);
437 Status
= _SEH_GetExceptionCode();
444 Status
= STATUS_OBJECT_TYPE_MISMATCH
;
445 DPRINT1("Waiting on invalid object type\n");
449 /* Now wait. Also SEH this since it can also raise an exception */
452 Status
= KeWaitForSingleObject(WaitableObject
,
460 Status
= _SEH_GetExceptionCode();
464 /* We're done here */
466 ObDereferenceObject(SignalObj
);
467 ObDereferenceObject(WaitObj
);