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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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
54 #define WIN32_NO_STATUS
57 #include "wine/server.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
->attributes
= (attr
) ? attr
->Attributes
: 0;
88 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
89 req
->initial
= InitialCount
;
90 req
->max
= MaximumCount
;
91 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
92 ret
= wine_server_call( req
);
93 *SemaphoreHandle
= reply
->handle
;
99 /******************************************************************************
100 * NtOpenSemaphore (NTDLL.@)
102 NTSTATUS WINAPI
NtOpenSemaphore( OUT PHANDLE SemaphoreHandle
,
103 IN ACCESS_MASK access
,
104 IN
const OBJECT_ATTRIBUTES
*attr
)
106 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
109 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
111 SERVER_START_REQ( open_semaphore
)
113 req
->access
= access
;
114 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
115 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
116 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
117 ret
= wine_server_call( req
);
118 *SemaphoreHandle
= reply
->handle
;
124 /******************************************************************************
125 * NtQuerySemaphore (NTDLL.@)
127 NTSTATUS WINAPI
NtQuerySemaphore(
128 HANDLE SemaphoreHandle
,
129 SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass
,
130 PVOID SemaphoreInformation
,
134 FIXME("(%p,%d,%p,0x%08x,%p) stub!\n",
135 SemaphoreHandle
, SemaphoreInformationClass
, SemaphoreInformation
, Length
, ReturnLength
);
136 return STATUS_SUCCESS
;
139 /******************************************************************************
140 * NtReleaseSemaphore (NTDLL.@)
142 NTSTATUS WINAPI
NtReleaseSemaphore( HANDLE handle
, ULONG count
, PULONG previous
)
145 SERVER_START_REQ( release_semaphore
)
147 req
->handle
= handle
;
149 if (!(ret
= wine_server_call( req
)))
151 if (previous
) *previous
= reply
->prev_count
;
162 /**************************************************************************
163 * NtCreateEvent (NTDLL.@)
164 * ZwCreateEvent (NTDLL.@)
166 NTSTATUS WINAPI
NtCreateEvent(
167 OUT PHANDLE EventHandle
,
168 IN ACCESS_MASK DesiredAccess
,
169 IN
const OBJECT_ATTRIBUTES
*attr
,
170 IN BOOLEAN ManualReset
,
171 IN BOOLEAN InitialState
)
173 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
176 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
178 SERVER_START_REQ( create_event
)
180 req
->access
= DesiredAccess
;
181 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
182 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
183 req
->manual_reset
= ManualReset
;
184 req
->initial_state
= InitialState
;
185 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
186 ret
= wine_server_call( req
);
187 *EventHandle
= reply
->handle
;
193 /******************************************************************************
194 * NtOpenEvent (NTDLL.@)
195 * ZwOpenEvent (NTDLL.@)
197 NTSTATUS WINAPI
NtOpenEvent(
198 OUT PHANDLE EventHandle
,
199 IN ACCESS_MASK DesiredAccess
,
200 IN
const OBJECT_ATTRIBUTES
*attr
)
202 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
205 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
207 SERVER_START_REQ( open_event
)
209 req
->access
= DesiredAccess
;
210 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
211 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
212 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
213 ret
= wine_server_call( req
);
214 *EventHandle
= reply
->handle
;
221 /******************************************************************************
222 * NtSetEvent (NTDLL.@)
223 * ZwSetEvent (NTDLL.@)
225 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
229 /* FIXME: set NumberOfThreadsReleased */
231 SERVER_START_REQ( event_op
)
233 req
->handle
= handle
;
235 ret
= wine_server_call( req
);
241 /******************************************************************************
242 * NtResetEvent (NTDLL.@)
244 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
248 /* resetting an event can't release any thread... */
249 if (NumberOfThreadsReleased
) *NumberOfThreadsReleased
= 0;
251 SERVER_START_REQ( event_op
)
253 req
->handle
= handle
;
254 req
->op
= RESET_EVENT
;
255 ret
= wine_server_call( req
);
261 /******************************************************************************
262 * NtClearEvent (NTDLL.@)
265 * same as NtResetEvent ???
267 NTSTATUS WINAPI
NtClearEvent ( HANDLE handle
)
269 return NtResetEvent( handle
, NULL
);
272 /******************************************************************************
273 * NtPulseEvent (NTDLL.@)
278 NTSTATUS WINAPI
NtPulseEvent( HANDLE handle
, PULONG PulseCount
)
283 FIXME("(%p,%d)\n", handle
, *PulseCount
);
285 SERVER_START_REQ( event_op
)
287 req
->handle
= handle
;
288 req
->op
= PULSE_EVENT
;
289 ret
= wine_server_call( req
);
295 /******************************************************************************
296 * NtQueryEvent (NTDLL.@)
298 NTSTATUS WINAPI
NtQueryEvent (
299 IN HANDLE EventHandle
,
300 IN UINT EventInformationClass
,
301 OUT PVOID EventInformation
,
302 IN ULONG EventInformationLength
,
303 OUT PULONG ReturnLength
)
305 FIXME("(%p)\n", EventHandle
);
306 return STATUS_SUCCESS
;
310 * Mutants (known as Mutexes in Kernel32)
313 /******************************************************************************
314 * NtCreateMutant [NTDLL.@]
315 * ZwCreateMutant [NTDLL.@]
317 NTSTATUS WINAPI
NtCreateMutant(OUT HANDLE
* MutantHandle
,
318 IN ACCESS_MASK access
,
319 IN
const OBJECT_ATTRIBUTES
* attr OPTIONAL
,
320 IN BOOLEAN InitialOwner
)
323 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
325 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
327 SERVER_START_REQ( create_mutex
)
329 req
->access
= access
;
330 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
331 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
332 req
->owned
= InitialOwner
;
333 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
334 status
= wine_server_call( req
);
335 *MutantHandle
= reply
->handle
;
341 /**************************************************************************
342 * NtOpenMutant [NTDLL.@]
343 * ZwOpenMutant [NTDLL.@]
345 NTSTATUS WINAPI
NtOpenMutant(OUT HANDLE
* MutantHandle
,
346 IN ACCESS_MASK access
,
347 IN
const OBJECT_ATTRIBUTES
* attr
)
350 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
352 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
354 SERVER_START_REQ( open_mutex
)
356 req
->access
= access
;
357 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
358 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
359 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
360 status
= wine_server_call( req
);
361 *MutantHandle
= reply
->handle
;
367 /**************************************************************************
368 * NtReleaseMutant [NTDLL.@]
369 * ZwReleaseMutant [NTDLL.@]
371 NTSTATUS WINAPI
NtReleaseMutant( IN HANDLE handle
, OUT PLONG prev_count OPTIONAL
)
375 SERVER_START_REQ( release_mutex
)
377 req
->handle
= handle
;
378 status
= wine_server_call( req
);
379 if (prev_count
) *prev_count
= reply
->prev_count
;
385 /******************************************************************
386 * NtQueryMutant [NTDLL.@]
387 * ZwQueryMutant [NTDLL.@]
389 NTSTATUS WINAPI
NtQueryMutant(IN HANDLE handle
,
390 IN MUTANT_INFORMATION_CLASS MutantInformationClass
,
391 OUT PVOID MutantInformation
,
392 IN ULONG MutantInformationLength
,
393 OUT PULONG ResultLength OPTIONAL
)
395 FIXME("(%p %u %p %u %p): stub!\n",
396 handle
, MutantInformationClass
, MutantInformation
, MutantInformationLength
, ResultLength
);
397 return STATUS_NOT_IMPLEMENTED
;
404 /**************************************************************************
405 * NtCreateTimer [NTDLL.@]
406 * ZwCreateTimer [NTDLL.@]
408 NTSTATUS WINAPI
NtCreateTimer(OUT HANDLE
*handle
,
409 IN ACCESS_MASK access
,
410 IN
const OBJECT_ATTRIBUTES
*attr OPTIONAL
,
411 IN TIMER_TYPE timer_type
)
413 DWORD len
= (attr
&& attr
->ObjectName
) ? attr
->ObjectName
->Length
: 0;
416 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
418 if (timer_type
!= NotificationTimer
&& timer_type
!= SynchronizationTimer
)
419 return STATUS_INVALID_PARAMETER
;
421 SERVER_START_REQ( create_timer
)
423 req
->access
= access
;
424 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
425 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
426 req
->manual
= (timer_type
== NotificationTimer
) ? TRUE
: FALSE
;
427 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
428 status
= wine_server_call( req
);
429 *handle
= reply
->handle
;
436 /**************************************************************************
437 * NtOpenTimer [NTDLL.@]
438 * ZwOpenTimer [NTDLL.@]
440 NTSTATUS WINAPI
NtOpenTimer(OUT PHANDLE handle
,
441 IN ACCESS_MASK access
,
442 IN
const OBJECT_ATTRIBUTES
* attr
)
444 DWORD len
= (attr
&& attr
->ObjectName
) ? attr
->ObjectName
->Length
: 0;
447 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
449 SERVER_START_REQ( open_timer
)
451 req
->access
= access
;
452 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
453 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
454 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
455 status
= wine_server_call( req
);
456 *handle
= reply
->handle
;
462 /**************************************************************************
463 * NtSetTimer [NTDLL.@]
464 * ZwSetTimer [NTDLL.@]
466 NTSTATUS WINAPI
NtSetTimer(IN HANDLE handle
,
467 IN
const LARGE_INTEGER
* when
,
468 IN PTIMER_APC_ROUTINE callback
,
469 IN PVOID callback_arg
,
471 IN ULONG period OPTIONAL
,
472 OUT PBOOLEAN state OPTIONAL
)
474 NTSTATUS status
= STATUS_SUCCESS
;
476 TRACE("(%p,%p,%p,%p,%08x,0x%08x,%p) stub\n",
477 handle
, when
, callback
, callback_arg
, resume
, period
, state
);
479 SERVER_START_REQ( set_timer
)
481 if (!when
->u
.LowPart
&& !when
->u
.HighPart
)
483 /* special case to start timeout on now+period without too many calculations */
485 req
->expire
.usec
= 0;
487 else NTDLL_get_server_abstime( &req
->expire
, when
);
489 req
->handle
= handle
;
490 req
->period
= period
;
491 req
->callback
= callback
;
492 req
->arg
= callback_arg
;
493 status
= wine_server_call( req
);
494 if (state
) *state
= reply
->signaled
;
498 /* set error but can still succeed */
499 if (resume
&& status
== STATUS_SUCCESS
) return STATUS_TIMER_RESUME_IGNORED
;
503 /**************************************************************************
504 * NtCancelTimer [NTDLL.@]
505 * ZwCancelTimer [NTDLL.@]
507 NTSTATUS WINAPI
NtCancelTimer(IN HANDLE handle
, OUT BOOLEAN
* state
)
511 SERVER_START_REQ( cancel_timer
)
513 req
->handle
= handle
;
514 status
= wine_server_call( req
);
515 if (state
) *state
= reply
->signaled
;
521 /******************************************************************************
522 * NtQueryTimer (NTDLL.@)
524 * Retrieves information about a timer.
527 * TimerHandle [I] The timer to retrieve information about.
528 * TimerInformationClass [I] The type of information to retrieve.
529 * TimerInformation [O] Pointer to buffer to store information in.
530 * Length [I] The length of the buffer pointed to by TimerInformation.
531 * ReturnLength [O] Optional. The size of buffer actually used.
534 * Success: STATUS_SUCCESS
535 * Failure: STATUS_INFO_LENGTH_MISMATCH, if Length doesn't match the required data
536 * size for the class specified.
537 * STATUS_INVALID_INFO_CLASS, if an invalid TimerInformationClass was specified.
538 * STATUS_ACCESS_DENIED, if TimerHandle does not have TIMER_QUERY_STATE access
541 NTSTATUS WINAPI
NtQueryTimer(
543 TIMER_INFORMATION_CLASS TimerInformationClass
,
544 PVOID TimerInformation
,
548 TIMER_BASIC_INFORMATION
* basic_info
= (TIMER_BASIC_INFORMATION
*)TimerInformation
;
552 TRACE("(%p,%d,%p,0x%08x,%p)\n", TimerHandle
, TimerInformationClass
,
553 TimerInformation
, Length
, ReturnLength
);
555 switch (TimerInformationClass
)
557 case TimerBasicInformation
:
558 if (Length
< sizeof(TIMER_BASIC_INFORMATION
))
559 return STATUS_INFO_LENGTH_MISMATCH
;
561 SERVER_START_REQ(get_timer_info
)
563 req
->handle
= TimerHandle
;
564 status
= wine_server_call(req
);
566 /* convert server time to absolute NTDLL time */
567 NTDLL_from_server_abstime(&basic_info
->RemainingTime
, &reply
->when
);
568 basic_info
->TimerState
= reply
->signaled
;
572 /* convert from absolute into relative time */
573 NtQuerySystemTime(&now
);
574 if (now
.QuadPart
> basic_info
->RemainingTime
.QuadPart
)
575 basic_info
->RemainingTime
.QuadPart
= 0;
577 basic_info
->RemainingTime
.QuadPart
-= now
.QuadPart
;
579 if (ReturnLength
) *ReturnLength
= sizeof(TIMER_BASIC_INFORMATION
);
584 FIXME("Unhandled class %d\n", TimerInformationClass
);
585 return STATUS_INVALID_INFO_CLASS
;
589 /******************************************************************************
590 * NtQueryTimerResolution [NTDLL.@]
592 NTSTATUS WINAPI
NtQueryTimerResolution(OUT ULONG
* min_resolution
,
593 OUT ULONG
* max_resolution
,
594 OUT ULONG
* current_resolution
)
596 FIXME("(%p,%p,%p), stub!\n",
597 min_resolution
, max_resolution
, current_resolution
);
599 return STATUS_NOT_IMPLEMENTED
;
602 /******************************************************************************
603 * NtSetTimerResolution [NTDLL.@]
605 NTSTATUS WINAPI
NtSetTimerResolution(IN ULONG resolution
,
606 IN BOOLEAN set_resolution
,
607 OUT ULONG
* current_resolution
)
609 FIXME("(%u,%u,%p), stub!\n",
610 resolution
, set_resolution
, current_resolution
);
612 return STATUS_NOT_IMPLEMENTED
;
616 /***********************************************************************
619 * Wait for a reply on the waiting pipe of the current thread.
621 static int wait_reply( void *cookie
)
624 struct wake_up_reply reply
;
628 ret
= read( ntdll_get_thread_data()->wait_fd
[0], &reply
, sizeof(reply
) );
629 if (ret
== sizeof(reply
))
631 if (!reply
.cookie
) break; /* thread got killed */
632 if (reply
.cookie
== cookie
) return reply
.signaled
;
633 /* we stole another reply, wait for the real one */
634 signaled
= wait_reply( cookie
);
635 /* and now put the wrong one back in the pipe */
638 ret
= write( ntdll_get_thread_data()->wait_fd
[1], &reply
, sizeof(reply
) );
639 if (ret
== sizeof(reply
)) break;
640 if (ret
>= 0) server_protocol_error( "partial wakeup write %d\n", ret
);
641 if (errno
== EINTR
) continue;
642 server_protocol_perror("wakeup write");
646 if (ret
>= 0) server_protocol_error( "partial wakeup read %d\n", ret
);
647 if (errno
== EINTR
) continue;
648 server_protocol_perror("wakeup read");
650 /* the server closed the connection; time to die... */
651 server_abort_thread(0);
655 /***********************************************************************
658 * Call outstanding APCs. Return TRUE if a user APC has been run.
660 static BOOL
call_apcs( BOOL alertable
)
662 BOOL user_apc
= FALSE
;
669 SERVER_START_REQ( get_apc
)
671 req
->alertable
= alertable
;
673 if (!(ret
= wine_server_call( req
)))
675 handle
= reply
->handle
;
681 if (ret
) return user_apc
; /* no more APCs */
686 call
.user
.func( call
.user
.args
[0], call
.user
.args
[1], call
.user
.args
[2] );
692 /* convert sec/usec to NT time */
693 RtlSecondsSince1970ToTime( call
.timer
.time
.sec
, &time
);
694 time
.QuadPart
+= call
.timer
.time
.usec
* 10;
695 call
.timer
.func( call
.timer
.arg
, time
.u
.LowPart
, time
.u
.HighPart
);
700 NtCurrentTeb()->num_async_io
--;
701 call
.async_io
.func( call
.async_io
.user
, call
.async_io
.sb
, call
.async_io
.status
);
704 server_protocol_error( "get_apc_request: bad type %d\n", call
.type
);
711 /***********************************************************************
712 * NTDLL_wait_for_multiple_objects
714 * Implementation of NtWaitForMultipleObjects
716 NTSTATUS
NTDLL_wait_for_multiple_objects( UINT count
, const HANDLE
*handles
, UINT flags
,
717 const LARGE_INTEGER
*timeout
, HANDLE signal_object
)
721 abs_time_t abs_timeout
;
723 NTDLL_get_server_abstime( &abs_timeout
, timeout
);
724 if (timeout
) flags
|= SELECT_TIMEOUT
;
727 SERVER_START_REQ( select
)
730 req
->cookie
= &cookie
;
731 req
->signal
= signal_object
;
732 req
->timeout
= abs_timeout
;
733 wine_server_add_data( req
, handles
, count
* sizeof(HANDLE
) );
734 ret
= wine_server_call( req
);
737 if (ret
== STATUS_PENDING
) ret
= wait_reply( &cookie
);
738 if (ret
!= STATUS_USER_APC
) break;
739 if (call_apcs( (flags
& SELECT_ALERTABLE
) != 0 )) break;
740 signal_object
= 0; /* don't signal it multiple times */
743 /* A test on Windows 2000 shows that Windows always yields during
744 a wait, but a wait that is hit by an event gets a priority
745 boost as well. This seems to model that behavior the closest. */
746 if (ret
== WAIT_TIMEOUT
) NtYieldExecution();
752 /* wait operations */
754 /******************************************************************
755 * NtWaitForMultipleObjects (NTDLL.@)
757 NTSTATUS WINAPI
NtWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
,
758 BOOLEAN wait_all
, BOOLEAN alertable
,
759 const LARGE_INTEGER
*timeout
)
761 UINT flags
= SELECT_INTERRUPTIBLE
;
763 if (!count
|| count
> MAXIMUM_WAIT_OBJECTS
) return STATUS_INVALID_PARAMETER_1
;
765 if (wait_all
) flags
|= SELECT_ALL
;
766 if (alertable
) flags
|= SELECT_ALERTABLE
;
767 return NTDLL_wait_for_multiple_objects( count
, handles
, flags
, timeout
, 0 );
771 /******************************************************************
772 * NtWaitForSingleObject (NTDLL.@)
774 NTSTATUS WINAPI
NtWaitForSingleObject(HANDLE handle
, BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
776 return NtWaitForMultipleObjects( 1, &handle
, FALSE
, alertable
, timeout
);
780 /******************************************************************
781 * NtSignalAndWaitForSingleObject (NTDLL.@)
783 NTSTATUS WINAPI
NtSignalAndWaitForSingleObject( HANDLE hSignalObject
, HANDLE hWaitObject
,
784 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
786 UINT flags
= SELECT_INTERRUPTIBLE
;
788 if (!hSignalObject
) return STATUS_INVALID_HANDLE
;
789 if (alertable
) flags
|= SELECT_ALERTABLE
;
790 return NTDLL_wait_for_multiple_objects( 1, &hWaitObject
, flags
, timeout
, hSignalObject
);
794 /******************************************************************
795 * NtYieldExecution (NTDLL.@)
797 NTSTATUS WINAPI
NtYieldExecution(void)
799 #ifdef HAVE_SCHED_YIELD
801 return STATUS_SUCCESS
;
803 return STATUS_NO_YIELD_PERFORMED
;
808 /******************************************************************
809 * NtDelayExecution (NTDLL.@)
811 NTSTATUS WINAPI
NtDelayExecution( BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
813 /* if alertable or async I/O in progress, we need to query the server */
814 if (alertable
|| NtCurrentTeb()->num_async_io
)
816 UINT flags
= SELECT_INTERRUPTIBLE
;
817 if (alertable
) flags
|= SELECT_ALERTABLE
;
818 return NTDLL_wait_for_multiple_objects( 0, NULL
, flags
, timeout
, 0 );
821 if (!timeout
) /* sleep forever */
823 for (;;) select( 0, NULL
, NULL
, NULL
, NULL
);
829 NTDLL_get_server_abstime( &when
, timeout
);
831 /* Note that we yield after establishing the desired timeout */
837 gettimeofday( &tv
, 0 );
838 tv
.tv_sec
= when
.sec
- tv
.tv_sec
;
839 if ((tv
.tv_usec
= when
.usec
- tv
.tv_usec
) < 0)
841 tv
.tv_usec
+= 1000000;
844 /* if our yield already passed enough time, we're done */
845 if (tv
.tv_sec
< 0) break;
847 if (select( 0, NULL
, NULL
, NULL
, &tv
) != -1) break;
850 return STATUS_SUCCESS
;
853 /******************************************************************
854 * NtCreateIoCompletion (NTDLL.@)
856 NTSTATUS WINAPI
NtCreateIoCompletion( PHANDLE CompletionPort
, ACCESS_MASK DesiredAccess
,
857 POBJECT_ATTRIBUTES ObjectAttributes
, ULONG NumberOfConcurrentThreads
)
859 FIXME("(%p, %x, %p, %d)\n", CompletionPort
, DesiredAccess
,
860 ObjectAttributes
, NumberOfConcurrentThreads
);
861 return STATUS_NOT_IMPLEMENTED
;
864 NTSTATUS WINAPI
NtSetIoCompletion( HANDLE CompletionPort
, ULONG_PTR CompletionKey
,
865 PIO_STATUS_BLOCK iosb
, ULONG NumberOfBytesTransferred
,
866 ULONG NumberOfBytesToTransfer
)
868 FIXME("(%p, %lx, %p, %d, %d)\n", CompletionPort
, CompletionKey
,
869 iosb
, NumberOfBytesTransferred
, NumberOfBytesToTransfer
);
870 return STATUS_NOT_IMPLEMENTED
;
873 NTSTATUS WINAPI
NtRemoveIoCompletion( HANDLE CompletionPort
, PULONG_PTR CompletionKey
,
874 PIO_STATUS_BLOCK iosb
, PULONG OperationStatus
,
875 PLARGE_INTEGER WaitTime
)
877 FIXME("(%p, %p, %p, %p, %p)\n", CompletionPort
, CompletionKey
,
878 iosb
, OperationStatus
, WaitTime
);
879 return STATUS_NOT_IMPLEMENTED
;