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>
35 #ifdef HAVE_SYS_POLL_H
36 # include <sys/poll.h>
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
55 #include "wine/server.h"
56 #include "wine/debug.h"
57 #include "ntdll_misc.h"
59 WINE_DEFAULT_DEBUG_CHANNEL(ntdll
);
66 /******************************************************************************
67 * NtCreateSemaphore (NTDLL.@)
69 NTSTATUS WINAPI
NtCreateSemaphore( OUT PHANDLE SemaphoreHandle
,
70 IN ACCESS_MASK access
,
71 IN
const OBJECT_ATTRIBUTES
*attr OPTIONAL
,
73 IN LONG MaximumCount
)
75 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
78 if (MaximumCount
<= 0 || InitialCount
< 0 || InitialCount
> MaximumCount
)
79 return STATUS_INVALID_PARAMETER
;
80 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
82 SERVER_START_REQ( create_semaphore
)
85 req
->initial
= InitialCount
;
86 req
->max
= MaximumCount
;
87 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
88 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
89 ret
= wine_server_call( req
);
90 *SemaphoreHandle
= reply
->handle
;
96 /******************************************************************************
97 * NtOpenSemaphore (NTDLL.@)
99 NTSTATUS WINAPI
NtOpenSemaphore( OUT PHANDLE SemaphoreHandle
,
100 IN ACCESS_MASK access
,
101 IN
const OBJECT_ATTRIBUTES
*attr
)
103 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
106 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
108 SERVER_START_REQ( open_semaphore
)
110 req
->access
= access
;
111 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
112 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
113 ret
= wine_server_call( req
);
114 *SemaphoreHandle
= reply
->handle
;
120 /******************************************************************************
121 * NtQuerySemaphore (NTDLL.@)
123 NTSTATUS WINAPI
NtQuerySemaphore(
124 HANDLE SemaphoreHandle
,
125 SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass
,
126 PVOID SemaphoreInformation
,
130 FIXME("(%p,%d,%p,0x%08lx,%p) stub!\n",
131 SemaphoreHandle
, SemaphoreInformationClass
, SemaphoreInformation
, Length
, ReturnLength
);
132 return STATUS_SUCCESS
;
135 /******************************************************************************
136 * NtReleaseSemaphore (NTDLL.@)
138 NTSTATUS WINAPI
NtReleaseSemaphore( HANDLE handle
, ULONG count
, PULONG previous
)
141 SERVER_START_REQ( release_semaphore
)
143 req
->handle
= handle
;
145 if (!(ret
= wine_server_call( req
)))
147 if (previous
) *previous
= reply
->prev_count
;
158 /**************************************************************************
159 * NtCreateEvent (NTDLL.@)
160 * ZwCreateEvent (NTDLL.@)
162 NTSTATUS WINAPI
NtCreateEvent(
163 OUT PHANDLE EventHandle
,
164 IN ACCESS_MASK DesiredAccess
,
165 IN
const OBJECT_ATTRIBUTES
*attr
,
166 IN BOOLEAN ManualReset
,
167 IN BOOLEAN InitialState
)
169 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
172 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
174 SERVER_START_REQ( create_event
)
176 req
->access
= DesiredAccess
;
177 req
->manual_reset
= ManualReset
;
178 req
->initial_state
= InitialState
;
179 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
180 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
181 ret
= wine_server_call( req
);
182 *EventHandle
= reply
->handle
;
188 /******************************************************************************
189 * NtOpenEvent (NTDLL.@)
190 * ZwOpenEvent (NTDLL.@)
192 NTSTATUS WINAPI
NtOpenEvent(
193 OUT PHANDLE EventHandle
,
194 IN ACCESS_MASK DesiredAccess
,
195 IN
const OBJECT_ATTRIBUTES
*attr
)
197 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
200 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
202 SERVER_START_REQ( open_event
)
204 req
->access
= DesiredAccess
;
205 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
206 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
207 ret
= wine_server_call( req
);
208 *EventHandle
= reply
->handle
;
215 /******************************************************************************
216 * NtSetEvent (NTDLL.@)
217 * ZwSetEvent (NTDLL.@)
219 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
223 /* FIXME: set NumberOfThreadsReleased */
225 SERVER_START_REQ( event_op
)
227 req
->handle
= handle
;
229 ret
= wine_server_call( req
);
235 /******************************************************************************
236 * NtResetEvent (NTDLL.@)
238 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
242 /* resetting an event can't release any thread... */
243 if (NumberOfThreadsReleased
) *NumberOfThreadsReleased
= 0;
245 SERVER_START_REQ( event_op
)
247 req
->handle
= handle
;
248 req
->op
= RESET_EVENT
;
249 ret
= wine_server_call( req
);
255 /******************************************************************************
256 * NtClearEvent (NTDLL.@)
259 * same as NtResetEvent ???
261 NTSTATUS WINAPI
NtClearEvent ( HANDLE handle
)
263 return NtResetEvent( handle
, NULL
);
266 /******************************************************************************
267 * NtPulseEvent (NTDLL.@)
272 NTSTATUS WINAPI
NtPulseEvent( HANDLE handle
, PULONG PulseCount
)
277 FIXME("(%p,%ld)\n", handle
, *PulseCount
);
279 SERVER_START_REQ( event_op
)
281 req
->handle
= handle
;
282 req
->op
= PULSE_EVENT
;
283 ret
= wine_server_call( req
);
289 /******************************************************************************
290 * NtQueryEvent (NTDLL.@)
292 NTSTATUS WINAPI
NtQueryEvent (
293 IN HANDLE EventHandle
,
294 IN UINT EventInformationClass
,
295 OUT PVOID EventInformation
,
296 IN ULONG EventInformationLength
,
297 OUT PULONG ReturnLength
)
299 FIXME("(%p)\n", EventHandle
);
300 return STATUS_SUCCESS
;
304 * Mutants (known as Mutexes in Kernel32)
307 /******************************************************************************
308 * NtCreateMutant [NTDLL.@]
309 * ZwCreateMutant [NTDLL.@]
311 NTSTATUS WINAPI
NtCreateMutant(OUT HANDLE
* MutantHandle
,
312 IN ACCESS_MASK access
,
313 IN
const OBJECT_ATTRIBUTES
* attr OPTIONAL
,
314 IN BOOLEAN InitialOwner
)
317 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
319 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
321 SERVER_START_REQ( create_mutex
)
323 req
->access
= access
;
324 req
->owned
= InitialOwner
;
325 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
326 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
327 status
= wine_server_call( req
);
328 *MutantHandle
= reply
->handle
;
334 /**************************************************************************
335 * NtOpenMutant [NTDLL.@]
336 * ZwOpenMutant [NTDLL.@]
338 NTSTATUS WINAPI
NtOpenMutant(OUT HANDLE
* MutantHandle
,
339 IN ACCESS_MASK access
,
340 IN
const OBJECT_ATTRIBUTES
* attr
)
343 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
345 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
347 SERVER_START_REQ( open_mutex
)
349 req
->access
= access
;
350 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
351 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
352 status
= wine_server_call( req
);
353 *MutantHandle
= reply
->handle
;
359 /**************************************************************************
360 * NtReleaseMutant [NTDLL.@]
361 * ZwReleaseMutant [NTDLL.@]
363 NTSTATUS WINAPI
NtReleaseMutant( IN HANDLE handle
, OUT PLONG prev_count OPTIONAL
)
367 SERVER_START_REQ( release_mutex
)
369 req
->handle
= handle
;
370 status
= wine_server_call( req
);
371 if (prev_count
) *prev_count
= reply
->prev_count
;
377 /******************************************************************
378 * NtQueryMutant [NTDLL.@]
379 * ZwQueryMutant [NTDLL.@]
381 NTSTATUS WINAPI
NtQueryMutant(IN HANDLE handle
,
382 IN MUTANT_INFORMATION_CLASS MutantInformationClass
,
383 OUT PVOID MutantInformation
,
384 IN ULONG MutantInformationLength
,
385 OUT PULONG ResultLength OPTIONAL
)
387 FIXME("(%p %u %p %lu %p): stub!\n",
388 handle
, MutantInformationClass
, MutantInformation
, MutantInformationLength
, ResultLength
);
389 return STATUS_NOT_IMPLEMENTED
;
396 /**************************************************************************
397 * NtCreateTimer [NTDLL.@]
398 * ZwCreateTimer [NTDLL.@]
400 NTSTATUS WINAPI
NtCreateTimer(OUT HANDLE
*handle
,
401 IN ACCESS_MASK access
,
402 IN
const OBJECT_ATTRIBUTES
*attr OPTIONAL
,
403 IN TIMER_TYPE timer_type
)
405 DWORD len
= (attr
&& attr
->ObjectName
) ? attr
->ObjectName
->Length
: 0;
408 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
410 if (timer_type
!= NotificationTimer
&& timer_type
!= SynchronizationTimer
)
411 return STATUS_INVALID_PARAMETER
;
413 SERVER_START_REQ( create_timer
)
415 req
->access
= access
;
416 req
->manual
= (timer_type
== NotificationTimer
) ? TRUE
: FALSE
;
417 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
418 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
419 status
= wine_server_call( req
);
420 *handle
= reply
->handle
;
427 /**************************************************************************
428 * NtOpenTimer [NTDLL.@]
429 * ZwOpenTimer [NTDLL.@]
431 NTSTATUS WINAPI
NtOpenTimer(OUT PHANDLE handle
,
432 IN ACCESS_MASK access
,
433 IN
const OBJECT_ATTRIBUTES
* attr
)
435 DWORD len
= (attr
&& attr
->ObjectName
) ? attr
->ObjectName
->Length
: 0;
438 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
440 SERVER_START_REQ( open_timer
)
442 req
->access
= access
;
443 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
444 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
445 status
= wine_server_call( req
);
446 *handle
= reply
->handle
;
452 /**************************************************************************
453 * NtSetTimer [NTDLL.@]
454 * ZwSetTimer [NTDLL.@]
456 NTSTATUS WINAPI
NtSetTimer(IN HANDLE handle
,
457 IN
const LARGE_INTEGER
* when
,
458 IN PTIMER_APC_ROUTINE callback
,
459 IN PVOID callback_arg
,
461 IN ULONG period OPTIONAL
,
462 OUT PBOOLEAN state OPTIONAL
)
464 NTSTATUS status
= STATUS_SUCCESS
;
466 TRACE("(%p,%p,%p,%p,%08x,0x%08lx,%p) stub\n",
467 handle
, when
, callback
, callback_arg
, resume
, period
, state
);
469 SERVER_START_REQ( set_timer
)
471 if (!when
->u
.LowPart
&& !when
->u
.HighPart
)
473 /* special case to start timeout on now+period without too many calculations */
475 req
->expire
.usec
= 0;
477 else NTDLL_get_server_timeout( &req
->expire
, when
);
479 req
->handle
= handle
;
480 req
->period
= period
;
481 req
->callback
= callback
;
482 req
->arg
= callback_arg
;
483 status
= wine_server_call( req
);
484 if (state
) *state
= reply
->signaled
;
488 /* set error but can still succeed */
489 if (resume
&& status
== STATUS_SUCCESS
) return STATUS_TIMER_RESUME_IGNORED
;
493 /**************************************************************************
494 * NtCancelTimer [NTDLL.@]
495 * ZwCancelTimer [NTDLL.@]
497 NTSTATUS WINAPI
NtCancelTimer(IN HANDLE handle
, OUT BOOLEAN
* state
)
501 SERVER_START_REQ( cancel_timer
)
503 req
->handle
= handle
;
504 status
= wine_server_call( req
);
505 if (state
) *state
= reply
->signaled
;
511 /******************************************************************************
512 * NtQueryTimer (NTDLL.@)
514 * Retrieves information about a timer.
517 * TimerHandle [I] The timer to retrieve information about.
518 * TimerInformationClass [I] The type of information to retrieve.
519 * TimerInformation [O] Pointer to buffer to store information in.
520 * Length [I] The length of the buffer pointed to by TimerInformation.
521 * ReturnLength [O] Optional. The size of buffer actually used.
524 * Success: STATUS_SUCCESS
525 * Failure: STATUS_INFO_LENGTH_MISMATCH, if Length doesn't match the required data
526 * size for the class specified.
527 * STATUS_INVALID_INFO_CLASS, if an invalid TimerInformationClass was specified.
528 * STATUS_ACCESS_DENIED, if TimerHandle does not have TIMER_QUERY_STATE access
531 NTSTATUS WINAPI
NtQueryTimer(
533 TIMER_INFORMATION_CLASS TimerInformationClass
,
534 PVOID TimerInformation
,
538 TIMER_BASIC_INFORMATION
* basic_info
= (TIMER_BASIC_INFORMATION
*)TimerInformation
;
542 TRACE("(%p,%d,%p,0x%08lx,%p)\n", TimerHandle
, TimerInformationClass
,
543 TimerInformation
, Length
, ReturnLength
);
545 switch (TimerInformationClass
)
547 case TimerBasicInformation
:
548 if (Length
< sizeof(TIMER_BASIC_INFORMATION
))
549 return STATUS_INFO_LENGTH_MISMATCH
;
551 SERVER_START_REQ(get_timer_info
)
553 req
->handle
= TimerHandle
;
554 status
= wine_server_call(req
);
556 /* convert server time to absolute NTDLL time */
557 NTDLL_from_server_timeout(&basic_info
->RemainingTime
, &reply
->when
);
558 basic_info
->TimerState
= reply
->signaled
;
562 /* convert from absolute into relative time */
563 NtQuerySystemTime(&now
);
564 if (now
.QuadPart
> basic_info
->RemainingTime
.QuadPart
)
565 basic_info
->RemainingTime
.QuadPart
= 0;
567 basic_info
->RemainingTime
.QuadPart
-= now
.QuadPart
;
569 if (ReturnLength
) *ReturnLength
= sizeof(TIMER_BASIC_INFORMATION
);
574 FIXME("Unhandled class %d\n", TimerInformationClass
);
575 return STATUS_INVALID_INFO_CLASS
;
579 /******************************************************************************
580 * NtQueryTimerResolution [NTDLL.@]
582 NTSTATUS WINAPI
NtQueryTimerResolution(OUT ULONG
* min_resolution
,
583 OUT ULONG
* max_resolution
,
584 OUT ULONG
* current_resolution
)
586 FIXME("(%p,%p,%p), stub!\n",
587 min_resolution
, max_resolution
, current_resolution
);
589 return STATUS_NOT_IMPLEMENTED
;
592 /******************************************************************************
593 * NtSetTimerResolution [NTDLL.@]
595 NTSTATUS WINAPI
NtSetTimerResolution(IN ULONG resolution
,
596 IN BOOLEAN set_resolution
,
597 OUT ULONG
* current_resolution
)
599 FIXME("(%lu,%u,%p), stub!\n",
600 resolution
, set_resolution
, current_resolution
);
602 return STATUS_NOT_IMPLEMENTED
;
606 /***********************************************************************
609 * Wait for a reply on the waiting pipe of the current thread.
611 static int wait_reply( void *cookie
)
614 struct wake_up_reply reply
;
618 ret
= read( ntdll_get_thread_data()->wait_fd
[0], &reply
, sizeof(reply
) );
619 if (ret
== sizeof(reply
))
621 if (!reply
.cookie
) break; /* thread got killed */
622 if (reply
.cookie
== cookie
) return reply
.signaled
;
623 /* we stole another reply, wait for the real one */
624 signaled
= wait_reply( cookie
);
625 /* and now put the wrong one back in the pipe */
628 ret
= write( ntdll_get_thread_data()->wait_fd
[1], &reply
, sizeof(reply
) );
629 if (ret
== sizeof(reply
)) break;
630 if (ret
>= 0) server_protocol_error( "partial wakeup write %d\n", ret
);
631 if (errno
== EINTR
) continue;
632 server_protocol_perror("wakeup write");
636 if (ret
>= 0) server_protocol_error( "partial wakeup read %d\n", ret
);
637 if (errno
== EINTR
) continue;
638 server_protocol_perror("wakeup read");
640 /* the server closed the connection; time to die... */
641 server_abort_thread(0);
645 /***********************************************************************
648 * Call outstanding APCs.
650 static void call_apcs( BOOL alertable
)
654 void *arg1
, *arg2
, *arg3
;
659 SERVER_START_REQ( get_apc
)
661 req
->alertable
= alertable
;
662 if (!wine_server_call( req
)) type
= reply
->type
;
673 return; /* no more APCs */
675 proc( arg1
, arg2
, arg3
);
678 /* convert sec/usec to NT time */
679 RtlSecondsSince1970ToTime( (time_t)arg1
, &time
);
680 time
.QuadPart
+= (DWORD
)arg2
* 10;
681 proc( arg3
, time
.u
.LowPart
, time
.u
.HighPart
);
684 NtCurrentTeb()->num_async_io
--;
685 proc( arg1
, (IO_STATUS_BLOCK
*)arg2
, (ULONG
)arg3
);
688 server_protocol_error( "get_apc_request: bad type %d\n", type
);
695 /***********************************************************************
696 * NTDLL_wait_for_multiple_objects
698 * Implementation of NtWaitForMultipleObjects
700 NTSTATUS
NTDLL_wait_for_multiple_objects( UINT count
, const HANDLE
*handles
, UINT flags
,
701 const LARGE_INTEGER
*timeout
, HANDLE signal_object
)
706 if (timeout
) flags
|= SELECT_TIMEOUT
;
709 SERVER_START_REQ( select
)
712 req
->cookie
= &cookie
;
713 req
->signal
= signal_object
;
714 NTDLL_get_server_timeout( &req
->timeout
, timeout
);
715 wine_server_add_data( req
, handles
, count
* sizeof(HANDLE
) );
716 ret
= wine_server_call( req
);
719 if (ret
== STATUS_PENDING
) ret
= wait_reply( &cookie
);
720 if (ret
!= STATUS_USER_APC
) break;
721 call_apcs( (flags
& SELECT_ALERTABLE
) != 0 );
722 if (flags
& SELECT_ALERTABLE
) break;
723 signal_object
= 0; /* don't signal it multiple times */
726 /* A test on Windows 2000 shows that Windows always yields during
727 a wait, but a wait that is hit by an event gets a priority
728 boost as well. This seems to model that behavior the closest. */
729 if (ret
== WAIT_TIMEOUT
) NtYieldExecution();
735 /* wait operations */
737 /******************************************************************
738 * NtWaitForMultipleObjects (NTDLL.@)
740 NTSTATUS WINAPI
NtWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
,
741 BOOLEAN wait_all
, BOOLEAN alertable
,
742 const LARGE_INTEGER
*timeout
)
744 UINT flags
= SELECT_INTERRUPTIBLE
;
746 if (!count
|| count
> MAXIMUM_WAIT_OBJECTS
) return STATUS_INVALID_PARAMETER_1
;
748 if (wait_all
) flags
|= SELECT_ALL
;
749 if (alertable
) flags
|= SELECT_ALERTABLE
;
750 return NTDLL_wait_for_multiple_objects( count
, handles
, flags
, timeout
, 0 );
754 /******************************************************************
755 * NtWaitForSingleObject (NTDLL.@)
757 NTSTATUS WINAPI
NtWaitForSingleObject(HANDLE handle
, BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
759 return NtWaitForMultipleObjects( 1, &handle
, FALSE
, alertable
, timeout
);
763 /******************************************************************
764 * NtSignalAndWaitForSingleObject (NTDLL.@)
766 NTSTATUS WINAPI
NtSignalAndWaitForSingleObject( HANDLE hSignalObject
, HANDLE hWaitObject
,
767 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
769 UINT flags
= SELECT_INTERRUPTIBLE
;
771 if (!hSignalObject
) return STATUS_INVALID_HANDLE
;
772 if (alertable
) flags
|= SELECT_ALERTABLE
;
773 return NTDLL_wait_for_multiple_objects( 1, &hWaitObject
, flags
, timeout
, hSignalObject
);
777 /******************************************************************
778 * NtYieldExecution (NTDLL.@)
780 NTSTATUS WINAPI
NtYieldExecution(void)
782 #ifdef HAVE_SCHED_YIELD
784 return STATUS_SUCCESS
;
786 return STATUS_NO_YIELD_PERFORMED
;
791 /******************************************************************
792 * NtDelayExecution (NTDLL.@)
794 NTSTATUS WINAPI
NtDelayExecution( BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
796 /* if alertable or async I/O in progress, we need to query the server */
797 if (alertable
|| NtCurrentTeb()->num_async_io
)
799 UINT flags
= SELECT_INTERRUPTIBLE
;
800 if (alertable
) flags
|= SELECT_ALERTABLE
;
801 return NTDLL_wait_for_multiple_objects( 0, NULL
, flags
, timeout
, 0 );
804 if (!timeout
) /* sleep forever */
806 for (;;) select( 0, NULL
, NULL
, NULL
, NULL
);
812 NTDLL_get_server_timeout( &when
, timeout
);
814 /* Note that we yield after establishing the desired timeout */
820 gettimeofday( &tv
, 0 );
821 tv
.tv_sec
= when
.sec
- tv
.tv_sec
;
822 if ((tv
.tv_usec
= when
.usec
- tv
.tv_usec
) < 0)
824 tv
.tv_usec
+= 1000000;
827 /* if our yield already passed enough time, we're done */
828 if (tv
.tv_sec
< 0) break;
830 if (select( 0, NULL
, NULL
, NULL
, &tv
) != -1) break;
833 return STATUS_SUCCESS
;