Moved support for opening DOS device files to ntdll.
[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
266     if (PulseCount)
267       FIXME("(%p,%ld)\n", handle, *PulseCount);
268
269     SERVER_START_REQ( event_op )
270     {
271         req->handle = handle;
272         req->op     = PULSE_EVENT;
273         ret = wine_server_call( req );
274     }
275     SERVER_END_REQ;
276     return ret;
277 }
278
279 /******************************************************************************
280  *  NtQueryEvent (NTDLL.@)
281  */
282 NTSTATUS WINAPI NtQueryEvent (
283         IN  HANDLE EventHandle,
284         IN  UINT EventInformationClass,
285         OUT PVOID EventInformation,
286         IN  ULONG EventInformationLength,
287         OUT PULONG  ReturnLength)
288 {
289         FIXME("(%p)\n", EventHandle);
290         return STATUS_SUCCESS;
291 }
292
293
294 /*
295  *      Timers
296  */
297
298 /**************************************************************************
299  *              NtCreateTimer                           [NTDLL.@]
300  *              ZwCreateTimer                           [NTDLL.@]
301  */
302 NTSTATUS WINAPI NtCreateTimer(OUT HANDLE *handle,
303                               IN ACCESS_MASK access,
304                               IN const OBJECT_ATTRIBUTES *oa OPTIONAL,
305                               IN TIMER_TYPE timer_type)
306 {
307     DWORD len = (oa && oa->ObjectName) ? oa->ObjectName->Length : 0;
308     NTSTATUS    status;
309
310     if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
311         return STATUS_INVALID_PARAMETER;
312
313     SERVER_START_REQ( create_timer )
314     {
315         req->manual  = (timer_type == NotificationTimer) ? TRUE : FALSE;
316         req->inherit = oa && (oa->Attributes & OBJ_INHERIT);
317         if (len) wine_server_add_data( req, oa->ObjectName->Buffer, len );
318         status = wine_server_call( req );
319         *handle = reply->handle;
320     }
321     SERVER_END_REQ;
322     return status;
323
324 }
325
326 /**************************************************************************
327  *              NtOpenTimer                             [NTDLL.@]
328  *              ZwOpenTimer                             [NTDLL.@]
329  */
330 NTSTATUS WINAPI NtOpenTimer(OUT PHANDLE handle,
331                             IN ACCESS_MASK access,
332                             IN const OBJECT_ATTRIBUTES* oa )
333 {
334     DWORD len = (oa && oa->ObjectName) ? oa->ObjectName->Length : 0;
335     NTSTATUS status;
336
337     if (oa && oa->Length >= MAX_PATH * sizeof(WCHAR))
338         return STATUS_NAME_TOO_LONG;
339
340     SERVER_START_REQ( open_timer )
341     {
342         req->access  = access;
343         req->inherit = oa && (oa->Attributes & OBJ_INHERIT);
344         if (len) wine_server_add_data( req, oa->ObjectName->Buffer, len );
345         status = wine_server_call( req );
346         *handle = reply->handle;
347     }
348     SERVER_END_REQ;
349     return status;
350 }
351
352 /**************************************************************************
353  *              NtSetTimer                              [NTDLL.@]
354  *              ZwSetTimer                              [NTDLL.@]
355  */
356 NTSTATUS WINAPI NtSetTimer(IN HANDLE handle,
357                            IN const LARGE_INTEGER* when,
358                            IN PTIMERAPCROUTINE callback,
359                            IN PVOID callback_arg,
360                            IN BOOLEAN resume,
361                            IN ULONG period OPTIONAL,
362                            OUT PBOOLEAN state OPTIONAL)
363 {
364     NTSTATUS    status = STATUS_SUCCESS;
365
366     TRACE("(%p,%p,%p,%p,%08x,0x%08lx,%p) stub\n",
367           handle, when, callback, callback_arg, resume, period, state);
368
369     SERVER_START_REQ( set_timer )
370     {
371         if (!when->u.LowPart && !when->u.HighPart)
372         {
373             /* special case to start timeout on now+period without too many calculations */
374             req->expire.sec  = 0;
375             req->expire.usec = 0;
376         }
377         else NTDLL_get_server_timeout( &req->expire, when );
378
379         req->handle   = handle;
380         req->period   = period;
381         req->callback = callback;
382         req->arg      = callback_arg;
383         status = wine_server_call( req );
384         if (state) *state = reply->signaled;
385     }
386     SERVER_END_REQ;
387
388     /* set error but can still succeed */
389     if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
390     return status;
391 }
392
393 /**************************************************************************
394  *              NtCancelTimer                           [NTDLL.@]
395  *              ZwCancelTimer                           [NTDLL.@]
396  */
397 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
398 {
399     NTSTATUS    status;
400
401     SERVER_START_REQ( cancel_timer )
402     {
403         req->handle = handle;
404         status = wine_server_call( req );
405         if (state) *state = reply->signaled;
406     }
407     SERVER_END_REQ;
408     return status;
409 }
410
411 /******************************************************************************
412  * NtQueryTimerResolution [NTDLL.@]
413  */
414 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
415                                        OUT ULONG* max_resolution,
416                                        OUT ULONG* current_resolution)
417 {
418     FIXME("(%p,%p,%p), stub!\n",
419           min_resolution, max_resolution, current_resolution);
420
421     return STATUS_NOT_IMPLEMENTED;
422 }
423
424 /******************************************************************************
425  * NtSetTimerResolution [NTDLL.@]
426  */
427 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
428                                      IN BOOLEAN set_resolution,
429                                      OUT ULONG* current_resolution )
430 {
431     FIXME("(%lu,%u,%p), stub!\n",
432           resolution, set_resolution, current_resolution);
433
434     return STATUS_NOT_IMPLEMENTED;
435 }
436
437
438 /***********************************************************************
439  *           check_async_list
440  *
441  * Process a status event from the server.
442  */
443 static void WINAPI check_async_list(async_private *asp, DWORD status)
444 {
445     async_private *ovp;
446     DWORD ovp_status;
447
448     for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
449
450     if(!ovp)
451             return;
452
453     if( status != STATUS_ALERTED )
454     {
455         ovp_status = status;
456         ovp->iosb->u.Status = status;
457     }
458     else ovp_status = ovp->iosb->u.Status;
459
460     if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
461
462     /* This will destroy all but PENDING requests */
463     register_old_async( ovp );
464 }
465
466
467 /***********************************************************************
468  *              wait_reply
469  *
470  * Wait for a reply on the waiting pipe of the current thread.
471  */
472 static int wait_reply( void *cookie )
473 {
474     int signaled;
475     struct wake_up_reply reply;
476     for (;;)
477     {
478         int ret;
479         ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
480         if (ret == sizeof(reply))
481         {
482             if (!reply.cookie) break;  /* thread got killed */
483             if (reply.cookie == cookie) return reply.signaled;
484             /* we stole another reply, wait for the real one */
485             signaled = wait_reply( cookie );
486             /* and now put the wrong one back in the pipe */
487             for (;;)
488             {
489                 ret = write( NtCurrentTeb()->wait_fd[1], &reply, sizeof(reply) );
490                 if (ret == sizeof(reply)) break;
491                 if (ret >= 0) server_protocol_error( "partial wakeup write %d\n", ret );
492                 if (errno == EINTR) continue;
493                 server_protocol_perror("wakeup write");
494             }
495             return signaled;
496         }
497         if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret );
498         if (errno == EINTR) continue;
499         server_protocol_perror("wakeup read");
500     }
501     /* the server closed the connection; time to die... */
502     server_abort_thread(0);
503 }
504
505
506 /***********************************************************************
507  *              call_apcs
508  *
509  * Call outstanding APCs.
510  */
511 static void call_apcs( BOOL alertable )
512 {
513     FARPROC proc;
514     LARGE_INTEGER time;
515     void *arg1, *arg2, *arg3;
516
517     for (;;)
518     {
519         int type = APC_NONE;
520         SERVER_START_REQ( get_apc )
521         {
522             req->alertable = alertable;
523             if (!wine_server_call( req )) type = reply->type;
524             proc = reply->func;
525             arg1 = reply->arg1;
526             arg2 = reply->arg2;
527             arg3 = reply->arg3;
528         }
529         SERVER_END_REQ;
530
531         switch(type)
532         {
533         case APC_NONE:
534             return;  /* no more APCs */
535         case APC_ASYNC:
536             proc( arg1, arg2 );
537             break;
538         case APC_USER:
539             proc( arg1, arg2, arg3 );
540             break;
541         case APC_TIMER:
542             /* convert sec/usec to NT time */
543             RtlSecondsSince1970ToTime( (time_t)arg1, &time );
544             time.QuadPart += (DWORD)arg2 * 10;
545             proc( arg3, time.u.LowPart, time.u.HighPart );
546             break;
547         case APC_ASYNC_IO:
548             check_async_list( arg1, (DWORD) arg2 );
549             break;
550         default:
551             server_protocol_error( "get_apc_request: bad type %d\n", type );
552             break;
553         }
554     }
555 }
556
557
558 /***********************************************************************
559  *              NTDLL_wait_for_multiple_objects
560  *
561  * Implementation of NtWaitForMultipleObjects
562  */
563 NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UINT flags,
564                                           const LARGE_INTEGER *timeout )
565 {
566     NTSTATUS ret;
567     int cookie;
568
569     if (timeout) flags |= SELECT_TIMEOUT;
570     for (;;)
571     {
572         SERVER_START_REQ( select )
573         {
574             req->flags   = flags;
575             req->cookie  = &cookie;
576             NTDLL_get_server_timeout( &req->timeout, timeout );
577             wine_server_add_data( req, handles, count * sizeof(HANDLE) );
578             ret = wine_server_call( req );
579         }
580         SERVER_END_REQ;
581         if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
582         if (ret != STATUS_USER_APC) break;
583         call_apcs( (flags & SELECT_ALERTABLE) != 0 );
584         if (flags & SELECT_ALERTABLE) break;
585     }
586     return ret;
587 }
588
589
590 /* wait operations */
591
592 /******************************************************************
593  *              NtWaitForMultipleObjects (NTDLL.@)
594  */
595 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
596                                           BOOLEAN wait_all, BOOLEAN alertable,
597                                           const LARGE_INTEGER *timeout )
598 {
599     UINT flags = SELECT_INTERRUPTIBLE;
600
601     if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
602
603     if (wait_all) flags |= SELECT_ALL;
604     if (alertable) flags |= SELECT_ALERTABLE;
605     return NTDLL_wait_for_multiple_objects( count, handles, flags, timeout );
606 }
607
608
609 /******************************************************************
610  *              NtWaitForSingleObject (NTDLL.@)
611  */
612 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
613 {
614     return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );
615 }
616
617
618 /******************************************************************
619  *              NtDelayExecution (NTDLL.@)
620  */
621 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
622 {
623     /* if alertable or async I/O in progress, we need to query the server */
624     if (alertable || NtCurrentTeb()->pending_list)
625     {
626         UINT flags = SELECT_INTERRUPTIBLE;
627         if (alertable) flags |= SELECT_ALERTABLE;
628         return NTDLL_wait_for_multiple_objects( 0, NULL, flags, timeout );
629     }
630
631     if (!timeout)  /* sleep forever */
632     {
633         for (;;) select( 0, NULL, NULL, NULL, NULL );
634     }
635     else
636     {
637         abs_time_t when;
638
639         NTDLL_get_server_timeout( &when, timeout );
640         for (;;)
641         {
642             struct timeval tv;
643             gettimeofday( &tv, 0 );
644             tv.tv_sec = when.sec - tv.tv_sec;
645             if ((tv.tv_usec = when.usec - tv.tv_usec) < 0)
646             {
647                 tv.tv_usec += 1000000;
648                 tv.tv_sec--;
649             }
650             if (tv.tv_sec < 0) tv.tv_sec = tv.tv_usec = 0;
651             if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
652         }
653     }
654     return STATUS_SUCCESS;
655 }