2 * Process synchronisation
4 * Copyright 1996, 1997, 1998 Marcus Meissner
5 * Copyright 1997, 1999 Alexandre Julliard
6 * Copyright 1999, 2000 Juergen Schmied
7 * Copyright 2003 Eric Pouech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #ifdef HAVE_SYS_TIME_H
30 # include <sys/time.h>
32 #ifdef HAVE_SYS_POLL_H
33 # include <sys/poll.h>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
49 #include "wine/server.h"
50 #include "wine/unicode.h"
51 #include "wine/debug.h"
52 #include "ntdll_misc.h"
54 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
61 /******************************************************************************
62 * NtCreateSemaphore (NTDLL.@)
64 NTSTATUS WINAPI NtCreateSemaphore( OUT PHANDLE SemaphoreHandle,
65 IN ACCESS_MASK access,
66 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
67 IN ULONG InitialCount,
68 IN ULONG MaximumCount )
70 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
73 if ((MaximumCount <= 0) || (InitialCount > MaximumCount))
74 return STATUS_INVALID_PARAMETER;
76 SERVER_START_REQ( create_semaphore )
78 req->initial = InitialCount;
79 req->max = MaximumCount;
80 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
81 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
82 ret = wine_server_call( req );
83 *SemaphoreHandle = reply->handle;
89 /******************************************************************************
90 * NtOpenSemaphore (NTDLL.@)
92 NTSTATUS WINAPI NtOpenSemaphore( OUT PHANDLE SemaphoreHandle,
93 IN ACCESS_MASK access,
94 IN const OBJECT_ATTRIBUTES *attr )
96 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
99 SERVER_START_REQ( open_semaphore )
101 req->access = access;
102 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
103 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
104 ret = wine_server_call( req );
105 *SemaphoreHandle = reply->handle;
111 /******************************************************************************
112 * NtQuerySemaphore (NTDLL.@)
114 NTSTATUS WINAPI NtQuerySemaphore(
115 HANDLE SemaphoreHandle,
116 PVOID SemaphoreInformationClass,
117 OUT PVOID SemaphoreInformation,
121 FIXME("(%p,%p,%p,0x%08lx,%p) stub!\n",
122 SemaphoreHandle, SemaphoreInformationClass, SemaphoreInformation, Length, ReturnLength);
123 return STATUS_SUCCESS;
126 /******************************************************************************
127 * NtReleaseSemaphore (NTDLL.@)
129 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
132 SERVER_START_REQ( release_semaphore )
134 req->handle = handle;
136 if (!(ret = wine_server_call( req )))
138 if (previous) *previous = reply->prev_count;
149 /**************************************************************************
150 * NtCreateEvent (NTDLL.@)
151 * ZwCreateEvent (NTDLL.@)
153 NTSTATUS WINAPI NtCreateEvent(
154 OUT PHANDLE EventHandle,
155 IN ACCESS_MASK DesiredAccess,
156 IN const OBJECT_ATTRIBUTES *attr,
157 IN BOOLEAN ManualReset,
158 IN BOOLEAN InitialState)
160 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
163 SERVER_START_REQ( create_event )
165 req->manual_reset = ManualReset;
166 req->initial_state = InitialState;
167 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
168 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
169 ret = wine_server_call( req );
170 *EventHandle = reply->handle;
176 /******************************************************************************
177 * NtOpenEvent (NTDLL.@)
178 * ZwOpenEvent (NTDLL.@)
180 NTSTATUS WINAPI NtOpenEvent(
181 OUT PHANDLE EventHandle,
182 IN ACCESS_MASK DesiredAccess,
183 IN const OBJECT_ATTRIBUTES *attr )
185 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
188 SERVER_START_REQ( open_event )
190 req->access = DesiredAccess;
191 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
192 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
193 ret = wine_server_call( req );
194 *EventHandle = reply->handle;
201 /******************************************************************************
202 * NtSetEvent (NTDLL.@)
203 * ZwSetEvent (NTDLL.@)
205 NTSTATUS WINAPI NtSetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
209 /* FIXME: set NumberOfThreadsReleased */
211 SERVER_START_REQ( event_op )
213 req->handle = handle;
215 ret = wine_server_call( req );
221 /******************************************************************************
222 * NtResetEvent (NTDLL.@)
224 NTSTATUS WINAPI NtResetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
228 /* resetting an event can't release any thread... */
229 if (NumberOfThreadsReleased) *NumberOfThreadsReleased = 0;
231 SERVER_START_REQ( event_op )
233 req->handle = handle;
234 req->op = RESET_EVENT;
235 ret = wine_server_call( req );
241 /******************************************************************************
242 * NtClearEvent (NTDLL.@)
245 * same as NtResetEvent ???
247 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
249 return NtResetEvent( handle, NULL );
252 /******************************************************************************
253 * NtPulseEvent (NTDLL.@)
258 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, PULONG PulseCount )
261 FIXME("(%p,%p)\n", handle, PulseCount);
262 SERVER_START_REQ( event_op )
264 req->handle = handle;
265 req->op = PULSE_EVENT;
266 ret = wine_server_call( req );
272 /******************************************************************************
273 * NtQueryEvent (NTDLL.@)
275 NTSTATUS WINAPI NtQueryEvent (
276 IN HANDLE EventHandle,
277 IN UINT EventInformationClass,
278 OUT PVOID EventInformation,
279 IN ULONG EventInformationLength,
280 OUT PULONG ReturnLength)
282 FIXME("(%p)\n", EventHandle);
283 return STATUS_SUCCESS;
291 /**************************************************************************
292 * NtCreateTimer [NTDLL.@]
293 * ZwCreateTimer [NTDLL.@]
295 NTSTATUS WINAPI NtCreateTimer(OUT HANDLE *handle,
296 IN ACCESS_MASK access,
297 IN const OBJECT_ATTRIBUTES *oa OPTIONAL,
298 IN TIMER_TYPE timer_type)
300 DWORD len = (oa && oa->ObjectName) ? oa->ObjectName->Length : 0;
303 if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
304 return STATUS_INVALID_PARAMETER;
306 SERVER_START_REQ( create_timer )
308 req->manual = (timer_type == NotificationTimer) ? TRUE : FALSE;
309 req->inherit = oa && (oa->Attributes & OBJ_INHERIT);
310 if (len) wine_server_add_data( req, oa->ObjectName->Buffer, len );
311 status = wine_server_call( req );
312 *handle = reply->handle;
319 /**************************************************************************
320 * NtOpenTimer [NTDLL.@]
321 * ZwOpenTimer [NTDLL.@]
323 NTSTATUS WINAPI NtOpenTimer(OUT PHANDLE handle,
324 IN ACCESS_MASK access,
325 IN const OBJECT_ATTRIBUTES* oa )
327 DWORD len = (oa && oa->ObjectName) ? oa->ObjectName->Length : 0;
330 if (oa && oa->Length >= MAX_PATH * sizeof(WCHAR))
331 return STATUS_NAME_TOO_LONG;
333 SERVER_START_REQ( open_timer )
335 req->access = access;
336 req->inherit = oa && (oa->Attributes & OBJ_INHERIT);
337 if (len) wine_server_add_data( req, oa->ObjectName->Buffer, len );
338 status = wine_server_call( req );
339 *handle = reply->handle;
345 /**************************************************************************
346 * NtSetTimer [NTDLL.@]
347 * ZwSetTimer [NTDLL.@]
349 NTSTATUS WINAPI NtSetTimer(IN HANDLE handle,
350 IN const LARGE_INTEGER* when,
351 IN PTIMERAPCROUTINE callback,
352 IN PVOID callback_arg,
354 IN ULONG period OPTIONAL,
355 OUT PBOOLEAN state OPTIONAL)
357 NTSTATUS status = STATUS_SUCCESS;
359 TRACE("(%p,%p,%p,%p,%08x,0x%08lx,%p) stub\n",
360 handle, when, callback, callback_arg, resume, period, state);
362 SERVER_START_REQ( set_timer )
364 if (!when->s.LowPart && !when->s.HighPart)
366 /* special case to start timeout on now+period without too many calculations */
368 req->expire.usec = 0;
370 else NTDLL_get_server_timeout( &req->expire, when );
372 req->handle = handle;
373 req->period = period;
374 req->callback = callback;
375 req->arg = callback_arg;
376 status = wine_server_call( req );
377 if (state) *state = reply->signaled;
381 /* set error but can still succeed */
382 if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
386 /**************************************************************************
387 * NtCancelTimer [NTDLL.@]
388 * ZwCancelTimer [NTDLL.@]
390 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
394 SERVER_START_REQ( cancel_timer )
396 req->handle = handle;
397 status = wine_server_call( req );
398 if (state) *state = reply->signaled;
404 /******************************************************************************
405 * NtQueryTimerResolution [NTDLL.@]
407 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
408 OUT ULONG* max_resolution,
409 OUT ULONG* current_resolution)
411 FIXME("(%p,%p,%p), stub!\n",
412 min_resolution, max_resolution, current_resolution);
414 return STATUS_NOT_IMPLEMENTED;
417 /******************************************************************************
418 * NtSetTimerResolution [NTDLL.@]
420 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
421 IN BOOLEAN set_resolution,
422 OUT ULONG* current_resolution )
424 FIXME("(%lu,%u,%p), stub!\n",
425 resolution, set_resolution, current_resolution);
427 return STATUS_NOT_IMPLEMENTED;
431 /***********************************************************************
434 * Process a status event from the server.
436 static void WINAPI check_async_list(async_private *asp, DWORD status)
441 for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
446 if( status != STATUS_ALERTED )
449 ovp->ops->set_status (ovp, status);
451 else ovp_status = ovp->ops->get_status (ovp);
453 if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
455 /* This will destroy all but PENDING requests */
456 register_old_async( ovp );
460 /***********************************************************************
463 * Wait for a reply on the waiting pipe of the current thread.
465 static int wait_reply( void *cookie )
468 struct wake_up_reply reply;
472 ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
473 if (ret == sizeof(reply))
475 if (!reply.cookie) break; /* thread got killed */
476 if (reply.cookie == cookie) return reply.signaled;
477 /* we stole another reply, wait for the real one */
478 signaled = wait_reply( cookie );
479 /* and now put the wrong one back in the pipe */
482 ret = write( NtCurrentTeb()->wait_fd[1], &reply, sizeof(reply) );
483 if (ret == sizeof(reply)) break;
484 if (ret >= 0) server_protocol_error( "partial wakeup write %d\n", ret );
485 if (errno == EINTR) continue;
486 server_protocol_perror("wakeup write");
490 if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret );
491 if (errno == EINTR) continue;
492 server_protocol_perror("wakeup read");
494 /* the server closed the connection; time to die... */
495 SYSDEPS_AbortThread(0);
499 /***********************************************************************
502 * Call outstanding APCs.
504 static void call_apcs( BOOL alertable )
508 void *arg1, *arg2, *arg3;
513 SERVER_START_REQ( get_apc )
515 req->alertable = alertable;
516 if (!wine_server_call( req )) type = reply->type;
527 return; /* no more APCs */
532 proc( arg1, arg2, arg3 );
535 /* convert sec/usec to NT time */
536 RtlSecondsSince1970ToTime( (time_t)arg1, &time );
537 time.QuadPart += (DWORD)arg2 * 10;
538 proc( arg3, time.s.LowPart, time.s.HighPart );
541 check_async_list( arg1, (DWORD) arg2 );
544 server_protocol_error( "get_apc_request: bad type %d\n", type );
550 /* wait operations */
552 /******************************************************************
553 * NtWaitForMultipleObjects (NTDLL.@)
555 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
556 BOOLEAN wait_all, BOOLEAN alertable,
557 PLARGE_INTEGER timeout )
561 if (count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
565 SERVER_START_REQ( select )
567 req->flags = SELECT_INTERRUPTIBLE;
568 req->cookie = &cookie;
569 NTDLL_get_server_timeout( &req->timeout, timeout );
570 wine_server_add_data( req, handles, count * sizeof(HANDLE) );
572 if (wait_all) req->flags |= SELECT_ALL;
573 if (alertable) req->flags |= SELECT_ALERTABLE;
574 if (timeout) req->flags |= SELECT_TIMEOUT;
576 ret = wine_server_call( req );
579 if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
580 if (ret != STATUS_USER_APC) break;
581 call_apcs( alertable );
582 if (alertable) break;
588 /******************************************************************
589 * NtWaitForSingleObject (NTDLL.@)
591 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, PLARGE_INTEGER timeout )
593 return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );