Fixed TrackPopupMenu return value (based on a patch by Andreas
[wine/multimedia.git] / dlls / ntdll / sync.c
blobb2e281355a3c667c0d7ddcdd78604dcf136d2cd8
1 /*
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "config.h"
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>
44 #define NONAMELESSUNION
45 #define NONAMELESSSTRUCT
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"
58 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
62 * Semaphores
65 /******************************************************************************
66 * NtCreateSemaphore (NTDLL.@)
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 )
74 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
75 NTSTATUS ret;
77 if ((MaximumCount <= 0) || (InitialCount > MaximumCount))
78 return STATUS_INVALID_PARAMETER;
80 SERVER_START_REQ( create_semaphore )
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;
89 SERVER_END_REQ;
90 return ret;
93 /******************************************************************************
94 * NtOpenSemaphore (NTDLL.@)
96 NTSTATUS WINAPI NtOpenSemaphore( OUT PHANDLE SemaphoreHandle,
97 IN ACCESS_MASK access,
98 IN const OBJECT_ATTRIBUTES *attr )
100 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
101 NTSTATUS ret;
103 SERVER_START_REQ( open_semaphore )
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;
111 SERVER_END_REQ;
112 return ret;
115 /******************************************************************************
116 * NtQuerySemaphore (NTDLL.@)
118 NTSTATUS WINAPI NtQuerySemaphore(
119 HANDLE SemaphoreHandle,
120 PVOID SemaphoreInformationClass,
121 OUT PVOID SemaphoreInformation,
122 ULONG Length,
123 PULONG ReturnLength)
125 FIXME("(%p,%p,%p,0x%08lx,%p) stub!\n",
126 SemaphoreHandle, SemaphoreInformationClass, SemaphoreInformation, Length, ReturnLength);
127 return STATUS_SUCCESS;
130 /******************************************************************************
131 * NtReleaseSemaphore (NTDLL.@)
133 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
135 NTSTATUS ret;
136 SERVER_START_REQ( release_semaphore )
138 req->handle = handle;
139 req->count = count;
140 if (!(ret = wine_server_call( req )))
142 if (previous) *previous = reply->prev_count;
145 SERVER_END_REQ;
146 return ret;
150 * Events
153 /**************************************************************************
154 * NtCreateEvent (NTDLL.@)
155 * ZwCreateEvent (NTDLL.@)
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)
164 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
165 NTSTATUS ret;
167 SERVER_START_REQ( create_event )
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;
176 SERVER_END_REQ;
177 return ret;
180 /******************************************************************************
181 * NtOpenEvent (NTDLL.@)
182 * ZwOpenEvent (NTDLL.@)
184 NTSTATUS WINAPI NtOpenEvent(
185 OUT PHANDLE EventHandle,
186 IN ACCESS_MASK DesiredAccess,
187 IN const OBJECT_ATTRIBUTES *attr )
189 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
190 NTSTATUS ret;
192 SERVER_START_REQ( open_event )
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;
200 SERVER_END_REQ;
201 return ret;
205 /******************************************************************************
206 * NtSetEvent (NTDLL.@)
207 * ZwSetEvent (NTDLL.@)
209 NTSTATUS WINAPI NtSetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
211 NTSTATUS ret;
213 /* FIXME: set NumberOfThreadsReleased */
215 SERVER_START_REQ( event_op )
217 req->handle = handle;
218 req->op = SET_EVENT;
219 ret = wine_server_call( req );
221 SERVER_END_REQ;
222 return ret;
225 /******************************************************************************
226 * NtResetEvent (NTDLL.@)
228 NTSTATUS WINAPI NtResetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
230 NTSTATUS ret;
232 /* resetting an event can't release any thread... */
233 if (NumberOfThreadsReleased) *NumberOfThreadsReleased = 0;
235 SERVER_START_REQ( event_op )
237 req->handle = handle;
238 req->op = RESET_EVENT;
239 ret = wine_server_call( req );
241 SERVER_END_REQ;
242 return ret;
245 /******************************************************************************
246 * NtClearEvent (NTDLL.@)
248 * FIXME
249 * same as NtResetEvent ???
251 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
253 return NtResetEvent( handle, NULL );
256 /******************************************************************************
257 * NtPulseEvent (NTDLL.@)
259 * FIXME
260 * PulseCount
262 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, PULONG PulseCount )
264 NTSTATUS ret;
265 FIXME("(%p,%p)\n", handle, PulseCount);
266 SERVER_START_REQ( event_op )
268 req->handle = handle;
269 req->op = PULSE_EVENT;
270 ret = wine_server_call( req );
272 SERVER_END_REQ;
273 return ret;
276 /******************************************************************************
277 * NtQueryEvent (NTDLL.@)
279 NTSTATUS WINAPI NtQueryEvent (
280 IN HANDLE EventHandle,
281 IN UINT EventInformationClass,
282 OUT PVOID EventInformation,
283 IN ULONG EventInformationLength,
284 OUT PULONG ReturnLength)
286 FIXME("(%p)\n", EventHandle);
287 return STATUS_SUCCESS;
292 * Timers
295 /**************************************************************************
296 * NtCreateTimer [NTDLL.@]
297 * ZwCreateTimer [NTDLL.@]
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)
304 DWORD len = (oa && oa->ObjectName) ? oa->ObjectName->Length : 0;
305 NTSTATUS status;
307 if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
308 return STATUS_INVALID_PARAMETER;
310 SERVER_START_REQ( create_timer )
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;
318 SERVER_END_REQ;
319 return status;
323 /**************************************************************************
324 * NtOpenTimer [NTDLL.@]
325 * ZwOpenTimer [NTDLL.@]
327 NTSTATUS WINAPI NtOpenTimer(OUT PHANDLE handle,
328 IN ACCESS_MASK access,
329 IN const OBJECT_ATTRIBUTES* oa )
331 DWORD len = (oa && oa->ObjectName) ? oa->ObjectName->Length : 0;
332 NTSTATUS status;
334 if (oa && oa->Length >= MAX_PATH * sizeof(WCHAR))
335 return STATUS_NAME_TOO_LONG;
337 SERVER_START_REQ( open_timer )
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;
345 SERVER_END_REQ;
346 return status;
349 /**************************************************************************
350 * NtSetTimer [NTDLL.@]
351 * ZwSetTimer [NTDLL.@]
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)
361 NTSTATUS status = STATUS_SUCCESS;
363 TRACE("(%p,%p,%p,%p,%08x,0x%08lx,%p) stub\n",
364 handle, when, callback, callback_arg, resume, period, state);
366 SERVER_START_REQ( set_timer )
368 if (!when->u.LowPart && !when->u.HighPart)
370 /* special case to start timeout on now+period without too many calculations */
371 req->expire.sec = 0;
372 req->expire.usec = 0;
374 else NTDLL_get_server_timeout( &req->expire, when );
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;
383 SERVER_END_REQ;
385 /* set error but can still succeed */
386 if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
387 return status;
390 /**************************************************************************
391 * NtCancelTimer [NTDLL.@]
392 * ZwCancelTimer [NTDLL.@]
394 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
396 NTSTATUS status;
398 SERVER_START_REQ( cancel_timer )
400 req->handle = handle;
401 status = wine_server_call( req );
402 if (state) *state = reply->signaled;
404 SERVER_END_REQ;
405 return status;
408 /******************************************************************************
409 * NtQueryTimerResolution [NTDLL.@]
411 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
412 OUT ULONG* max_resolution,
413 OUT ULONG* current_resolution)
415 FIXME("(%p,%p,%p), stub!\n",
416 min_resolution, max_resolution, current_resolution);
418 return STATUS_NOT_IMPLEMENTED;
421 /******************************************************************************
422 * NtSetTimerResolution [NTDLL.@]
424 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
425 IN BOOLEAN set_resolution,
426 OUT ULONG* current_resolution )
428 FIXME("(%lu,%u,%p), stub!\n",
429 resolution, set_resolution, current_resolution);
431 return STATUS_NOT_IMPLEMENTED;
435 /***********************************************************************
436 * check_async_list
438 * Process a status event from the server.
440 static void WINAPI check_async_list(async_private *asp, DWORD status)
442 async_private *ovp;
443 DWORD ovp_status;
445 for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
447 if(!ovp)
448 return;
450 if( status != STATUS_ALERTED )
452 ovp_status = status;
453 ovp->iosb->u.Status = status;
455 else ovp_status = ovp->iosb->u.Status;
457 if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
459 /* This will destroy all but PENDING requests */
460 register_old_async( ovp );
464 /***********************************************************************
465 * wait_reply
467 * Wait for a reply on the waiting pipe of the current thread.
469 static int wait_reply( void *cookie )
471 int signaled;
472 struct wake_up_reply reply;
473 for (;;)
475 int ret;
476 ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
477 if (ret == sizeof(reply))
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 (;;)
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");
492 return signaled;
494 if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret );
495 if (errno == EINTR) continue;
496 server_protocol_perror("wakeup read");
498 /* the server closed the connection; time to die... */
499 server_abort_thread(0);
503 /***********************************************************************
504 * call_apcs
506 * Call outstanding APCs.
508 static void call_apcs( BOOL alertable )
510 FARPROC proc;
511 LARGE_INTEGER time;
512 void *arg1, *arg2, *arg3;
514 for (;;)
516 int type = APC_NONE;
517 SERVER_START_REQ( get_apc )
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;
526 SERVER_END_REQ;
528 switch(type)
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;
555 /***********************************************************************
556 * NTDLL_wait_for_multiple_objects
558 * Implementation of NtWaitForMultipleObjects
560 NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UINT flags,
561 const LARGE_INTEGER *timeout )
563 NTSTATUS ret;
564 int cookie;
566 if (timeout) flags |= SELECT_TIMEOUT;
567 for (;;)
569 SERVER_START_REQ( select )
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 );
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;
583 return ret;
587 /* wait operations */
589 /******************************************************************
590 * NtWaitForMultipleObjects (NTDLL.@)
592 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
593 BOOLEAN wait_all, BOOLEAN alertable,
594 const LARGE_INTEGER *timeout )
596 UINT flags = SELECT_INTERRUPTIBLE;
598 if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
600 if (wait_all) flags |= SELECT_ALL;
601 if (alertable) flags |= SELECT_ALERTABLE;
602 return NTDLL_wait_for_multiple_objects( count, handles, flags, timeout );
606 /******************************************************************
607 * NtWaitForSingleObject (NTDLL.@)
609 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
611 return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );
615 /******************************************************************
616 * NtDelayExecution (NTDLL.@)
618 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
620 /* if alertable or async I/O in progress, we need to query the server */
621 if (alertable || NtCurrentTeb()->pending_list)
623 UINT flags = SELECT_INTERRUPTIBLE;
624 if (alertable) flags |= SELECT_ALERTABLE;
625 return NTDLL_wait_for_multiple_objects( 0, NULL, flags, timeout );
628 if (!timeout) /* sleep forever */
630 for (;;) select( 0, NULL, NULL, NULL, NULL );
632 else
634 abs_time_t when;
636 NTDLL_get_server_timeout( &when, timeout );
637 for (;;)
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)
644 tv.tv_usec += 1000000;
645 tv.tv_sec--;
647 if (tv.tv_sec < 0) tv.tv_sec = tv.tv_usec = 0;
648 if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
651 return STATUS_SUCCESS;