Allocate the proper size for the SystemClock object.
[wine] / dlls / ntdll / sync.c
1 /*
2  *      Process synchronisation
3  *
4  * Copyright 1996, 1997, 1998 Marcus Meissner
5  * Copyright 1997, 1999 Alexandre Julliard
6  * Copyright 1999, 2000 Juergen Schmied
7  * Copyright 2003 Eric Pouech
8  *
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.
13  *
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.
18  *
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
22  */
23
24 #include "config.h"
25
26 #include <assert.h>
27 #include <errno.h>
28 #include <signal.h>
29 #ifdef HAVE_SYS_TIME_H
30 # include <sys/time.h>
31 #endif
32 #ifdef HAVE_SYS_POLL_H
33 # include <sys/poll.h>
34 #endif
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif
38 #ifdef HAVE_SCHED_H
39 # include <sched.h>
40 #endif
41 #include <string.h>
42 #include <stdarg.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <time.h>
46
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
49
50 #include "windef.h"
51 #include "winbase.h"
52 #include "winreg.h"
53 #include "winternl.h"
54 #include "async.h"
55 #include "thread.h"
56 #include "wine/server.h"
57 #include "wine/unicode.h"
58 #include "wine/debug.h"
59 #include "ntdll_misc.h"
60
61 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
62
63
64 /*
65  *      Semaphores
66  */
67
68 /******************************************************************************
69  *  NtCreateSemaphore (NTDLL.@)
70  */
71 NTSTATUS WINAPI NtCreateSemaphore( OUT PHANDLE SemaphoreHandle,
72                                    IN ACCESS_MASK access,
73                                    IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
74                                    IN LONG InitialCount,
75                                    IN LONG MaximumCount )
76 {
77     DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
78     NTSTATUS ret;
79
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;
83
84     SERVER_START_REQ( create_semaphore )
85     {
86         req->access  = access;
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;
93     }
94     SERVER_END_REQ;
95     return ret;
96 }
97
98 /******************************************************************************
99  *  NtOpenSemaphore (NTDLL.@)
100  */
101 NTSTATUS WINAPI NtOpenSemaphore( OUT PHANDLE SemaphoreHandle,
102                                  IN ACCESS_MASK access,
103                                  IN const OBJECT_ATTRIBUTES *attr )
104 {
105     DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
106     NTSTATUS ret;
107
108     if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
109
110     SERVER_START_REQ( open_semaphore )
111     {
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;
117     }
118     SERVER_END_REQ;
119     return ret;
120 }
121
122 /******************************************************************************
123  *  NtQuerySemaphore (NTDLL.@)
124  */
125 NTSTATUS WINAPI NtQuerySemaphore(
126         HANDLE SemaphoreHandle,
127         PVOID SemaphoreInformationClass,
128         OUT PVOID SemaphoreInformation,
129         ULONG Length,
130         PULONG ReturnLength)
131 {
132         FIXME("(%p,%p,%p,0x%08lx,%p) stub!\n",
133         SemaphoreHandle, SemaphoreInformationClass, SemaphoreInformation, Length, ReturnLength);
134         return STATUS_SUCCESS;
135 }
136
137 /******************************************************************************
138  *  NtReleaseSemaphore (NTDLL.@)
139  */
140 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
141 {
142     NTSTATUS ret;
143     SERVER_START_REQ( release_semaphore )
144     {
145         req->handle = handle;
146         req->count  = count;
147         if (!(ret = wine_server_call( req )))
148         {
149             if (previous) *previous = reply->prev_count;
150         }
151     }
152     SERVER_END_REQ;
153     return ret;
154 }
155
156 /*
157  *      Events
158  */
159
160 /**************************************************************************
161  * NtCreateEvent (NTDLL.@)
162  * ZwCreateEvent (NTDLL.@)
163  */
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)
170 {
171     DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
172     NTSTATUS ret;
173
174     if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
175
176     SERVER_START_REQ( create_event )
177     {
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;
185     }
186     SERVER_END_REQ;
187     return ret;
188 }
189
190 /******************************************************************************
191  *  NtOpenEvent (NTDLL.@)
192  *  ZwOpenEvent (NTDLL.@)
193  */
194 NTSTATUS WINAPI NtOpenEvent(
195         OUT PHANDLE EventHandle,
196         IN ACCESS_MASK DesiredAccess,
197         IN const OBJECT_ATTRIBUTES *attr )
198 {
199     DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
200     NTSTATUS ret;
201
202     if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
203
204     SERVER_START_REQ( open_event )
205     {
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;
211     }
212     SERVER_END_REQ;
213     return ret;
214 }
215
216
217 /******************************************************************************
218  *  NtSetEvent (NTDLL.@)
219  *  ZwSetEvent (NTDLL.@)
220  */
221 NTSTATUS WINAPI NtSetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
222 {
223     NTSTATUS ret;
224
225     /* FIXME: set NumberOfThreadsReleased */
226
227     SERVER_START_REQ( event_op )
228     {
229         req->handle = handle;
230         req->op     = SET_EVENT;
231         ret = wine_server_call( req );
232     }
233     SERVER_END_REQ;
234     return ret;
235 }
236
237 /******************************************************************************
238  *  NtResetEvent (NTDLL.@)
239  */
240 NTSTATUS WINAPI NtResetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
241 {
242     NTSTATUS ret;
243
244     /* resetting an event can't release any thread... */
245     if (NumberOfThreadsReleased) *NumberOfThreadsReleased = 0;
246
247     SERVER_START_REQ( event_op )
248     {
249         req->handle = handle;
250         req->op     = RESET_EVENT;
251         ret = wine_server_call( req );
252     }
253     SERVER_END_REQ;
254     return ret;
255 }
256
257 /******************************************************************************
258  *  NtClearEvent (NTDLL.@)
259  *
260  * FIXME
261  *   same as NtResetEvent ???
262  */
263 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
264 {
265     return NtResetEvent( handle, NULL );
266 }
267
268 /******************************************************************************
269  *  NtPulseEvent (NTDLL.@)
270  *
271  * FIXME
272  *   PulseCount
273  */
274 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, PULONG PulseCount )
275 {
276     NTSTATUS ret;
277
278     if (PulseCount)
279       FIXME("(%p,%ld)\n", handle, *PulseCount);
280
281     SERVER_START_REQ( event_op )
282     {
283         req->handle = handle;
284         req->op     = PULSE_EVENT;
285         ret = wine_server_call( req );
286     }
287     SERVER_END_REQ;
288     return ret;
289 }
290
291 /******************************************************************************
292  *  NtQueryEvent (NTDLL.@)
293  */
294 NTSTATUS WINAPI NtQueryEvent (
295         IN  HANDLE EventHandle,
296         IN  UINT EventInformationClass,
297         OUT PVOID EventInformation,
298         IN  ULONG EventInformationLength,
299         OUT PULONG  ReturnLength)
300 {
301         FIXME("(%p)\n", EventHandle);
302         return STATUS_SUCCESS;
303 }
304
305 /*
306  *      Mutants (known as Mutexes in Kernel32)
307  */
308
309 /******************************************************************************
310  *              NtCreateMutant                          [NTDLL.@]
311  *              ZwCreateMutant                          [NTDLL.@]
312  */
313 NTSTATUS WINAPI NtCreateMutant(OUT HANDLE* MutantHandle,
314                                IN ACCESS_MASK access,
315                                IN const OBJECT_ATTRIBUTES* attr OPTIONAL,
316                                IN BOOLEAN InitialOwner)
317 {
318     NTSTATUS    status;
319     DWORD       len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
320
321     if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
322
323     SERVER_START_REQ( create_mutex )
324     {
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;
331     }
332     SERVER_END_REQ;
333     return status;
334 }
335
336 /**************************************************************************
337  *              NtOpenMutant                            [NTDLL.@]
338  *              ZwOpenMutant                            [NTDLL.@]
339  */
340 NTSTATUS WINAPI NtOpenMutant(OUT HANDLE* MutantHandle, 
341                              IN ACCESS_MASK access, 
342                              IN const OBJECT_ATTRIBUTES* attr )
343 {
344     NTSTATUS    status;
345     DWORD       len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
346
347     if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
348
349     SERVER_START_REQ( open_mutex )
350     {
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;
356     }
357     SERVER_END_REQ;
358     return status;
359 }
360
361 /**************************************************************************
362  *              NtReleaseMutant                         [NTDLL.@]
363  *              ZwReleaseMutant                         [NTDLL.@]
364  */
365 NTSTATUS WINAPI NtReleaseMutant( IN HANDLE handle, OUT PLONG prev_count OPTIONAL)
366 {
367     NTSTATUS    status;
368
369     SERVER_START_REQ( release_mutex )
370     {
371         req->handle = handle;
372         status = wine_server_call( req );
373         if (prev_count) *prev_count = reply->prev_count;
374     }
375     SERVER_END_REQ;
376     return status;
377 }
378
379 /******************************************************************
380  *              NtQueryMutant                   [NTDLL.@]
381  *              ZwQueryMutant                   [NTDLL.@]
382  */
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 )
388 {
389     FIXME("(%p %u %p %lu %p): stub!\n", 
390           handle, MutantInformationClass, MutantInformation, MutantInformationLength, ResultLength);
391     return STATUS_NOT_IMPLEMENTED;
392 }
393
394 /*
395  *      Timers
396  */
397
398 /**************************************************************************
399  *              NtCreateTimer                           [NTDLL.@]
400  *              ZwCreateTimer                           [NTDLL.@]
401  */
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)
406 {
407     DWORD       len = (attr && attr->ObjectName) ? attr->ObjectName->Length : 0;
408     NTSTATUS    status;
409
410     if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
411
412     if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
413         return STATUS_INVALID_PARAMETER;
414
415     SERVER_START_REQ( create_timer )
416     {
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;
423     }
424     SERVER_END_REQ;
425     return status;
426
427 }
428
429 /**************************************************************************
430  *              NtOpenTimer                             [NTDLL.@]
431  *              ZwOpenTimer                             [NTDLL.@]
432  */
433 NTSTATUS WINAPI NtOpenTimer(OUT PHANDLE handle,
434                             IN ACCESS_MASK access,
435                             IN const OBJECT_ATTRIBUTES* attr )
436 {
437     DWORD       len = (attr && attr->ObjectName) ? attr->ObjectName->Length : 0;
438     NTSTATUS    status;
439
440     if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
441
442     SERVER_START_REQ( open_timer )
443     {
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;
449     }
450     SERVER_END_REQ;
451     return status;
452 }
453
454 /**************************************************************************
455  *              NtSetTimer                              [NTDLL.@]
456  *              ZwSetTimer                              [NTDLL.@]
457  */
458 NTSTATUS WINAPI NtSetTimer(IN HANDLE handle,
459                            IN const LARGE_INTEGER* when,
460                            IN PTIMERAPCROUTINE callback,
461                            IN PVOID callback_arg,
462                            IN BOOLEAN resume,
463                            IN ULONG period OPTIONAL,
464                            OUT PBOOLEAN state OPTIONAL)
465 {
466     NTSTATUS    status = STATUS_SUCCESS;
467
468     TRACE("(%p,%p,%p,%p,%08x,0x%08lx,%p) stub\n",
469           handle, when, callback, callback_arg, resume, period, state);
470
471     SERVER_START_REQ( set_timer )
472     {
473         if (!when->u.LowPart && !when->u.HighPart)
474         {
475             /* special case to start timeout on now+period without too many calculations */
476             req->expire.sec  = 0;
477             req->expire.usec = 0;
478         }
479         else NTDLL_get_server_timeout( &req->expire, when );
480
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;
487     }
488     SERVER_END_REQ;
489
490     /* set error but can still succeed */
491     if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
492     return status;
493 }
494
495 /**************************************************************************
496  *              NtCancelTimer                           [NTDLL.@]
497  *              ZwCancelTimer                           [NTDLL.@]
498  */
499 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
500 {
501     NTSTATUS    status;
502
503     SERVER_START_REQ( cancel_timer )
504     {
505         req->handle = handle;
506         status = wine_server_call( req );
507         if (state) *state = reply->signaled;
508     }
509     SERVER_END_REQ;
510     return status;
511 }
512
513 /******************************************************************************
514  * NtQueryTimerResolution [NTDLL.@]
515  */
516 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
517                                        OUT ULONG* max_resolution,
518                                        OUT ULONG* current_resolution)
519 {
520     FIXME("(%p,%p,%p), stub!\n",
521           min_resolution, max_resolution, current_resolution);
522
523     return STATUS_NOT_IMPLEMENTED;
524 }
525
526 /******************************************************************************
527  * NtSetTimerResolution [NTDLL.@]
528  */
529 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
530                                      IN BOOLEAN set_resolution,
531                                      OUT ULONG* current_resolution )
532 {
533     FIXME("(%lu,%u,%p), stub!\n",
534           resolution, set_resolution, current_resolution);
535
536     return STATUS_NOT_IMPLEMENTED;
537 }
538
539
540 /***********************************************************************
541  *           check_async_list
542  *
543  * Process a status event from the server.
544  */
545 static void WINAPI check_async_list(async_private *asp, DWORD status)
546 {
547     async_private *ovp;
548     DWORD ovp_status;
549
550     for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
551
552     if(!ovp)
553             return;
554
555     if( status != STATUS_ALERTED )
556     {
557         ovp_status = status;
558         ovp->iosb->u.Status = status;
559     }
560     else ovp_status = ovp->iosb->u.Status;
561
562     if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
563
564     /* This will destroy all but PENDING requests */
565     register_old_async( ovp );
566 }
567
568
569 /***********************************************************************
570  *              wait_reply
571  *
572  * Wait for a reply on the waiting pipe of the current thread.
573  */
574 static int wait_reply( void *cookie )
575 {
576     int signaled;
577     struct wake_up_reply reply;
578     for (;;)
579     {
580         int ret;
581         ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
582         if (ret == sizeof(reply))
583         {
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 */
589             for (;;)
590             {
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");
596             }
597             return signaled;
598         }
599         if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret );
600         if (errno == EINTR) continue;
601         server_protocol_perror("wakeup read");
602     }
603     /* the server closed the connection; time to die... */
604     server_abort_thread(0);
605 }
606
607
608 /***********************************************************************
609  *              call_apcs
610  *
611  * Call outstanding APCs.
612  */
613 static void call_apcs( BOOL alertable )
614 {
615     FARPROC proc;
616     LARGE_INTEGER time;
617     void *arg1, *arg2, *arg3;
618
619     for (;;)
620     {
621         int type = APC_NONE;
622         SERVER_START_REQ( get_apc )
623         {
624             req->alertable = alertable;
625             if (!wine_server_call( req )) type = reply->type;
626             proc = reply->func;
627             arg1 = reply->arg1;
628             arg2 = reply->arg2;
629             arg3 = reply->arg3;
630         }
631         SERVER_END_REQ;
632
633         switch(type)
634         {
635         case APC_NONE:
636             return;  /* no more APCs */
637         case APC_ASYNC:
638             proc( arg1, arg2 );
639             break;
640         case APC_USER:
641             proc( arg1, arg2, arg3 );
642             break;
643         case APC_TIMER:
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 );
648             break;
649         case APC_ASYNC_IO:
650             check_async_list( arg1, (DWORD) arg2 );
651             break;
652         default:
653             server_protocol_error( "get_apc_request: bad type %d\n", type );
654             break;
655         }
656     }
657 }
658
659
660 /***********************************************************************
661  *              NTDLL_wait_for_multiple_objects
662  *
663  * Implementation of NtWaitForMultipleObjects
664  */
665 NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UINT flags,
666                                           const LARGE_INTEGER *timeout )
667 {
668     NTSTATUS ret;
669     int cookie;
670
671     if (timeout) flags |= SELECT_TIMEOUT;
672     for (;;)
673     {
674         SERVER_START_REQ( select )
675         {
676             req->flags   = flags;
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 );
681         }
682         SERVER_END_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;
687     }
688
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();
693
694     return ret;
695 }
696
697
698 /* wait operations */
699
700 /******************************************************************
701  *              NtWaitForMultipleObjects (NTDLL.@)
702  */
703 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
704                                           BOOLEAN wait_all, BOOLEAN alertable,
705                                           const LARGE_INTEGER *timeout )
706 {
707     UINT flags = SELECT_INTERRUPTIBLE;
708
709     if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
710
711     if (wait_all) flags |= SELECT_ALL;
712     if (alertable) flags |= SELECT_ALERTABLE;
713     return NTDLL_wait_for_multiple_objects( count, handles, flags, timeout );
714 }
715
716
717 /******************************************************************
718  *              NtWaitForSingleObject (NTDLL.@)
719  */
720 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
721 {
722     return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );
723 }
724
725
726 /******************************************************************
727  *              NtYieldExecution (NTDLL.@)
728  */
729 NTSTATUS WINAPI NtYieldExecution(void)
730 {
731 #ifdef HAVE_SCHED_YIELD
732     sched_yield();
733     return STATUS_SUCCESS;
734 #else
735     return STATUS_NO_YIELD_PERFORMED;
736 #endif
737 }
738
739
740 /******************************************************************
741  *              NtDelayExecution (NTDLL.@)
742  */
743 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
744 {
745     /* if alertable or async I/O in progress, we need to query the server */
746     if (alertable || NtCurrentTeb()->pending_list)
747     {
748         UINT flags = SELECT_INTERRUPTIBLE;
749         if (alertable) flags |= SELECT_ALERTABLE;
750         return NTDLL_wait_for_multiple_objects( 0, NULL, flags, timeout );
751     }
752
753     if (!timeout)  /* sleep forever */
754     {
755         for (;;) select( 0, NULL, NULL, NULL, NULL );
756     }
757     else
758     {
759         abs_time_t when;
760
761         NTDLL_get_server_timeout( &when, timeout );
762
763         /* Note that we yield after establishing the desired timeout */
764         NtYieldExecution();
765
766         for (;;)
767         {
768             struct timeval tv;
769             gettimeofday( &tv, 0 );
770             tv.tv_sec = when.sec - tv.tv_sec;
771             if ((tv.tv_usec = when.usec - tv.tv_usec) < 0)
772             {
773                 tv.tv_usec += 1000000;
774                 tv.tv_sec--;
775             }
776             /* if our yield already passed enough time, we're done */
777             if (tv.tv_sec < 0) break;
778
779             if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
780         }
781     }
782     return STATUS_SUCCESS;
783 }