Release 20030408.
[wine/gsoc-2012-control.git] / dlls / ntdll / sync.c
blobe0950f1487fcea25f6dae340764a2b6e1d1ea29d
1 /*
2 * Process synchronisation
4 * Copyright 1997 Alexandre Julliard
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
24 #include <assert.h>
25 #include <errno.h>
26 #include <signal.h>
27 #ifdef HAVE_SYS_TIME_H
28 # include <sys/time.h>
29 #endif
30 #ifdef HAVE_SYS_POLL_H
31 # include <sys/poll.h>
32 #endif
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #include <string.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <time.h>
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
44 #include "winternl.h"
45 #include "async.h"
46 #include "thread.h"
47 #include "wine/server.h"
48 #include "wine/unicode.h"
49 #include "wine/debug.h"
50 #include "ntdll_misc.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
56 * Semaphores
59 /******************************************************************************
60 * NtCreateSemaphore (NTDLL.@)
62 NTSTATUS WINAPI NtCreateSemaphore( OUT PHANDLE SemaphoreHandle,
63 IN ACCESS_MASK access,
64 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
65 IN ULONG InitialCount,
66 IN ULONG MaximumCount )
68 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
69 NTSTATUS ret;
71 if ((MaximumCount <= 0) || (InitialCount > MaximumCount))
72 return STATUS_INVALID_PARAMETER;
74 SERVER_START_REQ( create_semaphore )
76 req->initial = InitialCount;
77 req->max = MaximumCount;
78 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
79 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
80 ret = wine_server_call( req );
81 *SemaphoreHandle = reply->handle;
83 SERVER_END_REQ;
84 return ret;
87 /******************************************************************************
88 * NtOpenSemaphore (NTDLL.@)
90 NTSTATUS WINAPI NtOpenSemaphore( OUT PHANDLE SemaphoreHandle,
91 IN ACCESS_MASK access,
92 IN const OBJECT_ATTRIBUTES *attr )
94 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
95 NTSTATUS ret;
97 SERVER_START_REQ( open_semaphore )
99 req->access = access;
100 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
101 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
102 ret = wine_server_call( req );
103 *SemaphoreHandle = reply->handle;
105 SERVER_END_REQ;
106 return ret;
109 /******************************************************************************
110 * NtQuerySemaphore (NTDLL.@)
112 NTSTATUS WINAPI NtQuerySemaphore(
113 HANDLE SemaphoreHandle,
114 PVOID SemaphoreInformationClass,
115 OUT PVOID SemaphoreInformation,
116 ULONG Length,
117 PULONG ReturnLength)
119 FIXME("(%p,%p,%p,0x%08lx,%p) stub!\n",
120 SemaphoreHandle, SemaphoreInformationClass, SemaphoreInformation, Length, ReturnLength);
121 return STATUS_SUCCESS;
124 /******************************************************************************
125 * NtReleaseSemaphore (NTDLL.@)
127 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
129 NTSTATUS ret;
130 SERVER_START_REQ( release_semaphore )
132 req->handle = handle;
133 req->count = count;
134 if (!(ret = wine_server_call( req )))
136 if (previous) *previous = reply->prev_count;
139 SERVER_END_REQ;
140 return ret;
144 * Events
147 /**************************************************************************
148 * NtCreateEvent (NTDLL.@)
149 * ZwCreateEvent (NTDLL.@)
151 NTSTATUS WINAPI NtCreateEvent(
152 OUT PHANDLE EventHandle,
153 IN ACCESS_MASK DesiredAccess,
154 IN const OBJECT_ATTRIBUTES *attr,
155 IN BOOLEAN ManualReset,
156 IN BOOLEAN InitialState)
158 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
159 NTSTATUS ret;
161 SERVER_START_REQ( create_event )
163 req->manual_reset = ManualReset;
164 req->initial_state = InitialState;
165 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
166 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
167 ret = wine_server_call( req );
168 *EventHandle = reply->handle;
170 SERVER_END_REQ;
171 return ret;
174 /******************************************************************************
175 * NtOpenEvent (NTDLL.@)
176 * ZwOpenEvent (NTDLL.@)
178 NTSTATUS WINAPI NtOpenEvent(
179 OUT PHANDLE EventHandle,
180 IN ACCESS_MASK DesiredAccess,
181 IN const OBJECT_ATTRIBUTES *attr )
183 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
184 NTSTATUS ret;
186 SERVER_START_REQ( open_event )
188 req->access = DesiredAccess;
189 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
190 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
191 ret = wine_server_call( req );
192 *EventHandle = reply->handle;
194 SERVER_END_REQ;
195 return ret;
199 /******************************************************************************
200 * NtSetEvent (NTDLL.@)
201 * ZwSetEvent (NTDLL.@)
203 NTSTATUS WINAPI NtSetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
205 NTSTATUS ret;
207 /* FIXME: set NumberOfThreadsReleased */
209 SERVER_START_REQ( event_op )
211 req->handle = handle;
212 req->op = SET_EVENT;
213 ret = wine_server_call( req );
215 SERVER_END_REQ;
216 return ret;
219 /******************************************************************************
220 * NtResetEvent (NTDLL.@)
222 NTSTATUS WINAPI NtResetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
224 NTSTATUS ret;
226 /* resetting an event can't release any thread... */
227 if (NumberOfThreadsReleased) *NumberOfThreadsReleased = 0;
229 SERVER_START_REQ( event_op )
231 req->handle = handle;
232 req->op = RESET_EVENT;
233 ret = wine_server_call( req );
235 SERVER_END_REQ;
236 return ret;
239 /******************************************************************************
240 * NtClearEvent (NTDLL.@)
242 * FIXME
243 * same as NtResetEvent ???
245 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
247 return NtResetEvent( handle, NULL );
250 /******************************************************************************
251 * NtPulseEvent (NTDLL.@)
253 * FIXME
254 * PulseCount
256 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, PULONG PulseCount )
258 NTSTATUS ret;
259 FIXME("(%p,%p)\n", handle, PulseCount);
260 SERVER_START_REQ( event_op )
262 req->handle = handle;
263 req->op = PULSE_EVENT;
264 ret = wine_server_call( req );
266 SERVER_END_REQ;
267 return ret;
270 /******************************************************************************
271 * NtQueryEvent (NTDLL.@)
273 NTSTATUS WINAPI NtQueryEvent (
274 IN HANDLE EventHandle,
275 IN UINT EventInformationClass,
276 OUT PVOID EventInformation,
277 IN ULONG EventInformationLength,
278 OUT PULONG ReturnLength)
280 FIXME("(%p)\n", EventHandle);
281 return STATUS_SUCCESS;
285 /***********************************************************************
286 * check_async_list
288 * Process a status event from the server.
290 static void WINAPI check_async_list(async_private *asp, DWORD status)
292 async_private *ovp;
293 DWORD ovp_status;
295 for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
297 if(!ovp)
298 return;
300 if( status != STATUS_ALERTED )
302 ovp_status = status;
303 ovp->ops->set_status (ovp, status);
305 else ovp_status = ovp->ops->get_status (ovp);
307 if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
309 /* This will destroy all but PENDING requests */
310 register_old_async( ovp );
314 /***********************************************************************
315 * wait_reply
317 * Wait for a reply on the waiting pipe of the current thread.
319 static int wait_reply( void *cookie )
321 int signaled;
322 struct wake_up_reply reply;
323 for (;;)
325 int ret;
326 ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
327 if (ret == sizeof(reply))
329 if (!reply.cookie) break; /* thread got killed */
330 if (reply.cookie == cookie) return reply.signaled;
331 /* we stole another reply, wait for the real one */
332 signaled = wait_reply( cookie );
333 /* and now put the wrong one back in the pipe */
334 for (;;)
336 ret = write( NtCurrentTeb()->wait_fd[1], &reply, sizeof(reply) );
337 if (ret == sizeof(reply)) break;
338 if (ret >= 0) server_protocol_error( "partial wakeup write %d\n", ret );
339 if (errno == EINTR) continue;
340 server_protocol_perror("wakeup write");
342 return signaled;
344 if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret );
345 if (errno == EINTR) continue;
346 server_protocol_perror("wakeup read");
348 /* the server closed the connection; time to die... */
349 SYSDEPS_AbortThread(0);
353 /***********************************************************************
354 * call_apcs
356 * Call outstanding APCs.
358 static void call_apcs( BOOL alertable )
360 FARPROC proc;
361 LARGE_INTEGER time;
362 void *arg1, *arg2, *arg3;
364 for (;;)
366 int type = APC_NONE;
367 SERVER_START_REQ( get_apc )
369 req->alertable = alertable;
370 if (!wine_server_call( req )) type = reply->type;
371 proc = reply->func;
372 arg1 = reply->arg1;
373 arg2 = reply->arg2;
374 arg3 = reply->arg3;
376 SERVER_END_REQ;
378 switch(type)
380 case APC_NONE:
381 return; /* no more APCs */
382 case APC_ASYNC:
383 proc( arg1, arg2 );
384 break;
385 case APC_USER:
386 proc( arg1, arg2, arg3 );
387 break;
388 case APC_TIMER:
389 /* convert sec/usec to NT time */
390 RtlSecondsSince1970ToTime( (time_t)arg1, &time );
391 time.QuadPart += (DWORD)arg2 * 10;
392 proc( arg3, time.s.LowPart, time.s.HighPart );
393 break;
394 case APC_ASYNC_IO:
395 check_async_list( arg1, (DWORD) arg2 );
396 break;
397 default:
398 server_protocol_error( "get_apc_request: bad type %d\n", type );
399 break;
404 /* wait operations */
406 /******************************************************************
407 * NtWaitForMultipleObjects (NTDLL.@)
409 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
410 BOOLEAN wait_all, BOOLEAN alertable,
411 PLARGE_INTEGER timeout )
413 int ret, cookie;
415 if (count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
417 for (;;)
419 SERVER_START_REQ( select )
421 req->flags = SELECT_INTERRUPTIBLE;
422 req->cookie = &cookie;
423 NTDLL_get_server_timeout( &req->timeout, timeout );
424 wine_server_add_data( req, handles, count * sizeof(HANDLE) );
426 if (wait_all) req->flags |= SELECT_ALL;
427 if (alertable) req->flags |= SELECT_ALERTABLE;
428 if (timeout) req->flags |= SELECT_TIMEOUT;
430 ret = wine_server_call( req );
432 SERVER_END_REQ;
433 if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
434 if (ret != STATUS_USER_APC) break;
435 call_apcs( alertable );
436 if (alertable) break;
438 return ret;
442 /******************************************************************
443 * NtWaitForSingleObject (NTDLL.@)
445 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, PLARGE_INTEGER timeout )
447 return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );