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>
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
56 #include "wine/server.h"
57 #include "wine/unicode.h"
58 #include "wine/debug.h"
59 #include "ntdll_misc.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
68 /******************************************************************************
69 * NtCreateSemaphore (NTDLL.@)
71 NTSTATUS WINAPI NtCreateSemaphore( OUT PHANDLE SemaphoreHandle,
72 IN ACCESS_MASK access,
73 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
75 IN LONG MaximumCount )
77 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
80 if (MaximumCount <= 0 || InitialCount < 0 || InitialCount > MaximumCount)
81 return STATUS_INVALID_PARAMETER;
82 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
84 SERVER_START_REQ( create_semaphore )
87 req->initial = InitialCount;
88 req->max = MaximumCount;
89 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
90 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
91 ret = wine_server_call( req );
92 *SemaphoreHandle = reply->handle;
98 /******************************************************************************
99 * NtOpenSemaphore (NTDLL.@)
101 NTSTATUS WINAPI NtOpenSemaphore( OUT PHANDLE SemaphoreHandle,
102 IN ACCESS_MASK access,
103 IN const OBJECT_ATTRIBUTES *attr )
105 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
108 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
110 SERVER_START_REQ( open_semaphore )
112 req->access = access;
113 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
114 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
115 ret = wine_server_call( req );
116 *SemaphoreHandle = reply->handle;
122 /******************************************************************************
123 * NtQuerySemaphore (NTDLL.@)
125 NTSTATUS WINAPI NtQuerySemaphore(
126 HANDLE SemaphoreHandle,
127 PVOID SemaphoreInformationClass,
128 OUT PVOID SemaphoreInformation,
132 FIXME("(%p,%p,%p,0x%08lx,%p) stub!\n",
133 SemaphoreHandle, SemaphoreInformationClass, SemaphoreInformation, Length, ReturnLength);
134 return STATUS_SUCCESS;
137 /******************************************************************************
138 * NtReleaseSemaphore (NTDLL.@)
140 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
143 SERVER_START_REQ( release_semaphore )
145 req->handle = handle;
147 if (!(ret = wine_server_call( req )))
149 if (previous) *previous = reply->prev_count;
160 /**************************************************************************
161 * NtCreateEvent (NTDLL.@)
162 * ZwCreateEvent (NTDLL.@)
164 NTSTATUS WINAPI NtCreateEvent(
165 OUT PHANDLE EventHandle,
166 IN ACCESS_MASK DesiredAccess,
167 IN const OBJECT_ATTRIBUTES *attr,
168 IN BOOLEAN ManualReset,
169 IN BOOLEAN InitialState)
171 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
174 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
176 SERVER_START_REQ( create_event )
178 req->access = DesiredAccess;
179 req->manual_reset = ManualReset;
180 req->initial_state = InitialState;
181 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
182 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
183 ret = wine_server_call( req );
184 *EventHandle = reply->handle;
190 /******************************************************************************
191 * NtOpenEvent (NTDLL.@)
192 * ZwOpenEvent (NTDLL.@)
194 NTSTATUS WINAPI NtOpenEvent(
195 OUT PHANDLE EventHandle,
196 IN ACCESS_MASK DesiredAccess,
197 IN const OBJECT_ATTRIBUTES *attr )
199 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
202 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
204 SERVER_START_REQ( open_event )
206 req->access = DesiredAccess;
207 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
208 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
209 ret = wine_server_call( req );
210 *EventHandle = reply->handle;
217 /******************************************************************************
218 * NtSetEvent (NTDLL.@)
219 * ZwSetEvent (NTDLL.@)
221 NTSTATUS WINAPI NtSetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
225 /* FIXME: set NumberOfThreadsReleased */
227 SERVER_START_REQ( event_op )
229 req->handle = handle;
231 ret = wine_server_call( req );
237 /******************************************************************************
238 * NtResetEvent (NTDLL.@)
240 NTSTATUS WINAPI NtResetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
244 /* resetting an event can't release any thread... */
245 if (NumberOfThreadsReleased) *NumberOfThreadsReleased = 0;
247 SERVER_START_REQ( event_op )
249 req->handle = handle;
250 req->op = RESET_EVENT;
251 ret = wine_server_call( req );
257 /******************************************************************************
258 * NtClearEvent (NTDLL.@)
261 * same as NtResetEvent ???
263 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
265 return NtResetEvent( handle, NULL );
268 /******************************************************************************
269 * NtPulseEvent (NTDLL.@)
274 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, PULONG PulseCount )
279 FIXME("(%p,%ld)\n", handle, *PulseCount);
281 SERVER_START_REQ( event_op )
283 req->handle = handle;
284 req->op = PULSE_EVENT;
285 ret = wine_server_call( req );
291 /******************************************************************************
292 * NtQueryEvent (NTDLL.@)
294 NTSTATUS WINAPI NtQueryEvent (
295 IN HANDLE EventHandle,
296 IN UINT EventInformationClass,
297 OUT PVOID EventInformation,
298 IN ULONG EventInformationLength,
299 OUT PULONG ReturnLength)
301 FIXME("(%p)\n", EventHandle);
302 return STATUS_SUCCESS;
306 * Mutants (known as Mutexes in Kernel32)
309 /******************************************************************************
310 * NtCreateMutant [NTDLL.@]
311 * ZwCreateMutant [NTDLL.@]
313 NTSTATUS WINAPI NtCreateMutant(OUT HANDLE* MutantHandle,
314 IN ACCESS_MASK access,
315 IN const OBJECT_ATTRIBUTES* attr OPTIONAL,
316 IN BOOLEAN InitialOwner)
319 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
321 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
323 SERVER_START_REQ( create_mutex )
325 req->access = access;
326 req->owned = InitialOwner;
327 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
328 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
329 status = wine_server_call( req );
330 *MutantHandle = reply->handle;
336 /**************************************************************************
337 * NtOpenMutant [NTDLL.@]
338 * ZwOpenMutant [NTDLL.@]
340 NTSTATUS WINAPI NtOpenMutant(OUT HANDLE* MutantHandle,
341 IN ACCESS_MASK access,
342 IN const OBJECT_ATTRIBUTES* attr )
345 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
347 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
349 SERVER_START_REQ( open_mutex )
351 req->access = access;
352 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
353 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
354 status = wine_server_call( req );
355 *MutantHandle = reply->handle;
361 /**************************************************************************
362 * NtReleaseMutant [NTDLL.@]
363 * ZwReleaseMutant [NTDLL.@]
365 NTSTATUS WINAPI NtReleaseMutant( IN HANDLE handle, OUT PLONG prev_count OPTIONAL)
369 SERVER_START_REQ( release_mutex )
371 req->handle = handle;
372 status = wine_server_call( req );
373 if (prev_count) *prev_count = reply->prev_count;
379 /******************************************************************
380 * NtQueryMutant [NTDLL.@]
381 * ZwQueryMutant [NTDLL.@]
383 NTSTATUS WINAPI NtQueryMutant(IN HANDLE handle,
384 IN MUTANT_INFORMATION_CLASS MutantInformationClass,
385 OUT PVOID MutantInformation,
386 IN ULONG MutantInformationLength,
387 OUT PULONG ResultLength OPTIONAL )
389 FIXME("(%p %u %p %lu %p): stub!\n",
390 handle, MutantInformationClass, MutantInformation, MutantInformationLength, ResultLength);
391 return STATUS_NOT_IMPLEMENTED;
398 /**************************************************************************
399 * NtCreateTimer [NTDLL.@]
400 * ZwCreateTimer [NTDLL.@]
402 NTSTATUS WINAPI NtCreateTimer(OUT HANDLE *handle,
403 IN ACCESS_MASK access,
404 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
405 IN TIMER_TYPE timer_type)
407 DWORD len = (attr && attr->ObjectName) ? attr->ObjectName->Length : 0;
410 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
412 if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
413 return STATUS_INVALID_PARAMETER;
415 SERVER_START_REQ( create_timer )
417 req->access = access;
418 req->manual = (timer_type == NotificationTimer) ? TRUE : FALSE;
419 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
420 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
421 status = wine_server_call( req );
422 *handle = reply->handle;
429 /**************************************************************************
430 * NtOpenTimer [NTDLL.@]
431 * ZwOpenTimer [NTDLL.@]
433 NTSTATUS WINAPI NtOpenTimer(OUT PHANDLE handle,
434 IN ACCESS_MASK access,
435 IN const OBJECT_ATTRIBUTES* attr )
437 DWORD len = (attr && attr->ObjectName) ? attr->ObjectName->Length : 0;
440 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
442 SERVER_START_REQ( open_timer )
444 req->access = access;
445 req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
446 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
447 status = wine_server_call( req );
448 *handle = reply->handle;
454 /**************************************************************************
455 * NtSetTimer [NTDLL.@]
456 * ZwSetTimer [NTDLL.@]
458 NTSTATUS WINAPI NtSetTimer(IN HANDLE handle,
459 IN const LARGE_INTEGER* when,
460 IN PTIMERAPCROUTINE callback,
461 IN PVOID callback_arg,
463 IN ULONG period OPTIONAL,
464 OUT PBOOLEAN state OPTIONAL)
466 NTSTATUS status = STATUS_SUCCESS;
468 TRACE("(%p,%p,%p,%p,%08x,0x%08lx,%p) stub\n",
469 handle, when, callback, callback_arg, resume, period, state);
471 SERVER_START_REQ( set_timer )
473 if (!when->u.LowPart && !when->u.HighPart)
475 /* special case to start timeout on now+period without too many calculations */
477 req->expire.usec = 0;
479 else NTDLL_get_server_timeout( &req->expire, when );
481 req->handle = handle;
482 req->period = period;
483 req->callback = callback;
484 req->arg = callback_arg;
485 status = wine_server_call( req );
486 if (state) *state = reply->signaled;
490 /* set error but can still succeed */
491 if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
495 /**************************************************************************
496 * NtCancelTimer [NTDLL.@]
497 * ZwCancelTimer [NTDLL.@]
499 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
503 SERVER_START_REQ( cancel_timer )
505 req->handle = handle;
506 status = wine_server_call( req );
507 if (state) *state = reply->signaled;
513 /******************************************************************************
514 * NtQueryTimerResolution [NTDLL.@]
516 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
517 OUT ULONG* max_resolution,
518 OUT ULONG* current_resolution)
520 FIXME("(%p,%p,%p), stub!\n",
521 min_resolution, max_resolution, current_resolution);
523 return STATUS_NOT_IMPLEMENTED;
526 /******************************************************************************
527 * NtSetTimerResolution [NTDLL.@]
529 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
530 IN BOOLEAN set_resolution,
531 OUT ULONG* current_resolution )
533 FIXME("(%lu,%u,%p), stub!\n",
534 resolution, set_resolution, current_resolution);
536 return STATUS_NOT_IMPLEMENTED;
540 /***********************************************************************
543 * Process a status event from the server.
545 static void WINAPI check_async_list(async_private *asp, DWORD status)
550 for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
555 if( status != STATUS_ALERTED )
558 ovp->iosb->u.Status = status;
560 else ovp_status = ovp->iosb->u.Status;
562 if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
564 /* This will destroy all but PENDING requests */
565 register_old_async( ovp );
569 /***********************************************************************
572 * Wait for a reply on the waiting pipe of the current thread.
574 static int wait_reply( void *cookie )
577 struct wake_up_reply reply;
581 ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
582 if (ret == sizeof(reply))
584 if (!reply.cookie) break; /* thread got killed */
585 if (reply.cookie == cookie) return reply.signaled;
586 /* we stole another reply, wait for the real one */
587 signaled = wait_reply( cookie );
588 /* and now put the wrong one back in the pipe */
591 ret = write( NtCurrentTeb()->wait_fd[1], &reply, sizeof(reply) );
592 if (ret == sizeof(reply)) break;
593 if (ret >= 0) server_protocol_error( "partial wakeup write %d\n", ret );
594 if (errno == EINTR) continue;
595 server_protocol_perror("wakeup write");
599 if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret );
600 if (errno == EINTR) continue;
601 server_protocol_perror("wakeup read");
603 /* the server closed the connection; time to die... */
604 server_abort_thread(0);
608 /***********************************************************************
611 * Call outstanding APCs.
613 static void call_apcs( BOOL alertable )
617 void *arg1, *arg2, *arg3;
622 SERVER_START_REQ( get_apc )
624 req->alertable = alertable;
625 if (!wine_server_call( req )) type = reply->type;
636 return; /* no more APCs */
641 proc( arg1, arg2, arg3 );
644 /* convert sec/usec to NT time */
645 RtlSecondsSince1970ToTime( (time_t)arg1, &time );
646 time.QuadPart += (DWORD)arg2 * 10;
647 proc( arg3, time.u.LowPart, time.u.HighPart );
650 check_async_list( arg1, (DWORD) arg2 );
653 server_protocol_error( "get_apc_request: bad type %d\n", type );
660 /***********************************************************************
661 * NTDLL_wait_for_multiple_objects
663 * Implementation of NtWaitForMultipleObjects
665 NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UINT flags,
666 const LARGE_INTEGER *timeout )
671 if (timeout) flags |= SELECT_TIMEOUT;
674 SERVER_START_REQ( select )
677 req->cookie = &cookie;
678 NTDLL_get_server_timeout( &req->timeout, timeout );
679 wine_server_add_data( req, handles, count * sizeof(HANDLE) );
680 ret = wine_server_call( req );
683 if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
684 if (ret != STATUS_USER_APC) break;
685 call_apcs( (flags & SELECT_ALERTABLE) != 0 );
686 if (flags & SELECT_ALERTABLE) break;
689 /* A test on Windows 2000 shows that Windows always yields during
690 a wait, but a wait that is hit by an event gets a priority
691 boost as well. This seems to model that behavior the closest. */
692 if (ret == WAIT_TIMEOUT) NtYieldExecution();
698 /* wait operations */
700 /******************************************************************
701 * NtWaitForMultipleObjects (NTDLL.@)
703 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
704 BOOLEAN wait_all, BOOLEAN alertable,
705 const LARGE_INTEGER *timeout )
707 UINT flags = SELECT_INTERRUPTIBLE;
709 if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
711 if (wait_all) flags |= SELECT_ALL;
712 if (alertable) flags |= SELECT_ALERTABLE;
713 return NTDLL_wait_for_multiple_objects( count, handles, flags, timeout );
717 /******************************************************************
718 * NtWaitForSingleObject (NTDLL.@)
720 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
722 return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );
726 /******************************************************************
727 * NtYieldExecution (NTDLL.@)
729 NTSTATUS WINAPI NtYieldExecution(void)
731 #ifdef HAVE_SCHED_YIELD
733 return STATUS_SUCCESS;
735 return STATUS_NO_YIELD_PERFORMED;
740 /******************************************************************
741 * NtDelayExecution (NTDLL.@)
743 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
745 /* if alertable or async I/O in progress, we need to query the server */
746 if (alertable || NtCurrentTeb()->pending_list)
748 UINT flags = SELECT_INTERRUPTIBLE;
749 if (alertable) flags |= SELECT_ALERTABLE;
750 return NTDLL_wait_for_multiple_objects( 0, NULL, flags, timeout );
753 if (!timeout) /* sleep forever */
755 for (;;) select( 0, NULL, NULL, NULL, NULL );
761 NTDLL_get_server_timeout( &when, timeout );
763 /* Note that we yield after establishing the desired timeout */
769 gettimeofday( &tv, 0 );
770 tv.tv_sec = when.sec - tv.tv_sec;
771 if ((tv.tv_usec = when.usec - tv.tv_usec) < 0)
773 tv.tv_usec += 1000000;
776 /* if our yield already passed enough time, we're done */
777 if (tv.tv_sec < 0) break;
779 if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
782 return STATUS_SUCCESS;