Fix the MHz detection code.
[wine/multimedia.git] / dlls / ntdll / sync.c
blob2f190247e013702814c679ab02b43e527aa0e195
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 <stdio.h>
40 #include <stdlib.h>
41 #include <time.h>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
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"
54 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
58 * Semaphores
61 /******************************************************************************
62 * NtCreateSemaphore (NTDLL.@)
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 )
70 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
71 NTSTATUS ret;
73 if ((MaximumCount <= 0) || (InitialCount > MaximumCount))
74 return STATUS_INVALID_PARAMETER;
76 SERVER_START_REQ( create_semaphore )
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;
85 SERVER_END_REQ;
86 return ret;
89 /******************************************************************************
90 * NtOpenSemaphore (NTDLL.@)
92 NTSTATUS WINAPI NtOpenSemaphore( OUT PHANDLE SemaphoreHandle,
93 IN ACCESS_MASK access,
94 IN const OBJECT_ATTRIBUTES *attr )
96 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
97 NTSTATUS ret;
99 SERVER_START_REQ( open_semaphore )
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;
107 SERVER_END_REQ;
108 return ret;
111 /******************************************************************************
112 * NtQuerySemaphore (NTDLL.@)
114 NTSTATUS WINAPI NtQuerySemaphore(
115 HANDLE SemaphoreHandle,
116 PVOID SemaphoreInformationClass,
117 OUT PVOID SemaphoreInformation,
118 ULONG Length,
119 PULONG ReturnLength)
121 FIXME("(%p,%p,%p,0x%08lx,%p) stub!\n",
122 SemaphoreHandle, SemaphoreInformationClass, SemaphoreInformation, Length, ReturnLength);
123 return STATUS_SUCCESS;
126 /******************************************************************************
127 * NtReleaseSemaphore (NTDLL.@)
129 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
131 NTSTATUS ret;
132 SERVER_START_REQ( release_semaphore )
134 req->handle = handle;
135 req->count = count;
136 if (!(ret = wine_server_call( req )))
138 if (previous) *previous = reply->prev_count;
141 SERVER_END_REQ;
142 return ret;
146 * Events
149 /**************************************************************************
150 * NtCreateEvent (NTDLL.@)
151 * ZwCreateEvent (NTDLL.@)
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)
160 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
161 NTSTATUS ret;
163 SERVER_START_REQ( create_event )
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;
172 SERVER_END_REQ;
173 return ret;
176 /******************************************************************************
177 * NtOpenEvent (NTDLL.@)
178 * ZwOpenEvent (NTDLL.@)
180 NTSTATUS WINAPI NtOpenEvent(
181 OUT PHANDLE EventHandle,
182 IN ACCESS_MASK DesiredAccess,
183 IN const OBJECT_ATTRIBUTES *attr )
185 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
186 NTSTATUS ret;
188 SERVER_START_REQ( open_event )
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;
196 SERVER_END_REQ;
197 return ret;
201 /******************************************************************************
202 * NtSetEvent (NTDLL.@)
203 * ZwSetEvent (NTDLL.@)
205 NTSTATUS WINAPI NtSetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
207 NTSTATUS ret;
209 /* FIXME: set NumberOfThreadsReleased */
211 SERVER_START_REQ( event_op )
213 req->handle = handle;
214 req->op = SET_EVENT;
215 ret = wine_server_call( req );
217 SERVER_END_REQ;
218 return ret;
221 /******************************************************************************
222 * NtResetEvent (NTDLL.@)
224 NTSTATUS WINAPI NtResetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
226 NTSTATUS ret;
228 /* resetting an event can't release any thread... */
229 if (NumberOfThreadsReleased) *NumberOfThreadsReleased = 0;
231 SERVER_START_REQ( event_op )
233 req->handle = handle;
234 req->op = RESET_EVENT;
235 ret = wine_server_call( req );
237 SERVER_END_REQ;
238 return ret;
241 /******************************************************************************
242 * NtClearEvent (NTDLL.@)
244 * FIXME
245 * same as NtResetEvent ???
247 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
249 return NtResetEvent( handle, NULL );
252 /******************************************************************************
253 * NtPulseEvent (NTDLL.@)
255 * FIXME
256 * PulseCount
258 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, PULONG PulseCount )
260 NTSTATUS ret;
261 FIXME("(%p,%p)\n", handle, PulseCount);
262 SERVER_START_REQ( event_op )
264 req->handle = handle;
265 req->op = PULSE_EVENT;
266 ret = wine_server_call( req );
268 SERVER_END_REQ;
269 return ret;
272 /******************************************************************************
273 * NtQueryEvent (NTDLL.@)
275 NTSTATUS WINAPI NtQueryEvent (
276 IN HANDLE EventHandle,
277 IN UINT EventInformationClass,
278 OUT PVOID EventInformation,
279 IN ULONG EventInformationLength,
280 OUT PULONG ReturnLength)
282 FIXME("(%p)\n", EventHandle);
283 return STATUS_SUCCESS;
288 * Timers
291 /**************************************************************************
292 * NtCreateTimer [NTDLL.@]
293 * ZwCreateTimer [NTDLL.@]
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)
300 DWORD len = (oa && oa->ObjectName) ? oa->ObjectName->Length : 0;
301 NTSTATUS status;
303 if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
304 return STATUS_INVALID_PARAMETER;
306 SERVER_START_REQ( create_timer )
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;
314 SERVER_END_REQ;
315 return status;
319 /**************************************************************************
320 * NtOpenTimer [NTDLL.@]
321 * ZwOpenTimer [NTDLL.@]
323 NTSTATUS WINAPI NtOpenTimer(OUT PHANDLE handle,
324 IN ACCESS_MASK access,
325 IN const OBJECT_ATTRIBUTES* oa )
327 DWORD len = (oa && oa->ObjectName) ? oa->ObjectName->Length : 0;
328 NTSTATUS status;
330 if (oa && oa->Length >= MAX_PATH * sizeof(WCHAR))
331 return STATUS_NAME_TOO_LONG;
333 SERVER_START_REQ( open_timer )
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;
341 SERVER_END_REQ;
342 return status;
345 /**************************************************************************
346 * NtSetTimer [NTDLL.@]
347 * ZwSetTimer [NTDLL.@]
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)
357 NTSTATUS status = STATUS_SUCCESS;
359 TRACE("(%p,%p,%p,%p,%08x,0x%08lx,%p) stub\n",
360 handle, when, callback, callback_arg, resume, period, state);
362 SERVER_START_REQ( set_timer )
364 if (!when->s.LowPart && !when->s.HighPart)
366 /* special case to start timeout on now+period without too many calculations */
367 req->expire.sec = 0;
368 req->expire.usec = 0;
370 else NTDLL_get_server_timeout( &req->expire, when );
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;
379 SERVER_END_REQ;
381 /* set error but can still succeed */
382 if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
383 return status;
386 /**************************************************************************
387 * NtCancelTimer [NTDLL.@]
388 * ZwCancelTimer [NTDLL.@]
390 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
392 NTSTATUS status;
394 SERVER_START_REQ( cancel_timer )
396 req->handle = handle;
397 status = wine_server_call( req );
398 if (state) *state = reply->signaled;
400 SERVER_END_REQ;
401 return status;
404 /******************************************************************************
405 * NtQueryTimerResolution [NTDLL.@]
407 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
408 OUT ULONG* max_resolution,
409 OUT ULONG* current_resolution)
411 FIXME("(%p,%p,%p), stub!\n",
412 min_resolution, max_resolution, current_resolution);
414 return STATUS_NOT_IMPLEMENTED;
417 /******************************************************************************
418 * NtSetTimerResolution [NTDLL.@]
420 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
421 IN BOOLEAN set_resolution,
422 OUT ULONG* current_resolution )
424 FIXME("(%lu,%u,%p), stub!\n",
425 resolution, set_resolution, current_resolution);
427 return STATUS_NOT_IMPLEMENTED;
431 /***********************************************************************
432 * check_async_list
434 * Process a status event from the server.
436 static void WINAPI check_async_list(async_private *asp, DWORD status)
438 async_private *ovp;
439 DWORD ovp_status;
441 for( ovp = NtCurrentTeb()->pending_list; ovp && ovp != asp; ovp = ovp->next );
443 if(!ovp)
444 return;
446 if( status != STATUS_ALERTED )
448 ovp_status = status;
449 ovp->iosb->u.Status = status;
451 else ovp_status = ovp->iosb->u.Status;
453 if( ovp_status == STATUS_PENDING ) ovp->func( ovp );
455 /* This will destroy all but PENDING requests */
456 register_old_async( ovp );
460 /***********************************************************************
461 * wait_reply
463 * Wait for a reply on the waiting pipe of the current thread.
465 static int wait_reply( void *cookie )
467 int signaled;
468 struct wake_up_reply reply;
469 for (;;)
471 int ret;
472 ret = read( NtCurrentTeb()->wait_fd[0], &reply, sizeof(reply) );
473 if (ret == sizeof(reply))
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 (;;)
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");
488 return signaled;
490 if (ret >= 0) server_protocol_error( "partial wakeup read %d\n", ret );
491 if (errno == EINTR) continue;
492 server_protocol_perror("wakeup read");
494 /* the server closed the connection; time to die... */
495 SYSDEPS_AbortThread(0);
499 /***********************************************************************
500 * call_apcs
502 * Call outstanding APCs.
504 static void call_apcs( BOOL alertable )
506 FARPROC proc;
507 LARGE_INTEGER time;
508 void *arg1, *arg2, *arg3;
510 for (;;)
512 int type = APC_NONE;
513 SERVER_START_REQ( get_apc )
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;
522 SERVER_END_REQ;
524 switch(type)
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;
551 /***********************************************************************
552 * NTDLL_wait_for_multiple_objects
554 * Implementation of NtWaitForMultipleObjects
556 NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UINT flags,
557 const LARGE_INTEGER *timeout )
559 NTSTATUS ret;
560 int cookie;
562 if (timeout) flags |= SELECT_TIMEOUT;
563 for (;;)
565 SERVER_START_REQ( select )
567 req->flags = flags;
568 req->cookie = &cookie;
569 NTDLL_get_server_timeout( &req->timeout, timeout );
570 wine_server_add_data( req, handles, count * sizeof(HANDLE) );
571 ret = wine_server_call( req );
573 SERVER_END_REQ;
574 if (ret == STATUS_PENDING) ret = wait_reply( &cookie );
575 if (ret != STATUS_USER_APC) break;
576 call_apcs( (flags & SELECT_ALERTABLE) != 0 );
577 if (flags & SELECT_ALERTABLE) break;
579 return ret;
583 /* wait operations */
585 /******************************************************************
586 * NtWaitForMultipleObjects (NTDLL.@)
588 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
589 BOOLEAN wait_all, BOOLEAN alertable,
590 const LARGE_INTEGER *timeout )
592 UINT flags = SELECT_INTERRUPTIBLE;
594 if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
596 if (wait_all) flags |= SELECT_ALL;
597 if (alertable) flags |= SELECT_ALERTABLE;
598 return NTDLL_wait_for_multiple_objects( count, handles, flags, timeout );
602 /******************************************************************
603 * NtWaitForSingleObject (NTDLL.@)
605 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
607 return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );
611 /******************************************************************
612 * NtDelayExecution (NTDLL.@)
614 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
616 /* if alertable or async I/O in progress, we need to query the server */
617 if (alertable || NtCurrentTeb()->pending_list)
619 UINT flags = SELECT_INTERRUPTIBLE;
620 if (alertable) flags |= SELECT_ALERTABLE;
621 return NTDLL_wait_for_multiple_objects( 0, NULL, flags, timeout );
624 if (!timeout) /* sleep forever */
626 for (;;) select( 0, NULL, NULL, NULL, NULL );
628 else
630 abs_time_t when;
632 NTDLL_get_server_timeout( &when, timeout );
633 for (;;)
635 struct timeval tv;
636 gettimeofday( &tv, 0 );
637 tv.tv_sec = when.sec - tv.tv_sec;
638 if ((tv.tv_usec = when.usec - tv.tv_usec) < 0)
640 tv.tv_usec += 1000000;
641 tv.tv_sec--;
643 if (tv.tv_sec < 0) tv.tv_sec = tv.tv_usec = 0;
644 if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
647 return STATUS_SUCCESS;