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/debug.h"
58 #include "ntdll_misc.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(ntdll
);
67 /******************************************************************************
68 * NtCreateSemaphore (NTDLL.@)
70 NTSTATUS WINAPI
NtCreateSemaphore( OUT PHANDLE SemaphoreHandle
,
71 IN ACCESS_MASK access
,
72 IN
const OBJECT_ATTRIBUTES
*attr OPTIONAL
,
74 IN LONG MaximumCount
)
76 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
79 if (MaximumCount
<= 0 || InitialCount
< 0 || InitialCount
> MaximumCount
)
80 return STATUS_INVALID_PARAMETER
;
81 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
83 SERVER_START_REQ( create_semaphore
)
86 req
->initial
= InitialCount
;
87 req
->max
= MaximumCount
;
88 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
89 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
90 ret
= wine_server_call( req
);
91 *SemaphoreHandle
= reply
->handle
;
97 /******************************************************************************
98 * NtOpenSemaphore (NTDLL.@)
100 NTSTATUS WINAPI
NtOpenSemaphore( OUT PHANDLE SemaphoreHandle
,
101 IN ACCESS_MASK access
,
102 IN
const OBJECT_ATTRIBUTES
*attr
)
104 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
107 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
109 SERVER_START_REQ( open_semaphore
)
111 req
->access
= access
;
112 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
113 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
114 ret
= wine_server_call( req
);
115 *SemaphoreHandle
= reply
->handle
;
121 /******************************************************************************
122 * NtQuerySemaphore (NTDLL.@)
124 NTSTATUS WINAPI
NtQuerySemaphore(
125 HANDLE SemaphoreHandle
,
126 PVOID SemaphoreInformationClass
,
127 OUT PVOID SemaphoreInformation
,
131 FIXME("(%p,%p,%p,0x%08lx,%p) stub!\n",
132 SemaphoreHandle
, SemaphoreInformationClass
, SemaphoreInformation
, Length
, ReturnLength
);
133 return STATUS_SUCCESS
;
136 /******************************************************************************
137 * NtReleaseSemaphore (NTDLL.@)
139 NTSTATUS WINAPI
NtReleaseSemaphore( HANDLE handle
, ULONG count
, PULONG previous
)
142 SERVER_START_REQ( release_semaphore
)
144 req
->handle
= handle
;
146 if (!(ret
= wine_server_call( req
)))
148 if (previous
) *previous
= reply
->prev_count
;
159 /**************************************************************************
160 * NtCreateEvent (NTDLL.@)
161 * ZwCreateEvent (NTDLL.@)
163 NTSTATUS WINAPI
NtCreateEvent(
164 OUT PHANDLE EventHandle
,
165 IN ACCESS_MASK DesiredAccess
,
166 IN
const OBJECT_ATTRIBUTES
*attr
,
167 IN BOOLEAN ManualReset
,
168 IN BOOLEAN InitialState
)
170 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
173 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
175 SERVER_START_REQ( create_event
)
177 req
->access
= DesiredAccess
;
178 req
->manual_reset
= ManualReset
;
179 req
->initial_state
= InitialState
;
180 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
181 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
182 ret
= wine_server_call( req
);
183 *EventHandle
= reply
->handle
;
189 /******************************************************************************
190 * NtOpenEvent (NTDLL.@)
191 * ZwOpenEvent (NTDLL.@)
193 NTSTATUS WINAPI
NtOpenEvent(
194 OUT PHANDLE EventHandle
,
195 IN ACCESS_MASK DesiredAccess
,
196 IN
const OBJECT_ATTRIBUTES
*attr
)
198 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
201 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
203 SERVER_START_REQ( open_event
)
205 req
->access
= DesiredAccess
;
206 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
207 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
208 ret
= wine_server_call( req
);
209 *EventHandle
= reply
->handle
;
216 /******************************************************************************
217 * NtSetEvent (NTDLL.@)
218 * ZwSetEvent (NTDLL.@)
220 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
224 /* FIXME: set NumberOfThreadsReleased */
226 SERVER_START_REQ( event_op
)
228 req
->handle
= handle
;
230 ret
= wine_server_call( req
);
236 /******************************************************************************
237 * NtResetEvent (NTDLL.@)
239 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
243 /* resetting an event can't release any thread... */
244 if (NumberOfThreadsReleased
) *NumberOfThreadsReleased
= 0;
246 SERVER_START_REQ( event_op
)
248 req
->handle
= handle
;
249 req
->op
= RESET_EVENT
;
250 ret
= wine_server_call( req
);
256 /******************************************************************************
257 * NtClearEvent (NTDLL.@)
260 * same as NtResetEvent ???
262 NTSTATUS WINAPI
NtClearEvent ( HANDLE handle
)
264 return NtResetEvent( handle
, NULL
);
267 /******************************************************************************
268 * NtPulseEvent (NTDLL.@)
273 NTSTATUS WINAPI
NtPulseEvent( HANDLE handle
, PULONG PulseCount
)
278 FIXME("(%p,%ld)\n", handle
, *PulseCount
);
280 SERVER_START_REQ( event_op
)
282 req
->handle
= handle
;
283 req
->op
= PULSE_EVENT
;
284 ret
= wine_server_call( req
);
290 /******************************************************************************
291 * NtQueryEvent (NTDLL.@)
293 NTSTATUS WINAPI
NtQueryEvent (
294 IN HANDLE EventHandle
,
295 IN UINT EventInformationClass
,
296 OUT PVOID EventInformation
,
297 IN ULONG EventInformationLength
,
298 OUT PULONG ReturnLength
)
300 FIXME("(%p)\n", EventHandle
);
301 return STATUS_SUCCESS
;
305 * Mutants (known as Mutexes in Kernel32)
308 /******************************************************************************
309 * NtCreateMutant [NTDLL.@]
310 * ZwCreateMutant [NTDLL.@]
312 NTSTATUS WINAPI
NtCreateMutant(OUT HANDLE
* MutantHandle
,
313 IN ACCESS_MASK access
,
314 IN
const OBJECT_ATTRIBUTES
* attr OPTIONAL
,
315 IN BOOLEAN InitialOwner
)
318 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
320 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
322 SERVER_START_REQ( create_mutex
)
324 req
->access
= access
;
325 req
->owned
= InitialOwner
;
326 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
327 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
328 status
= wine_server_call( req
);
329 *MutantHandle
= reply
->handle
;
335 /**************************************************************************
336 * NtOpenMutant [NTDLL.@]
337 * ZwOpenMutant [NTDLL.@]
339 NTSTATUS WINAPI
NtOpenMutant(OUT HANDLE
* MutantHandle
,
340 IN ACCESS_MASK access
,
341 IN
const OBJECT_ATTRIBUTES
* attr
)
344 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
346 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
348 SERVER_START_REQ( open_mutex
)
350 req
->access
= access
;
351 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
352 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
353 status
= wine_server_call( req
);
354 *MutantHandle
= reply
->handle
;
360 /**************************************************************************
361 * NtReleaseMutant [NTDLL.@]
362 * ZwReleaseMutant [NTDLL.@]
364 NTSTATUS WINAPI
NtReleaseMutant( IN HANDLE handle
, OUT PLONG prev_count OPTIONAL
)
368 SERVER_START_REQ( release_mutex
)
370 req
->handle
= handle
;
371 status
= wine_server_call( req
);
372 if (prev_count
) *prev_count
= reply
->prev_count
;
378 /******************************************************************
379 * NtQueryMutant [NTDLL.@]
380 * ZwQueryMutant [NTDLL.@]
382 NTSTATUS WINAPI
NtQueryMutant(IN HANDLE handle
,
383 IN MUTANT_INFORMATION_CLASS MutantInformationClass
,
384 OUT PVOID MutantInformation
,
385 IN ULONG MutantInformationLength
,
386 OUT PULONG ResultLength OPTIONAL
)
388 FIXME("(%p %u %p %lu %p): stub!\n",
389 handle
, MutantInformationClass
, MutantInformation
, MutantInformationLength
, ResultLength
);
390 return STATUS_NOT_IMPLEMENTED
;
397 /**************************************************************************
398 * NtCreateTimer [NTDLL.@]
399 * ZwCreateTimer [NTDLL.@]
401 NTSTATUS WINAPI
NtCreateTimer(OUT HANDLE
*handle
,
402 IN ACCESS_MASK access
,
403 IN
const OBJECT_ATTRIBUTES
*attr OPTIONAL
,
404 IN TIMER_TYPE timer_type
)
406 DWORD len
= (attr
&& attr
->ObjectName
) ? attr
->ObjectName
->Length
: 0;
409 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
411 if (timer_type
!= NotificationTimer
&& timer_type
!= SynchronizationTimer
)
412 return STATUS_INVALID_PARAMETER
;
414 SERVER_START_REQ( create_timer
)
416 req
->access
= access
;
417 req
->manual
= (timer_type
== NotificationTimer
) ? TRUE
: FALSE
;
418 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
419 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
420 status
= wine_server_call( req
);
421 *handle
= reply
->handle
;
428 /**************************************************************************
429 * NtOpenTimer [NTDLL.@]
430 * ZwOpenTimer [NTDLL.@]
432 NTSTATUS WINAPI
NtOpenTimer(OUT PHANDLE handle
,
433 IN ACCESS_MASK access
,
434 IN
const OBJECT_ATTRIBUTES
* attr
)
436 DWORD len
= (attr
&& attr
->ObjectName
) ? attr
->ObjectName
->Length
: 0;
439 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
441 SERVER_START_REQ( open_timer
)
443 req
->access
= access
;
444 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
445 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
446 status
= wine_server_call( req
);
447 *handle
= reply
->handle
;
453 /**************************************************************************
454 * NtSetTimer [NTDLL.@]
455 * ZwSetTimer [NTDLL.@]
457 NTSTATUS WINAPI
NtSetTimer(IN HANDLE handle
,
458 IN
const LARGE_INTEGER
* when
,
459 IN PTIMERAPCROUTINE callback
,
460 IN PVOID callback_arg
,
462 IN ULONG period OPTIONAL
,
463 OUT PBOOLEAN state OPTIONAL
)
465 NTSTATUS status
= STATUS_SUCCESS
;
467 TRACE("(%p,%p,%p,%p,%08x,0x%08lx,%p) stub\n",
468 handle
, when
, callback
, callback_arg
, resume
, period
, state
);
470 SERVER_START_REQ( set_timer
)
472 if (!when
->u
.LowPart
&& !when
->u
.HighPart
)
474 /* special case to start timeout on now+period without too many calculations */
476 req
->expire
.usec
= 0;
478 else NTDLL_get_server_timeout( &req
->expire
, when
);
480 req
->handle
= handle
;
481 req
->period
= period
;
482 req
->callback
= callback
;
483 req
->arg
= callback_arg
;
484 status
= wine_server_call( req
);
485 if (state
) *state
= reply
->signaled
;
489 /* set error but can still succeed */
490 if (resume
&& status
== STATUS_SUCCESS
) return STATUS_TIMER_RESUME_IGNORED
;
494 /**************************************************************************
495 * NtCancelTimer [NTDLL.@]
496 * ZwCancelTimer [NTDLL.@]
498 NTSTATUS WINAPI
NtCancelTimer(IN HANDLE handle
, OUT BOOLEAN
* state
)
502 SERVER_START_REQ( cancel_timer
)
504 req
->handle
= handle
;
505 status
= wine_server_call( req
);
506 if (state
) *state
= reply
->signaled
;
512 /******************************************************************************
513 * NtQueryTimer (NTDLL.@)
515 * Retrieves information about a timer.
518 * TimerHandle [I] The timer to retrieve information about.
519 * TimerInformationClass [I] The type of information to retrieve.
520 * TimerInformation [O] Pointer to buffer to store information in.
521 * Length [I] The length of the buffer pointed to by TimerInformation.
522 * ReturnLength [O] Optional. The size of buffer actually used.
525 * Success: STATUS_SUCCESS
526 * Failure: STATUS_INFO_LENGTH_MISMATCH, if Length doesn't match the required data
527 * size for the class specified.
528 * STATUS_INVALID_INFO_CLASS, if an invalid TimerInformationClass was specified.
529 * STATUS_ACCESS_DENIED, if TimerHandle does not have TIMER_QUERY_STATE access
532 NTSTATUS WINAPI
NtQueryTimer(
534 TIMER_INFORMATION_CLASS TimerInformationClass
,
535 PVOID TimerInformation
,
539 TIMER_BASIC_INFORMATION
* basic_info
= (TIMER_BASIC_INFORMATION
*)TimerInformation
;
543 TRACE("(%p,%d,%p,0x%08lx,%p)\n", TimerHandle
, TimerInformationClass
,
544 TimerInformation
, Length
, ReturnLength
);
546 switch (TimerInformationClass
)
548 case TimerBasicInformation
:
549 if (Length
< sizeof(TIMER_BASIC_INFORMATION
))
550 return STATUS_INFO_LENGTH_MISMATCH
;
552 SERVER_START_REQ(get_timer_info
)
554 req
->handle
= TimerHandle
;
555 status
= wine_server_call(req
);
557 /* convert server time to absolute NTDLL time */
558 NTDLL_from_server_timeout(&basic_info
->RemainingTime
, &reply
->when
);
559 basic_info
->TimerState
= reply
->signaled
;
563 /* convert from absolute into relative time */
564 NtQuerySystemTime(&now
);
565 if (now
.QuadPart
> basic_info
->RemainingTime
.QuadPart
)
566 basic_info
->RemainingTime
.QuadPart
= 0;
568 basic_info
->RemainingTime
.QuadPart
-= now
.QuadPart
;
570 if (ReturnLength
) *ReturnLength
= sizeof(TIMER_BASIC_INFORMATION
);
575 FIXME("Unhandled class %d\n", TimerInformationClass
);
576 return STATUS_INVALID_INFO_CLASS
;
580 /******************************************************************************
581 * NtQueryTimerResolution [NTDLL.@]
583 NTSTATUS WINAPI
NtQueryTimerResolution(OUT ULONG
* min_resolution
,
584 OUT ULONG
* max_resolution
,
585 OUT ULONG
* current_resolution
)
587 FIXME("(%p,%p,%p), stub!\n",
588 min_resolution
, max_resolution
, current_resolution
);
590 return STATUS_NOT_IMPLEMENTED
;
593 /******************************************************************************
594 * NtSetTimerResolution [NTDLL.@]
596 NTSTATUS WINAPI
NtSetTimerResolution(IN ULONG resolution
,
597 IN BOOLEAN set_resolution
,
598 OUT ULONG
* current_resolution
)
600 FIXME("(%lu,%u,%p), stub!\n",
601 resolution
, set_resolution
, current_resolution
);
603 return STATUS_NOT_IMPLEMENTED
;
607 /***********************************************************************
610 * Process a status event from the server.
612 static void WINAPI
check_async_list(async_private
*asp
, DWORD status
)
617 for( ovp
= NtCurrentTeb()->pending_list
; ovp
&& ovp
!= asp
; ovp
= ovp
->next
);
622 if( status
!= STATUS_ALERTED
)
625 ovp
->iosb
->u
.Status
= status
;
627 else ovp_status
= ovp
->iosb
->u
.Status
;
629 if( ovp_status
== STATUS_PENDING
) ovp
->func( ovp
);
631 /* This will destroy all but PENDING requests */
632 register_old_async( ovp
);
636 /***********************************************************************
639 * Wait for a reply on the waiting pipe of the current thread.
641 static int wait_reply( void *cookie
)
644 struct wake_up_reply reply
;
648 ret
= read( NtCurrentTeb()->wait_fd
[0], &reply
, sizeof(reply
) );
649 if (ret
== sizeof(reply
))
651 if (!reply
.cookie
) break; /* thread got killed */
652 if (reply
.cookie
== cookie
) return reply
.signaled
;
653 /* we stole another reply, wait for the real one */
654 signaled
= wait_reply( cookie
);
655 /* and now put the wrong one back in the pipe */
658 ret
= write( NtCurrentTeb()->wait_fd
[1], &reply
, sizeof(reply
) );
659 if (ret
== sizeof(reply
)) break;
660 if (ret
>= 0) server_protocol_error( "partial wakeup write %d\n", ret
);
661 if (errno
== EINTR
) continue;
662 server_protocol_perror("wakeup write");
666 if (ret
>= 0) server_protocol_error( "partial wakeup read %d\n", ret
);
667 if (errno
== EINTR
) continue;
668 server_protocol_perror("wakeup read");
670 /* the server closed the connection; time to die... */
671 server_abort_thread(0);
675 /***********************************************************************
678 * Call outstanding APCs.
680 static void call_apcs( BOOL alertable
)
684 void *arg1
, *arg2
, *arg3
;
689 SERVER_START_REQ( get_apc
)
691 req
->alertable
= alertable
;
692 if (!wine_server_call( req
)) type
= reply
->type
;
703 return; /* no more APCs */
708 proc( arg1
, arg2
, arg3
);
711 /* convert sec/usec to NT time */
712 RtlSecondsSince1970ToTime( (time_t)arg1
, &time
);
713 time
.QuadPart
+= (DWORD
)arg2
* 10;
714 proc( arg3
, time
.u
.LowPart
, time
.u
.HighPart
);
717 check_async_list( arg1
, (DWORD
) arg2
);
720 server_protocol_error( "get_apc_request: bad type %d\n", type
);
727 /***********************************************************************
728 * NTDLL_wait_for_multiple_objects
730 * Implementation of NtWaitForMultipleObjects
732 NTSTATUS
NTDLL_wait_for_multiple_objects( UINT count
, const HANDLE
*handles
, UINT flags
,
733 const LARGE_INTEGER
*timeout
)
738 if (timeout
) flags
|= SELECT_TIMEOUT
;
741 SERVER_START_REQ( select
)
744 req
->cookie
= &cookie
;
745 NTDLL_get_server_timeout( &req
->timeout
, timeout
);
746 wine_server_add_data( req
, handles
, count
* sizeof(HANDLE
) );
747 ret
= wine_server_call( req
);
750 if (ret
== STATUS_PENDING
) ret
= wait_reply( &cookie
);
751 if (ret
!= STATUS_USER_APC
) break;
752 call_apcs( (flags
& SELECT_ALERTABLE
) != 0 );
753 if (flags
& SELECT_ALERTABLE
) break;
756 /* A test on Windows 2000 shows that Windows always yields during
757 a wait, but a wait that is hit by an event gets a priority
758 boost as well. This seems to model that behavior the closest. */
759 if (ret
== WAIT_TIMEOUT
) NtYieldExecution();
765 /* wait operations */
767 /******************************************************************
768 * NtWaitForMultipleObjects (NTDLL.@)
770 NTSTATUS WINAPI
NtWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
,
771 BOOLEAN wait_all
, BOOLEAN alertable
,
772 const LARGE_INTEGER
*timeout
)
774 UINT flags
= SELECT_INTERRUPTIBLE
;
776 if (!count
|| count
> MAXIMUM_WAIT_OBJECTS
) return STATUS_INVALID_PARAMETER_1
;
778 if (wait_all
) flags
|= SELECT_ALL
;
779 if (alertable
) flags
|= SELECT_ALERTABLE
;
780 return NTDLL_wait_for_multiple_objects( count
, handles
, flags
, timeout
);
784 /******************************************************************
785 * NtWaitForSingleObject (NTDLL.@)
787 NTSTATUS WINAPI
NtWaitForSingleObject(HANDLE handle
, BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
789 return NtWaitForMultipleObjects( 1, &handle
, FALSE
, alertable
, timeout
);
793 /******************************************************************
794 * NtYieldExecution (NTDLL.@)
796 NTSTATUS WINAPI
NtYieldExecution(void)
798 #ifdef HAVE_SCHED_YIELD
800 return STATUS_SUCCESS
;
802 return STATUS_NO_YIELD_PERFORMED
;
807 /******************************************************************
808 * NtDelayExecution (NTDLL.@)
810 NTSTATUS WINAPI
NtDelayExecution( BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
812 /* if alertable or async I/O in progress, we need to query the server */
813 if (alertable
|| NtCurrentTeb()->pending_list
)
815 UINT flags
= SELECT_INTERRUPTIBLE
;
816 if (alertable
) flags
|= SELECT_ALERTABLE
;
817 return NTDLL_wait_for_multiple_objects( 0, NULL
, flags
, timeout
);
820 if (!timeout
) /* sleep forever */
822 for (;;) select( 0, NULL
, NULL
, NULL
, NULL
);
828 NTDLL_get_server_timeout( &when
, timeout
);
830 /* Note that we yield after establishing the desired timeout */
836 gettimeofday( &tv
, 0 );
837 tv
.tv_sec
= when
.sec
- tv
.tv_sec
;
838 if ((tv
.tv_usec
= when
.usec
- tv
.tv_usec
) < 0)
840 tv
.tv_usec
+= 1000000;
843 /* if our yield already passed enough time, we're done */
844 if (tv
.tv_sec
< 0) break;
846 if (select( 0, NULL
, NULL
, NULL
, &tv
) != -1) break;
849 return STATUS_SUCCESS
;