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
29 #ifdef HAVE_SYS_TIME_H
30 # include <sys/time.h>
32 #ifdef HAVE_SYS_POLL_H
33 # include <sys/poll.h>
47 #define NONAMELESSUNION
48 #define NONAMELESSSTRUCT
56 #include "wine/server.h"
57 #include "wine/unicode.h"
58 #include "wine/debug.h"
59 #include "ntdll_misc.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(ntdll
);
68 /******************************************************************************
69 * NtCreateSemaphore (NTDLL.@)
71 NTSTATUS WINAPI
NtCreateSemaphore( OUT PHANDLE SemaphoreHandle
,
72 IN ACCESS_MASK access
,
73 IN
const OBJECT_ATTRIBUTES
*attr OPTIONAL
,
74 IN ULONG InitialCount
,
75 IN ULONG MaximumCount
)
77 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
80 if ((MaximumCount
<= 0) || (InitialCount
> MaximumCount
))
81 return STATUS_INVALID_PARAMETER
;
83 SERVER_START_REQ( create_semaphore
)
85 req
->initial
= InitialCount
;
86 req
->max
= MaximumCount
;
87 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
88 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
89 ret
= wine_server_call( req
);
90 *SemaphoreHandle
= reply
->handle
;
96 /******************************************************************************
97 * NtOpenSemaphore (NTDLL.@)
99 NTSTATUS WINAPI
NtOpenSemaphore( OUT PHANDLE SemaphoreHandle
,
100 IN ACCESS_MASK access
,
101 IN
const OBJECT_ATTRIBUTES
*attr
)
103 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
106 SERVER_START_REQ( open_semaphore
)
108 req
->access
= access
;
109 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
110 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
111 ret
= wine_server_call( req
);
112 *SemaphoreHandle
= reply
->handle
;
118 /******************************************************************************
119 * NtQuerySemaphore (NTDLL.@)
121 NTSTATUS WINAPI
NtQuerySemaphore(
122 HANDLE SemaphoreHandle
,
123 PVOID SemaphoreInformationClass
,
124 OUT PVOID SemaphoreInformation
,
128 FIXME("(%p,%p,%p,0x%08lx,%p) stub!\n",
129 SemaphoreHandle
, SemaphoreInformationClass
, SemaphoreInformation
, Length
, ReturnLength
);
130 return STATUS_SUCCESS
;
133 /******************************************************************************
134 * NtReleaseSemaphore (NTDLL.@)
136 NTSTATUS WINAPI
NtReleaseSemaphore( HANDLE handle
, ULONG count
, PULONG previous
)
139 SERVER_START_REQ( release_semaphore
)
141 req
->handle
= handle
;
143 if (!(ret
= wine_server_call( req
)))
145 if (previous
) *previous
= reply
->prev_count
;
156 /**************************************************************************
157 * NtCreateEvent (NTDLL.@)
158 * ZwCreateEvent (NTDLL.@)
160 NTSTATUS WINAPI
NtCreateEvent(
161 OUT PHANDLE EventHandle
,
162 IN ACCESS_MASK DesiredAccess
,
163 IN
const OBJECT_ATTRIBUTES
*attr
,
164 IN BOOLEAN ManualReset
,
165 IN BOOLEAN InitialState
)
167 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
170 SERVER_START_REQ( create_event
)
172 req
->manual_reset
= ManualReset
;
173 req
->initial_state
= InitialState
;
174 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
175 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
176 ret
= wine_server_call( req
);
177 *EventHandle
= reply
->handle
;
183 /******************************************************************************
184 * NtOpenEvent (NTDLL.@)
185 * ZwOpenEvent (NTDLL.@)
187 NTSTATUS WINAPI
NtOpenEvent(
188 OUT PHANDLE EventHandle
,
189 IN ACCESS_MASK DesiredAccess
,
190 IN
const OBJECT_ATTRIBUTES
*attr
)
192 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
195 SERVER_START_REQ( open_event
)
197 req
->access
= DesiredAccess
;
198 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
199 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
200 ret
= wine_server_call( req
);
201 *EventHandle
= reply
->handle
;
208 /******************************************************************************
209 * NtSetEvent (NTDLL.@)
210 * ZwSetEvent (NTDLL.@)
212 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
216 /* FIXME: set NumberOfThreadsReleased */
218 SERVER_START_REQ( event_op
)
220 req
->handle
= handle
;
222 ret
= wine_server_call( req
);
228 /******************************************************************************
229 * NtResetEvent (NTDLL.@)
231 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
235 /* resetting an event can't release any thread... */
236 if (NumberOfThreadsReleased
) *NumberOfThreadsReleased
= 0;
238 SERVER_START_REQ( event_op
)
240 req
->handle
= handle
;
241 req
->op
= RESET_EVENT
;
242 ret
= wine_server_call( req
);
248 /******************************************************************************
249 * NtClearEvent (NTDLL.@)
252 * same as NtResetEvent ???
254 NTSTATUS WINAPI
NtClearEvent ( HANDLE handle
)
256 return NtResetEvent( handle
, NULL
);
259 /******************************************************************************
260 * NtPulseEvent (NTDLL.@)
265 NTSTATUS WINAPI
NtPulseEvent( HANDLE handle
, PULONG PulseCount
)
270 FIXME("(%p,%ld)\n", handle
, *PulseCount
);
272 SERVER_START_REQ( event_op
)
274 req
->handle
= handle
;
275 req
->op
= PULSE_EVENT
;
276 ret
= wine_server_call( req
);
282 /******************************************************************************
283 * NtQueryEvent (NTDLL.@)
285 NTSTATUS WINAPI
NtQueryEvent (
286 IN HANDLE EventHandle
,
287 IN UINT EventInformationClass
,
288 OUT PVOID EventInformation
,
289 IN ULONG EventInformationLength
,
290 OUT PULONG ReturnLength
)
292 FIXME("(%p)\n", EventHandle
);
293 return STATUS_SUCCESS
;
301 /**************************************************************************
302 * NtCreateTimer [NTDLL.@]
303 * ZwCreateTimer [NTDLL.@]
305 NTSTATUS WINAPI
NtCreateTimer(OUT HANDLE
*handle
,
306 IN ACCESS_MASK access
,
307 IN
const OBJECT_ATTRIBUTES
*oa OPTIONAL
,
308 IN TIMER_TYPE timer_type
)
310 DWORD len
= (oa
&& oa
->ObjectName
) ? oa
->ObjectName
->Length
: 0;
313 if (timer_type
!= NotificationTimer
&& timer_type
!= SynchronizationTimer
)
314 return STATUS_INVALID_PARAMETER
;
316 SERVER_START_REQ( create_timer
)
318 req
->manual
= (timer_type
== NotificationTimer
) ? TRUE
: FALSE
;
319 req
->inherit
= oa
&& (oa
->Attributes
& OBJ_INHERIT
);
320 if (len
) wine_server_add_data( req
, oa
->ObjectName
->Buffer
, len
);
321 status
= wine_server_call( req
);
322 *handle
= reply
->handle
;
329 /**************************************************************************
330 * NtOpenTimer [NTDLL.@]
331 * ZwOpenTimer [NTDLL.@]
333 NTSTATUS WINAPI
NtOpenTimer(OUT PHANDLE handle
,
334 IN ACCESS_MASK access
,
335 IN
const OBJECT_ATTRIBUTES
* oa
)
337 DWORD len
= (oa
&& oa
->ObjectName
) ? oa
->ObjectName
->Length
: 0;
340 if (oa
&& oa
->Length
>= MAX_PATH
* sizeof(WCHAR
))
341 return STATUS_NAME_TOO_LONG
;
343 SERVER_START_REQ( open_timer
)
345 req
->access
= access
;
346 req
->inherit
= oa
&& (oa
->Attributes
& OBJ_INHERIT
);
347 if (len
) wine_server_add_data( req
, oa
->ObjectName
->Buffer
, len
);
348 status
= wine_server_call( req
);
349 *handle
= reply
->handle
;
355 /**************************************************************************
356 * NtSetTimer [NTDLL.@]
357 * ZwSetTimer [NTDLL.@]
359 NTSTATUS WINAPI
NtSetTimer(IN HANDLE handle
,
360 IN
const LARGE_INTEGER
* when
,
361 IN PTIMERAPCROUTINE callback
,
362 IN PVOID callback_arg
,
364 IN ULONG period OPTIONAL
,
365 OUT PBOOLEAN state OPTIONAL
)
367 NTSTATUS status
= STATUS_SUCCESS
;
369 TRACE("(%p,%p,%p,%p,%08x,0x%08lx,%p) stub\n",
370 handle
, when
, callback
, callback_arg
, resume
, period
, state
);
372 SERVER_START_REQ( set_timer
)
374 if (!when
->u
.LowPart
&& !when
->u
.HighPart
)
376 /* special case to start timeout on now+period without too many calculations */
378 req
->expire
.usec
= 0;
380 else NTDLL_get_server_timeout( &req
->expire
, when
);
382 req
->handle
= handle
;
383 req
->period
= period
;
384 req
->callback
= callback
;
385 req
->arg
= callback_arg
;
386 status
= wine_server_call( req
);
387 if (state
) *state
= reply
->signaled
;
391 /* set error but can still succeed */
392 if (resume
&& status
== STATUS_SUCCESS
) return STATUS_TIMER_RESUME_IGNORED
;
396 /**************************************************************************
397 * NtCancelTimer [NTDLL.@]
398 * ZwCancelTimer [NTDLL.@]
400 NTSTATUS WINAPI
NtCancelTimer(IN HANDLE handle
, OUT BOOLEAN
* state
)
404 SERVER_START_REQ( cancel_timer
)
406 req
->handle
= handle
;
407 status
= wine_server_call( req
);
408 if (state
) *state
= reply
->signaled
;
414 /******************************************************************************
415 * NtQueryTimerResolution [NTDLL.@]
417 NTSTATUS WINAPI
NtQueryTimerResolution(OUT ULONG
* min_resolution
,
418 OUT ULONG
* max_resolution
,
419 OUT ULONG
* current_resolution
)
421 FIXME("(%p,%p,%p), stub!\n",
422 min_resolution
, max_resolution
, current_resolution
);
424 return STATUS_NOT_IMPLEMENTED
;
427 /******************************************************************************
428 * NtSetTimerResolution [NTDLL.@]
430 NTSTATUS WINAPI
NtSetTimerResolution(IN ULONG resolution
,
431 IN BOOLEAN set_resolution
,
432 OUT ULONG
* current_resolution
)
434 FIXME("(%lu,%u,%p), stub!\n",
435 resolution
, set_resolution
, current_resolution
);
437 return STATUS_NOT_IMPLEMENTED
;
441 /***********************************************************************
444 * Process a status event from the server.
446 static void WINAPI
check_async_list(async_private
*asp
, DWORD status
)
451 for( ovp
= NtCurrentTeb()->pending_list
; ovp
&& ovp
!= asp
; ovp
= ovp
->next
);
456 if( status
!= STATUS_ALERTED
)
459 ovp
->iosb
->u
.Status
= status
;
461 else ovp_status
= ovp
->iosb
->u
.Status
;
463 if( ovp_status
== STATUS_PENDING
) ovp
->func( ovp
);
465 /* This will destroy all but PENDING requests */
466 register_old_async( ovp
);
470 /***********************************************************************
473 * Wait for a reply on the waiting pipe of the current thread.
475 static int wait_reply( void *cookie
)
478 struct wake_up_reply reply
;
482 ret
= read( NtCurrentTeb()->wait_fd
[0], &reply
, sizeof(reply
) );
483 if (ret
== sizeof(reply
))
485 if (!reply
.cookie
) break; /* thread got killed */
486 if (reply
.cookie
== cookie
) return reply
.signaled
;
487 /* we stole another reply, wait for the real one */
488 signaled
= wait_reply( cookie
);
489 /* and now put the wrong one back in the pipe */
492 ret
= write( NtCurrentTeb()->wait_fd
[1], &reply
, sizeof(reply
) );
493 if (ret
== sizeof(reply
)) break;
494 if (ret
>= 0) server_protocol_error( "partial wakeup write %d\n", ret
);
495 if (errno
== EINTR
) continue;
496 server_protocol_perror("wakeup write");
500 if (ret
>= 0) server_protocol_error( "partial wakeup read %d\n", ret
);
501 if (errno
== EINTR
) continue;
502 server_protocol_perror("wakeup read");
504 /* the server closed the connection; time to die... */
505 server_abort_thread(0);
509 /***********************************************************************
512 * Call outstanding APCs.
514 static void call_apcs( BOOL alertable
)
518 void *arg1
, *arg2
, *arg3
;
523 SERVER_START_REQ( get_apc
)
525 req
->alertable
= alertable
;
526 if (!wine_server_call( req
)) type
= reply
->type
;
537 return; /* no more APCs */
542 proc( arg1
, arg2
, arg3
);
545 /* convert sec/usec to NT time */
546 RtlSecondsSince1970ToTime( (time_t)arg1
, &time
);
547 time
.QuadPart
+= (DWORD
)arg2
* 10;
548 proc( arg3
, time
.u
.LowPart
, time
.u
.HighPart
);
551 check_async_list( arg1
, (DWORD
) arg2
);
554 server_protocol_error( "get_apc_request: bad type %d\n", type
);
561 /***********************************************************************
562 * NTDLL_wait_for_multiple_objects
564 * Implementation of NtWaitForMultipleObjects
566 NTSTATUS
NTDLL_wait_for_multiple_objects( UINT count
, const HANDLE
*handles
, UINT flags
,
567 const LARGE_INTEGER
*timeout
)
572 if (timeout
) flags
|= SELECT_TIMEOUT
;
575 SERVER_START_REQ( select
)
578 req
->cookie
= &cookie
;
579 NTDLL_get_server_timeout( &req
->timeout
, timeout
);
580 wine_server_add_data( req
, handles
, count
* sizeof(HANDLE
) );
581 ret
= wine_server_call( req
);
584 if (ret
== STATUS_PENDING
) ret
= wait_reply( &cookie
);
585 if (ret
!= STATUS_USER_APC
) break;
586 call_apcs( (flags
& SELECT_ALERTABLE
) != 0 );
587 if (flags
& SELECT_ALERTABLE
) break;
593 /* wait operations */
595 /******************************************************************
596 * NtWaitForMultipleObjects (NTDLL.@)
598 NTSTATUS WINAPI
NtWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
,
599 BOOLEAN wait_all
, BOOLEAN alertable
,
600 const LARGE_INTEGER
*timeout
)
602 UINT flags
= SELECT_INTERRUPTIBLE
;
604 if (!count
|| count
> MAXIMUM_WAIT_OBJECTS
) return STATUS_INVALID_PARAMETER_1
;
606 if (wait_all
) flags
|= SELECT_ALL
;
607 if (alertable
) flags
|= SELECT_ALERTABLE
;
608 return NTDLL_wait_for_multiple_objects( count
, handles
, flags
, timeout
);
612 /******************************************************************
613 * NtWaitForSingleObject (NTDLL.@)
615 NTSTATUS WINAPI
NtWaitForSingleObject(HANDLE handle
, BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
617 return NtWaitForMultipleObjects( 1, &handle
, FALSE
, alertable
, timeout
);
621 /******************************************************************
622 * NtYieldExecution (NTDLL.@)
624 NTSTATUS WINAPI
NtYieldExecution(void)
626 #ifdef HAVE_SCHED_YIELD
628 return STATUS_SUCCESS
;
630 return STATUS_NO_YIELD_PERFORMED
;
635 /******************************************************************
636 * NtDelayExecution (NTDLL.@)
638 NTSTATUS WINAPI
NtDelayExecution( BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
640 /* if alertable or async I/O in progress, we need to query the server */
641 if (alertable
|| NtCurrentTeb()->pending_list
)
643 UINT flags
= SELECT_INTERRUPTIBLE
;
644 if (alertable
) flags
|= SELECT_ALERTABLE
;
645 return NTDLL_wait_for_multiple_objects( 0, NULL
, flags
, timeout
);
648 if (!timeout
) /* sleep forever */
650 for (;;) select( 0, NULL
, NULL
, NULL
, NULL
);
652 else if (!timeout
->QuadPart
)
660 NTDLL_get_server_timeout( &when
, timeout
);
664 gettimeofday( &tv
, 0 );
665 tv
.tv_sec
= when
.sec
- tv
.tv_sec
;
666 if ((tv
.tv_usec
= when
.usec
- tv
.tv_usec
) < 0)
668 tv
.tv_usec
+= 1000000;
671 if (tv
.tv_sec
< 0) tv
.tv_sec
= tv
.tv_usec
= 0;
672 if (select( 0, NULL
, NULL
, NULL
, &tv
) != -1) break;
675 return STATUS_SUCCESS
;