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