Test commit. Not official branch release -- it will follow shortly in 15 minutes...
[reactos.git] / reactos / ntoskrnl / ob / wait.c
1 /*
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
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created file
8 * David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* FUNCTIONS *****************************************************************/
18
19 BOOL inline FASTCALL KiIsObjectWaitable(PVOID Object);
20
21 NTSTATUS STDCALL
22 NtWaitForMultipleObjects(IN ULONG ObjectCount,
23 IN PHANDLE ObjectsArray,
24 IN WAIT_TYPE WaitType,
25 IN BOOLEAN Alertable,
26 IN PLARGE_INTEGER TimeOut OPTIONAL)
27 {
28 KWAIT_BLOCK WaitBlockArray[MAXIMUM_WAIT_OBJECTS];
29 HANDLE SafeObjectsArray[MAXIMUM_WAIT_OBJECTS];
30 PVOID ObjectPtrArray[MAXIMUM_WAIT_OBJECTS];
31 ULONG i, j;
32 KPROCESSOR_MODE PreviousMode;
33 LARGE_INTEGER SafeTimeOut;
34 NTSTATUS Status = STATUS_SUCCESS;
35
36 DPRINT("NtWaitForMultipleObjects(ObjectCount %lu ObjectsArray[] %x, Alertable %d, "
37 "TimeOut %x)\n", ObjectCount,ObjectsArray,Alertable,TimeOut);
38
39 PreviousMode = ExGetPreviousMode();
40
41 if (ObjectCount > MAXIMUM_WAIT_OBJECTS)
42 return STATUS_UNSUCCESSFUL;
43 if (0 == ObjectCount)
44 return STATUS_INVALID_PARAMETER;
45
46 if(PreviousMode != KernelMode)
47 {
48 _SEH_TRY
49 {
50 ProbeForRead(ObjectsArray,
51 ObjectCount * sizeof(ObjectsArray[0]),
52 sizeof(ULONG));
53 /* make a copy so we don't have to guard with SEH later and keep track of
54 what objects we referenced in case dereferencing pointers suddenly fails */
55 RtlCopyMemory(SafeObjectsArray, ObjectsArray, ObjectCount * sizeof(ObjectsArray[0]));
56 ObjectsArray = SafeObjectsArray;
57
58 if(TimeOut != NULL)
59 {
60 ProbeForRead(TimeOut,
61 sizeof(LARGE_INTEGER),
62 sizeof(ULONG));
63 /* make a local copy of the timeout on the stack */
64 SafeTimeOut = *TimeOut;
65 TimeOut = &SafeTimeOut;
66 }
67 }
68 _SEH_HANDLE
69 {
70 Status = _SEH_GetExceptionCode();
71 }
72 _SEH_END;
73
74 if(!NT_SUCCESS(Status))
75 {
76 return Status;
77 }
78 }
79
80 /* reference all objects */
81 for (i = 0; i < ObjectCount; i++)
82 {
83 Status = ObReferenceObjectByHandle(ObjectsArray[i],
84 SYNCHRONIZE,
85 NULL,
86 PreviousMode,
87 &ObjectPtrArray[i],
88 NULL);
89 if (!NT_SUCCESS(Status) || !KiIsObjectWaitable(ObjectPtrArray[i]))
90 {
91 if (NT_SUCCESS(Status))
92 {
93 DPRINT1("Waiting for object type '%wZ' is not supported\n",
94 &BODY_TO_HEADER(ObjectPtrArray[i])->ObjectType->TypeName);
95 Status = STATUS_HANDLE_NOT_WAITABLE;
96 i++;
97 }
98 /* dereference all referenced objects */
99 for (j = 0; j < i; j++)
100 {
101 ObDereferenceObject(ObjectPtrArray[j]);
102 }
103
104 return(Status);
105 }
106 }
107
108 Status = KeWaitForMultipleObjects(ObjectCount,
109 ObjectPtrArray,
110 WaitType,
111 UserRequest,
112 PreviousMode,
113 Alertable,
114 TimeOut,
115 WaitBlockArray);
116
117 /* dereference all objects */
118 for (i = 0; i < ObjectCount; i++)
119 {
120 ObDereferenceObject(ObjectPtrArray[i]);
121 }
122
123 return(Status);
124 }
125
126
127 /*
128 * @implemented
129 */
130 NTSTATUS STDCALL
131 NtWaitForSingleObject(IN HANDLE ObjectHandle,
132 IN BOOLEAN Alertable,
133 IN PLARGE_INTEGER TimeOut OPTIONAL)
134 {
135 PVOID ObjectPtr;
136 KPROCESSOR_MODE PreviousMode;
137 LARGE_INTEGER SafeTimeOut;
138 NTSTATUS Status = STATUS_SUCCESS;
139
140 DPRINT("NtWaitForSingleObject(ObjectHandle %x, Alertable %d, TimeOut %x)\n",
141 ObjectHandle,Alertable,TimeOut);
142
143 PreviousMode = ExGetPreviousMode();
144
145 if(TimeOut != NULL && PreviousMode != KernelMode)
146 {
147 _SEH_TRY
148 {
149 ProbeForRead(TimeOut,
150 sizeof(LARGE_INTEGER),
151 sizeof(ULONG));
152 /* make a copy on the stack */
153 SafeTimeOut = *TimeOut;
154 TimeOut = &SafeTimeOut;
155 }
156 _SEH_HANDLE
157 {
158 Status = _SEH_GetExceptionCode();
159 }
160 _SEH_END;
161
162 if(!NT_SUCCESS(Status))
163 {
164 return Status;
165 }
166 }
167
168 Status = ObReferenceObjectByHandle(ObjectHandle,
169 SYNCHRONIZE,
170 NULL,
171 PreviousMode,
172 &ObjectPtr,
173 NULL);
174 if (!NT_SUCCESS(Status))
175 {
176 return(Status);
177 }
178 if (!KiIsObjectWaitable(ObjectPtr))
179 {
180 DPRINT1("Waiting for object type '%wZ' is not supported\n",
181 &BODY_TO_HEADER(ObjectPtr)->ObjectType->TypeName);
182 Status = STATUS_HANDLE_NOT_WAITABLE;
183 }
184 else
185 {
186 Status = KeWaitForSingleObject(ObjectPtr,
187 UserRequest,
188 PreviousMode,
189 Alertable,
190 TimeOut);
191 }
192
193 ObDereferenceObject(ObjectPtr);
194
195 return(Status);
196 }
197
198
199 NTSTATUS STDCALL
200 NtSignalAndWaitForSingleObject(IN HANDLE ObjectHandleToSignal,
201 IN HANDLE WaitableObjectHandle,
202 IN BOOLEAN Alertable,
203 IN PLARGE_INTEGER TimeOut OPTIONAL)
204 {
205 KPROCESSOR_MODE PreviousMode;
206 DISPATCHER_HEADER* hdr;
207 PVOID SignalObj;
208 PVOID WaitObj;
209 LARGE_INTEGER SafeTimeOut;
210 NTSTATUS Status = STATUS_SUCCESS;
211
212 PreviousMode = ExGetPreviousMode();
213
214 if(TimeOut != NULL && PreviousMode != KernelMode)
215 {
216 _SEH_TRY
217 {
218 ProbeForRead(TimeOut,
219 sizeof(LARGE_INTEGER),
220 sizeof(ULONG));
221 /* make a copy on the stack */
222 SafeTimeOut = *TimeOut;
223 TimeOut = &SafeTimeOut;
224 }
225 _SEH_HANDLE
226 {
227 Status = _SEH_GetExceptionCode();
228 }
229 _SEH_END;
230
231 if(!NT_SUCCESS(Status))
232 {
233 return Status;
234 }
235 }
236
237 Status = ObReferenceObjectByHandle(ObjectHandleToSignal,
238 0,
239 NULL,
240 PreviousMode,
241 &SignalObj,
242 NULL);
243 if (!NT_SUCCESS(Status))
244 {
245 return Status;
246 }
247
248 Status = ObReferenceObjectByHandle(WaitableObjectHandle,
249 SYNCHRONIZE,
250 NULL,
251 PreviousMode,
252 &WaitObj,
253 NULL);
254 if (!NT_SUCCESS(Status))
255 {
256 ObDereferenceObject(SignalObj);
257 return Status;
258 }
259
260 hdr = (DISPATCHER_HEADER *)SignalObj;
261 switch (hdr->Type)
262 {
263 case EventNotificationObject:
264 case EventSynchronizationObject:
265 KeSetEvent(SignalObj,
266 EVENT_INCREMENT,
267 TRUE);
268 break;
269
270 case MutantObject:
271 KeReleaseMutex(SignalObj,
272 TRUE);
273 break;
274
275 case SemaphoreObject:
276 KeReleaseSemaphore(SignalObj,
277 SEMAPHORE_INCREMENT,
278 1,
279 TRUE);
280 break;
281
282 default:
283 ObDereferenceObject(SignalObj);
284 ObDereferenceObject(WaitObj);
285 return STATUS_OBJECT_TYPE_MISMATCH;
286 }
287
288 Status = KeWaitForSingleObject(WaitObj,
289 UserRequest,
290 PreviousMode,
291 Alertable,
292 TimeOut);
293
294 ObDereferenceObject(SignalObj);
295 ObDereferenceObject(WaitObj);
296
297 return Status;
298 }
299
300 /* EOF */