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>
44 #define NONAMELESSUNION
45 #define NONAMELESSSTRUCT
53 #include "wine/server.h"
54 #include "wine/unicode.h"
55 #include "wine/debug.h"
56 #include "ntdll_misc.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
65 /******************************************************************************
66 * NtCreateSemaphore (NTDLL.@)
68 NTSTATUS WINAPI NtCreateSemaphore( OUT PHANDLE SemaphoreHandle,
69 IN ACCESS_MASK access,
70 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
71 IN ULONG InitialCount,
72 IN ULONG MaximumCount )
74 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
77 if ((MaximumCount <= 0) || (InitialCount > MaximumCount))
78 return STATUS_INVALID_PARAMETER;
80 SERVER_START_REQ( create_semaphore )
82 req->initial = InitialCount;
83 req->max = MaximumCount;
84 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
85 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
86 ret = wine_server_call( req );
87 *SemaphoreHandle = reply->handle;
93 /******************************************************************************
94 * NtOpenSemaphore (NTDLL.@)
96 NTSTATUS WINAPI NtOpenSemaphore( OUT PHANDLE SemaphoreHandle,
97 IN ACCESS_MASK access,
98 IN const OBJECT_ATTRIBUTES *attr )
100 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
103 SERVER_START_REQ( open_semaphore )
105 req->access = access;
106 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
107 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
108 ret = wine_server_call( req );
109 *SemaphoreHandle = reply->handle;
115 /******************************************************************************
116 * NtQuerySemaphore (NTDLL.@)
118 NTSTATUS WINAPI NtQuerySemaphore(
119 HANDLE SemaphoreHandle,
120 PVOID SemaphoreInformationClass,
121 OUT PVOID SemaphoreInformation,
125 FIXME("(%p,%p,%p,0x%08lx,%p) stub!\n",
126 SemaphoreHandle, SemaphoreInformationClass, SemaphoreInformation, Length, ReturnLength);
127 return STATUS_SUCCESS;
130 /******************************************************************************
131 * NtReleaseSemaphore (NTDLL.@)
133 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
136 SERVER_START_REQ( release_semaphore )
138 req->handle = handle;
140 if (!(ret = wine_server_call( req )))
142 if (previous) *previous = reply->prev_count;
153 /**************************************************************************
154 * NtCreateEvent (NTDLL.@)
155 * ZwCreateEvent (NTDLL.@)
157 NTSTATUS WINAPI NtCreateEvent(
158 OUT PHANDLE EventHandle,
159 IN ACCESS_MASK DesiredAccess,
160 IN const OBJECT_ATTRIBUTES *attr,
161 IN BOOLEAN ManualReset,
162 IN BOOLEAN InitialState)
164 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
167 SERVER_START_REQ( create_event )
169 req->manual_reset = ManualReset;
170 req->initial_state = InitialState;
171 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
172 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
173 ret = wine_server_call( req );
174 *EventHandle = reply->handle;
180 /******************************************************************************
181 * NtOpenEvent (NTDLL.@)
182 * ZwOpenEvent (NTDLL.@)
184 NTSTATUS WINAPI NtOpenEvent(
185 OUT PHANDLE EventHandle,
186 IN ACCESS_MASK DesiredAccess,
187 IN const OBJECT_ATTRIBUTES *attr )
189 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
192 SERVER_START_REQ( open_event )
194 req->access = DesiredAccess;
195 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
196 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
197 ret = wine_server_call( req );
198 *EventHandle = reply->handle;
205 /******************************************************************************
206 * NtSetEvent (NTDLL.@)
207 * ZwSetEvent (NTDLL.@)
209 NTSTATUS WINAPI NtSetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
213 /* FIXME: set NumberOfThreadsReleased */
215 SERVER_START_REQ( event_op )
217 req->handle = handle;
219 ret = wine_server_call( req );
225 /******************************************************************************
226 * NtResetEvent (NTDLL.@)
228 NTSTATUS WINAPI NtResetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
232 /* resetting an event can't release any thread... */
233 if (NumberOfThreadsReleased) *NumberOfThreadsReleased = 0;
235 SERVER_START_REQ( event_op )
237 req->handle = handle;
238 req->op = RESET_EVENT;
239 ret = wine_server_call( req );
245 /******************************************************************************
246 * NtClearEvent (NTDLL.@)
249 * same as NtResetEvent ???
251 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
253 return NtResetEvent( handle, NULL );
256 /******************************************************************************
257 * NtPulseEvent (NTDLL.@)
262 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, PULONG PulseCount )
267 FIXME("(%p,%ld)\n", handle, *PulseCount);
269 SERVER_START_REQ( event_op )
271 req->handle = handle;
272 req->op = PULSE_EVENT;
273 ret = wine_server_call( req );
279 /******************************************************************************
280 * NtQueryEvent (NTDLL.@)
282 NTSTATUS WINAPI NtQueryEvent (
283 IN HANDLE EventHandle,
284 IN UINT EventInformationClass,
285 OUT PVOID EventInformation,
286 IN ULONG EventInformationLength,
287 OUT PULONG ReturnLength)
289 FIXME("(%p)\n", EventHandle);
290 return STATUS_SUCCESS;
298 /**************************************************************************
299 * NtCreateTimer [NTDLL.@]
300 * ZwCreateTimer [NTDLL.@]
302 NTSTATUS WINAPI NtCreateTimer(OUT HANDLE *handle,
303 IN ACCESS_MASK access,
304 IN const OBJECT_ATTRIBUTES *oa OPTIONAL,
305 IN TIMER_TYPE timer_type)
307 DWORD len = (oa && oa->ObjectName) ? oa->ObjectName->Length : 0;
310 if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
311 return STATUS_INVALID_PARAMETER;
313 SERVER_START_REQ( create_timer )
315 req->manual = (timer_type == NotificationTimer) ? TRUE : FALSE;
316 req->inherit = oa && (oa->Attributes & OBJ_INHERIT);
317 if (len) wine_server_add_data( req, oa->ObjectName->Buffer, len );
318 status = wine_server_call( req );
319 *handle = reply->handle;
326 /**************************************************************************
327 * NtOpenTimer [NTDLL.@]
328 * ZwOpenTimer [NTDLL.@]
330 NTSTATUS WINAPI NtOpenTimer(OUT PHANDLE handle,
331 IN ACCESS_MASK access,
332 IN const OBJECT_ATTRIBUTES* oa )
334 DWORD len = (oa && oa->ObjectName) ? oa->ObjectName->Length : 0;
337 if (oa && oa->Length >= MAX_PATH * sizeof(WCHAR))
338 return STATUS_NAME_TOO_LONG;
340 SERVER_START_REQ( open_timer )
342 req->access = access;
343 req->inherit = oa && (oa->Attributes & OBJ_INHERIT);
344 if (len) wine_server_add_data( req, oa->ObjectName->Buffer, len );
345 status = wine_server_call( req );
346 *handle = reply->handle;
352 /**************************************************************************
353 * NtSetTimer [NTDLL.@]
354 * ZwSetTimer [NTDLL.@]
356 NTSTATUS WINAPI NtSetTimer(IN HANDLE handle,
357 IN const LARGE_INTEGER* when,
358 IN PTIMERAPCROUTINE callback,
359 IN PVOID callback_arg,
361 IN ULONG period OPTIONAL,
362 OUT PBOOLEAN state OPTIONAL)
364 NTSTATUS status = STATUS_SUCCESS;
366 TRACE("(%p,%p,%p,%p,%08x,0x%08lx,%p) stub\n",
367 handle, when, callback, callback_arg, resume, period, state);
369 SERVER_START_REQ( set_timer )
371 if (!when->u.LowPart && !when->u.HighPart)
373 /* special case to start timeout on now+period without too many calculations */
375 req->expire.usec = 0;
377 else NTDLL_get_server_timeout( &req->expire, when );
379 req->handle = handle;
380 req->period = period;
381 req->callback = callback;
382 req->arg = callback_arg;
383 status = wine_server_call( req );
384 if (state) *state = reply->signaled;
388 /* set error but can still succeed */
389 if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
393 /**************************************************************************
394 * NtCancelTimer [NTDLL.@]
395 * ZwCancelTimer [NTDLL.@]
397 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
401 SERVER_START_REQ( cancel_timer )
403 req->handle = handle;
404 status = wine_server_call( req );
405 if (state) *state = reply->signaled;
411 /******************************************************************************
412 * NtQueryTimerResolution [NTDLL.@]
414 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
415 OUT ULONG* max_resolution,
416 OUT ULONG* current_resolution)
418 FIXME("(%p,%p,%p), stub!\n",
419 min_resolution, max_resolution, current_resolution);
421 return STATUS_NOT_IMPLEMENTED;
424 /******************************************************************************
425 * NtSetTimerResolution [NTDLL.@]
427 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
428 IN BOOLEAN set_resolution,
429 OUT ULONG* current_resolution )
431 FIXME("(%lu,%u,%p), stub!\n",
432 resolution, set_resolution, current_resolution);
434 return STATUS_NOT_IMPLEMENTED;
438 /***********************************************************************
441 * Process a status event from the server.
443 static void WINAPI check_async_list(async_private *asp, DWORD status)
448 for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
453 if( status != STATUS_ALERTED )
456 ovp->iosb->u.Status = status;
458 else ovp_status = ovp->iosb->u.Status;
460 if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
462 /* This will destroy all but PENDING requests */
463 register_old_async( ovp );
467 /***********************************************************************
470 * Wait for a reply on the waiting pipe of the current thread.
472 static int wait_reply( void *cookie )
475 struct wake_up_reply reply;
479 ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
480 if (ret == sizeof(reply))
482 if (!reply.cookie) break; /* thread got killed */
483 if (reply.cookie == cookie) return reply.signaled;
484 /* we stole another reply, wait for the real one */
485 signaled = wait_reply( cookie );
486 /* and now put the wrong one back in the pipe */
489 ret = write( NtCurrentTeb()->wait_fd[1], &reply, sizeof(reply) );
490 if (ret == sizeof(reply)) break;
491 if (ret >= 0) server_protocol_error( "partial wakeup write %d\n", ret );
492 if (errno == EINTR) continue;
493 server_protocol_perror("wakeup write");
497 if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret );
498 if (errno == EINTR) continue;
499 server_protocol_perror("wakeup read");
501 /* the server closed the connection; time to die... */
502 server_abort_thread(0);
506 /***********************************************************************
509 * Call outstanding APCs.
511 static void call_apcs( BOOL alertable )
515 void *arg1, *arg2, *arg3;
520 SERVER_START_REQ( get_apc )
522 req->alertable = alertable;
523 if (!wine_server_call( req )) type = reply->type;
534 return; /* no more APCs */
539 proc( arg1, arg2, arg3 );
542 /* convert sec/usec to NT time */
543 RtlSecondsSince1970ToTime( (time_t)arg1, &time );
544 time.QuadPart += (DWORD)arg2 * 10;
545 proc( arg3, time.u.LowPart, time.u.HighPart );
548 check_async_list( arg1, (DWORD) arg2 );
551 server_protocol_error( "get_apc_request: bad type %d\n", type );
558 /***********************************************************************
559 * NTDLL_wait_for_multiple_objects
561 * Implementation of NtWaitForMultipleObjects
563 NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UINT flags,
564 const LARGE_INTEGER *timeout )
569 if (timeout) flags |= SELECT_TIMEOUT;
572 SERVER_START_REQ( select )
575 req->cookie = &cookie;
576 NTDLL_get_server_timeout( &req->timeout, timeout );
577 wine_server_add_data( req, handles, count * sizeof(HANDLE) );
578 ret = wine_server_call( req );
581 if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
582 if (ret != STATUS_USER_APC) break;
583 call_apcs( (flags & SELECT_ALERTABLE) != 0 );
584 if (flags & SELECT_ALERTABLE) break;
590 /* wait operations */
592 /******************************************************************
593 * NtWaitForMultipleObjects (NTDLL.@)
595 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
596 BOOLEAN wait_all, BOOLEAN alertable,
597 const LARGE_INTEGER *timeout )
599 UINT flags = SELECT_INTERRUPTIBLE;
601 if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
603 if (wait_all) flags |= SELECT_ALL;
604 if (alertable) flags |= SELECT_ALERTABLE;
605 return NTDLL_wait_for_multiple_objects( count, handles, flags, timeout );
609 /******************************************************************
610 * NtWaitForSingleObject (NTDLL.@)
612 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
614 return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );
618 /******************************************************************
619 * NtDelayExecution (NTDLL.@)
621 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
623 /* if alertable or async I/O in progress, we need to query the server */
624 if (alertable || NtCurrentTeb()->pending_list)
626 UINT flags = SELECT_INTERRUPTIBLE;
627 if (alertable) flags |= SELECT_ALERTABLE;
628 return NTDLL_wait_for_multiple_objects( 0, NULL, flags, timeout );
631 if (!timeout) /* sleep forever */
633 for (;;) select( 0, NULL, NULL, NULL, NULL );
639 NTDLL_get_server_timeout( &when, timeout );
643 gettimeofday( &tv, 0 );
644 tv.tv_sec = when.sec - tv.tv_sec;
645 if ((tv.tv_usec = when.usec - tv.tv_usec) < 0)
647 tv.tv_usec += 1000000;
650 if (tv.tv_sec < 0) tv.tv_sec = tv.tv_usec = 0;
651 if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
654 return STATUS_SUCCESS;