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
27 #ifdef HAVE_SYS_TIME_H
28 # include <sys/time.h>
30 #ifdef HAVE_SYS_POLL_H
31 # include <sys/poll.h>
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
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);
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;
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;
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;
97 SERVER_START_REQ( open_semaphore )
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;
109 /******************************************************************************
110 * NtQuerySemaphore (NTDLL.@)
112 NTSTATUS WINAPI NtQuerySemaphore(
113 HANDLE SemaphoreHandle,
114 PVOID SemaphoreInformationClass,
115 OUT PVOID SemaphoreInformation,
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 )
130 SERVER_START_REQ( release_semaphore )
132 req->handle = handle;
134 if (!(ret = wine_server_call( req )))
136 if (previous) *previous = reply->prev_count;
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;
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;
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;
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;
199 /******************************************************************************
200 * NtSetEvent (NTDLL.@)
201 * ZwSetEvent (NTDLL.@)
203 NTSTATUS WINAPI NtSetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
207 /* FIXME: set NumberOfThreadsReleased */
209 SERVER_START_REQ( event_op )
211 req->handle = handle;
213 ret = wine_server_call( req );
219 /******************************************************************************
220 * NtResetEvent (NTDLL.@)
222 NTSTATUS WINAPI NtResetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
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 );
239 /******************************************************************************
240 * NtClearEvent (NTDLL.@)
243 * same as NtResetEvent ???
245 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
247 return NtResetEvent( handle, NULL );
250 /******************************************************************************
251 * NtPulseEvent (NTDLL.@)
256 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, PULONG PulseCount )
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 );
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 /***********************************************************************
288 * Process a status event from the server.
290 static void WINAPI check_async_list(async_private *asp, DWORD status)
295 for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
300 if( status != STATUS_ALERTED )
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 /***********************************************************************
317 * Wait for a reply on the waiting pipe of the current thread.
319 static int wait_reply( void *cookie )
322 struct wake_up_reply reply;
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 */
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");
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 /***********************************************************************
356 * Call outstanding APCs.
358 static void call_apcs( BOOL alertable )
362 void *arg1, *arg2, *arg3;
367 SERVER_START_REQ( get_apc )
369 req->alertable = alertable;
370 if (!wine_server_call( req )) type = reply->type;
381 return; /* no more APCs */
386 proc( arg1, arg2, arg3 );
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 );
395 check_async_list( arg1, (DWORD) arg2 );
398 server_protocol_error( "get_apc_request: bad type %d\n", type );
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 )
415 if (count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
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 );
433 if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
434 if (ret != STATUS_USER_APC) break;
435 call_apcs( alertable );
436 if (alertable) break;
442 /******************************************************************
443 * NtWaitForSingleObject (NTDLL.@)
445 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, PLARGE_INTEGER timeout )
447 return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );