SetMenu should always call SetWindowPos whether the window is visible
[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 #include <string.h>
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <time.h>
43
44 #define NONAMELESSUNION
45 #define NONAMELESSSTRUCT
46
47 #include "windef.h"
48 #include "winbase.h"
49 #include "winreg.h"
50 #include "winternl.h"
51 #include "async.h"
52 #include "thread.h"
53 #include "wine/server.h"
54 #include "wine/unicode.h"
55 #include "wine/debug.h"
56 #include "ntdll_misc.h"
57
58 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
59
60
61 /*
62  *      Semaphores
63  */
64
65 /******************************************************************************
66  *  NtCreateSemaphore (NTDLL.@)
67  */
68 NTSTATUS WINAPI NtCreateSemaphore( OUT PHANDLE SemaphoreHandle,
69                                    IN ACCESS_MASK access,
70                                    IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
71                                    IN ULONG InitialCount,
72                                    IN ULONG MaximumCount )
73 {
74     DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
75     NTSTATUS ret;
76
77     if ((MaximumCount <= 0) || (InitialCount > MaximumCount))
78         return STATUS_INVALID_PARAMETER;
79
80     SERVER_START_REQ( create_semaphore )
81     {
82         req->initial = InitialCount;
83         req->max     = MaximumCount;
84         req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
85         if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
86         ret = wine_server_call( req );
87         *SemaphoreHandle = reply->handle;
88     }
89     SERVER_END_REQ;
90     return ret;
91 }
92
93 /******************************************************************************
94  *  NtOpenSemaphore (NTDLL.@)
95  */
96 NTSTATUS WINAPI NtOpenSemaphore( OUT PHANDLE SemaphoreHandle,
97                                  IN ACCESS_MASK access,
98                                  IN const OBJECT_ATTRIBUTES *attr )
99 {
100     DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
101     NTSTATUS ret;
102
103     SERVER_START_REQ( open_semaphore )
104     {
105         req->access  = access;
106         req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
107         if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
108         ret = wine_server_call( req );
109         *SemaphoreHandle = reply->handle;
110     }
111     SERVER_END_REQ;
112     return ret;
113 }
114
115 /******************************************************************************
116  *  NtQuerySemaphore (NTDLL.@)
117  */
118 NTSTATUS WINAPI NtQuerySemaphore(
119         HANDLE SemaphoreHandle,
120         PVOID SemaphoreInformationClass,
121         OUT PVOID SemaphoreInformation,
122         ULONG Length,
123         PULONG ReturnLength)
124 {
125         FIXME("(%p,%p,%p,0x%08lx,%p) stub!\n",
126         SemaphoreHandle, SemaphoreInformationClass, SemaphoreInformation, Length, ReturnLength);
127         return STATUS_SUCCESS;
128 }
129
130 /******************************************************************************
131  *  NtReleaseSemaphore (NTDLL.@)
132  */
133 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
134 {
135     NTSTATUS ret;
136     SERVER_START_REQ( release_semaphore )
137     {
138         req->handle = handle;
139         req->count  = count;
140         if (!(ret = wine_server_call( req )))
141         {
142             if (previous) *previous = reply->prev_count;
143         }
144     }
145     SERVER_END_REQ;
146     return ret;
147 }
148
149 /*
150  *      Events
151  */
152
153 /**************************************************************************
154  * NtCreateEvent (NTDLL.@)
155  * ZwCreateEvent (NTDLL.@)
156  */
157 NTSTATUS WINAPI NtCreateEvent(
158         OUT PHANDLE EventHandle,
159         IN ACCESS_MASK DesiredAccess,
160         IN const OBJECT_ATTRIBUTES *attr,
161         IN BOOLEAN ManualReset,
162         IN BOOLEAN InitialState)
163 {
164     DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
165     NTSTATUS ret;
166
167     SERVER_START_REQ( create_event )
168     {
169         req->manual_reset = ManualReset;
170         req->initial_state = InitialState;
171         req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
172         if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
173         ret = wine_server_call( req );
174         *EventHandle = reply->handle;
175     }
176     SERVER_END_REQ;
177     return ret;
178 }
179
180 /******************************************************************************
181  *  NtOpenEvent (NTDLL.@)
182  *  ZwOpenEvent (NTDLL.@)
183  */
184 NTSTATUS WINAPI NtOpenEvent(
185         OUT PHANDLE EventHandle,
186         IN ACCESS_MASK DesiredAccess,
187         IN const OBJECT_ATTRIBUTES *attr )
188 {
189     DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
190     NTSTATUS ret;
191
192     SERVER_START_REQ( open_event )
193     {
194         req->access  = DesiredAccess;
195         req->inherit = attr && (attr->Attributes & OBJ_INHERIT);
196         if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
197         ret = wine_server_call( req );
198         *EventHandle = reply->handle;
199     }
200     SERVER_END_REQ;
201     return ret;
202 }
203
204
205 /******************************************************************************
206  *  NtSetEvent (NTDLL.@)
207  *  ZwSetEvent (NTDLL.@)
208  */
209 NTSTATUS WINAPI NtSetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
210 {
211     NTSTATUS ret;
212
213     /* FIXME: set NumberOfThreadsReleased */
214
215     SERVER_START_REQ( event_op )
216     {
217         req->handle = handle;
218         req->op     = SET_EVENT;
219         ret = wine_server_call( req );
220     }
221     SERVER_END_REQ;
222     return ret;
223 }
224
225 /******************************************************************************
226  *  NtResetEvent (NTDLL.@)
227  */
228 NTSTATUS WINAPI NtResetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
229 {
230     NTSTATUS ret;
231
232     /* resetting an event can't release any thread... */
233     if (NumberOfThreadsReleased) *NumberOfThreadsReleased = 0;
234
235     SERVER_START_REQ( event_op )
236     {
237         req->handle = handle;
238         req->op     = RESET_EVENT;
239         ret = wine_server_call( req );
240     }
241     SERVER_END_REQ;
242     return ret;
243 }
244
245 /******************************************************************************
246  *  NtClearEvent (NTDLL.@)
247  *
248  * FIXME
249  *   same as NtResetEvent ???
250  */
251 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
252 {
253     return NtResetEvent( handle, NULL );
254 }
255
256 /******************************************************************************
257  *  NtPulseEvent (NTDLL.@)
258  *
259  * FIXME
260  *   PulseCount
261  */
262 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, PULONG PulseCount )
263 {
264     NTSTATUS ret;
265     FIXME("(%p,%p)\n", handle, PulseCount);
266     SERVER_START_REQ( event_op )
267     {
268         req->handle = handle;
269         req->op     = PULSE_EVENT;
270         ret = wine_server_call( req );
271     }
272     SERVER_END_REQ;
273     return ret;
274 }
275
276 /******************************************************************************
277  *  NtQueryEvent (NTDLL.@)
278  */
279 NTSTATUS WINAPI NtQueryEvent (
280         IN  HANDLE EventHandle,
281         IN  UINT EventInformationClass,
282         OUT PVOID EventInformation,
283         IN  ULONG EventInformationLength,
284         OUT PULONG  ReturnLength)
285 {
286         FIXME("(%p)\n", EventHandle);
287         return STATUS_SUCCESS;
288 }
289
290
291 /*
292  *      Timers
293  */
294
295 /**************************************************************************
296  *              NtCreateTimer                           [NTDLL.@]
297  *              ZwCreateTimer                           [NTDLL.@]
298  */
299 NTSTATUS WINAPI NtCreateTimer(OUT HANDLE *handle,
300                               IN ACCESS_MASK access,
301                               IN const OBJECT_ATTRIBUTES *oa OPTIONAL,
302                               IN TIMER_TYPE timer_type)
303 {
304     DWORD len = (oa && oa->ObjectName) ? oa->ObjectName->Length : 0;
305     NTSTATUS    status;
306
307     if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
308         return STATUS_INVALID_PARAMETER;
309
310     SERVER_START_REQ( create_timer )
311     {
312         req->manual  = (timer_type == NotificationTimer) ? TRUE : FALSE;
313         req->inherit = oa && (oa->Attributes & OBJ_INHERIT);
314         if (len) wine_server_add_data( req, oa->ObjectName->Buffer, len );
315         status = wine_server_call( req );
316         *handle = reply->handle;
317     }
318     SERVER_END_REQ;
319     return status;
320
321 }
322
323 /**************************************************************************
324  *              NtOpenTimer                             [NTDLL.@]
325  *              ZwOpenTimer                             [NTDLL.@]
326  */
327 NTSTATUS WINAPI NtOpenTimer(OUT PHANDLE handle,
328                             IN ACCESS_MASK access,
329                             IN const OBJECT_ATTRIBUTES* oa )
330 {
331     DWORD len = (oa && oa->ObjectName) ? oa->ObjectName->Length : 0;
332     NTSTATUS status;
333
334     if (oa && oa->Length >= MAX_PATH * sizeof(WCHAR))
335         return STATUS_NAME_TOO_LONG;
336
337     SERVER_START_REQ( open_timer )
338     {
339         req->access  = access;
340         req->inherit = oa && (oa->Attributes & OBJ_INHERIT);
341         if (len) wine_server_add_data( req, oa->ObjectName->Buffer, len );
342         status = wine_server_call( req );
343         *handle = reply->handle;
344     }
345     SERVER_END_REQ;
346     return status;
347 }
348
349 /**************************************************************************
350  *              NtSetTimer                              [NTDLL.@]
351  *              ZwSetTimer                              [NTDLL.@]
352  */
353 NTSTATUS WINAPI NtSetTimer(IN HANDLE handle,
354                            IN const LARGE_INTEGER* when,
355                            IN PTIMERAPCROUTINE callback,
356                            IN PVOID callback_arg,
357                            IN BOOLEAN resume,
358                            IN ULONG period OPTIONAL,
359                            OUT PBOOLEAN state OPTIONAL)
360 {
361     NTSTATUS    status = STATUS_SUCCESS;
362
363     TRACE("(%p,%p,%p,%p,%08x,0x%08lx,%p) stub\n",
364           handle, when, callback, callback_arg, resume, period, state);
365
366     SERVER_START_REQ( set_timer )
367     {
368         if (!when->u.LowPart && !when->u.HighPart)
369         {
370             /* special case to start timeout on now+period without too many calculations */
371             req->expire.sec  = 0;
372             req->expire.usec = 0;
373         }
374         else NTDLL_get_server_timeout( &req->expire, when );
375
376         req->handle   = handle;
377         req->period   = period;
378         req->callback = callback;
379         req->arg      = callback_arg;
380         status = wine_server_call( req );
381         if (state) *state = reply->signaled;
382     }
383     SERVER_END_REQ;
384
385     /* set error but can still succeed */
386     if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
387     return status;
388 }
389
390 /**************************************************************************
391  *              NtCancelTimer                           [NTDLL.@]
392  *              ZwCancelTimer                           [NTDLL.@]
393  */
394 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
395 {
396     NTSTATUS    status;
397
398     SERVER_START_REQ( cancel_timer )
399     {
400         req->handle = handle;
401         status = wine_server_call( req );
402         if (state) *state = reply->signaled;
403     }
404     SERVER_END_REQ;
405     return status;
406 }
407
408 /******************************************************************************
409  * NtQueryTimerResolution [NTDLL.@]
410  */
411 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
412                                        OUT ULONG* max_resolution,
413                                        OUT ULONG* current_resolution)
414 {
415     FIXME("(%p,%p,%p), stub!\n",
416           min_resolution, max_resolution, current_resolution);
417
418     return STATUS_NOT_IMPLEMENTED;
419 }
420
421 /******************************************************************************
422  * NtSetTimerResolution [NTDLL.@]
423  */
424 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
425                                      IN BOOLEAN set_resolution,
426                                      OUT ULONG* current_resolution )
427 {
428     FIXME("(%lu,%u,%p), stub!\n",
429           resolution, set_resolution, current_resolution);
430
431     return STATUS_NOT_IMPLEMENTED;
432 }
433
434
435 /***********************************************************************
436  *           check_async_list
437  *
438  * Process a status event from the server.
439  */
440 static void WINAPI check_async_list(async_private *asp, DWORD status)
441 {
442     async_private *ovp;
443     DWORD ovp_status;
444
445     for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
446
447     if(!ovp)
448             return;
449
450     if( status != STATUS_ALERTED )
451     {
452         ovp_status = status;
453         ovp->iosb->u.Status = status;
454     }
455     else ovp_status = ovp->iosb->u.Status;
456
457     if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
458
459     /* This will destroy all but PENDING requests */
460     register_old_async( ovp );
461 }
462
463
464 /***********************************************************************
465  *              wait_reply
466  *
467  * Wait for a reply on the waiting pipe of the current thread.
468  */
469 static int wait_reply( void *cookie )
470 {
471     int signaled;
472     struct wake_up_reply reply;
473     for (;;)
474     {
475         int ret;
476         ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
477         if (ret == sizeof(reply))
478         {
479             if (!reply.cookie) break;  /* thread got killed */
480             if (reply.cookie == cookie) return reply.signaled;
481             /* we stole another reply, wait for the real one */
482             signaled = wait_reply( cookie );
483             /* and now put the wrong one back in the pipe */
484             for (;;)
485             {
486                 ret = write( NtCurrentTeb()->wait_fd[1], &reply, sizeof(reply) );
487                 if (ret == sizeof(reply)) break;
488                 if (ret >= 0) server_protocol_error( "partial wakeup write %d\n", ret );
489                 if (errno == EINTR) continue;
490                 server_protocol_perror("wakeup write");
491             }
492             return signaled;
493         }
494         if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret );
495         if (errno == EINTR) continue;
496         server_protocol_perror("wakeup read");
497     }
498     /* the server closed the connection; time to die... */
499     server_abort_thread(0);
500 }
501
502
503 /***********************************************************************
504  *              call_apcs
505  *
506  * Call outstanding APCs.
507  */
508 static void call_apcs( BOOL alertable )
509 {
510     FARPROC proc;
511     LARGE_INTEGER time;
512     void *arg1, *arg2, *arg3;
513
514     for (;;)
515     {
516         int type = APC_NONE;
517         SERVER_START_REQ( get_apc )
518         {
519             req->alertable = alertable;
520             if (!wine_server_call( req )) type = reply->type;
521             proc = reply->func;
522             arg1 = reply->arg1;
523             arg2 = reply->arg2;
524             arg3 = reply->arg3;
525         }
526         SERVER_END_REQ;
527
528         switch(type)
529         {
530         case APC_NONE:
531             return;  /* no more APCs */
532         case APC_ASYNC:
533             proc( arg1, arg2 );
534             break;
535         case APC_USER:
536             proc( arg1, arg2, arg3 );
537             break;
538         case APC_TIMER:
539             /* convert sec/usec to NT time */
540             RtlSecondsSince1970ToTime( (time_t)arg1, &time );
541             time.QuadPart += (DWORD)arg2 * 10;
542             proc( arg3, time.u.LowPart, time.u.HighPart );
543             break;
544         case APC_ASYNC_IO:
545             check_async_list( arg1, (DWORD) arg2 );
546             break;
547         default:
548             server_protocol_error( "get_apc_request: bad type %d\n", type );
549             break;
550         }
551     }
552 }
553
554
555 /***********************************************************************
556  *              NTDLL_wait_for_multiple_objects
557  *
558  * Implementation of NtWaitForMultipleObjects
559  */
560 NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UINT flags,
561                                           const LARGE_INTEGER *timeout )
562 {
563     NTSTATUS ret;
564     int cookie;
565
566     if (timeout) flags |= SELECT_TIMEOUT;
567     for (;;)
568     {
569         SERVER_START_REQ( select )
570         {
571             req->flags   = flags;
572             req->cookie  = &cookie;
573             NTDLL_get_server_timeout( &req->timeout, timeout );
574             wine_server_add_data( req, handles, count * sizeof(HANDLE) );
575             ret = wine_server_call( req );
576         }
577         SERVER_END_REQ;
578         if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
579         if (ret != STATUS_USER_APC) break;
580         call_apcs( (flags & SELECT_ALERTABLE) != 0 );
581         if (flags & SELECT_ALERTABLE) break;
582     }
583     return ret;
584 }
585
586
587 /* wait operations */
588
589 /******************************************************************
590  *              NtWaitForMultipleObjects (NTDLL.@)
591  */
592 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
593                                           BOOLEAN wait_all, BOOLEAN alertable,
594                                           const LARGE_INTEGER *timeout )
595 {
596     UINT flags = SELECT_INTERRUPTIBLE;
597
598     if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
599
600     if (wait_all) flags |= SELECT_ALL;
601     if (alertable) flags |= SELECT_ALERTABLE;
602     return NTDLL_wait_for_multiple_objects( count, handles, flags, timeout );
603 }
604
605
606 /******************************************************************
607  *              NtWaitForSingleObject (NTDLL.@)
608  */
609 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
610 {
611     return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );
612 }
613
614
615 /******************************************************************
616  *              NtDelayExecution (NTDLL.@)
617  */
618 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
619 {
620     /* if alertable or async I/O in progress, we need to query the server */
621     if (alertable || NtCurrentTeb()->pending_list)
622     {
623         UINT flags = SELECT_INTERRUPTIBLE;
624         if (alertable) flags |= SELECT_ALERTABLE;
625         return NTDLL_wait_for_multiple_objects( 0, NULL, flags, timeout );
626     }
627
628     if (!timeout)  /* sleep forever */
629     {
630         for (;;) select( 0, NULL, NULL, NULL, NULL );
631     }
632     else
633     {
634         abs_time_t when;
635
636         NTDLL_get_server_timeout( &when, timeout );
637         for (;;)
638         {
639             struct timeval tv;
640             gettimeofday( &tv, 0 );
641             tv.tv_sec = when.sec - tv.tv_sec;
642             if ((tv.tv_usec = when.usec - tv.tv_usec) < 0)
643             {
644                 tv.tv_usec += 1000000;
645                 tv.tv_sec--;
646             }
647             if (tv.tv_sec < 0) tv.tv_sec = tv.tv_usec = 0;
648             if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
649         }
650     }
651     return STATUS_SUCCESS;
652 }