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>
43 #define NONAMELESSUNION
44 #define NONAMELESSSTRUCT
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
);
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;
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
;
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;
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
;
111 /******************************************************************************
112 * NtQuerySemaphore (NTDLL.@)
114 NTSTATUS WINAPI
NtQuerySemaphore(
115 HANDLE SemaphoreHandle
,
116 PVOID SemaphoreInformationClass
,
117 OUT PVOID SemaphoreInformation
,
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
)
132 SERVER_START_REQ( release_semaphore
)
134 req
->handle
= handle
;
136 if (!(ret
= wine_server_call( req
)))
138 if (previous
) *previous
= reply
->prev_count
;
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;
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
;
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;
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
;
201 /******************************************************************************
202 * NtSetEvent (NTDLL.@)
203 * ZwSetEvent (NTDLL.@)
205 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
209 /* FIXME: set NumberOfThreadsReleased */
211 SERVER_START_REQ( event_op
)
213 req
->handle
= handle
;
215 ret
= wine_server_call( req
);
221 /******************************************************************************
222 * NtResetEvent (NTDLL.@)
224 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
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
);
241 /******************************************************************************
242 * NtClearEvent (NTDLL.@)
245 * same as NtResetEvent ???
247 NTSTATUS WINAPI
NtClearEvent ( HANDLE handle
)
249 return NtResetEvent( handle
, NULL
);
252 /******************************************************************************
253 * NtPulseEvent (NTDLL.@)
258 NTSTATUS WINAPI
NtPulseEvent( HANDLE handle
, PULONG PulseCount
)
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
);
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
;
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;
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
;
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;
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
;
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
,
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 */
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
;
381 /* set error but can still succeed */
382 if (resume
&& status
== STATUS_SUCCESS
) return STATUS_TIMER_RESUME_IGNORED
;
386 /**************************************************************************
387 * NtCancelTimer [NTDLL.@]
388 * ZwCancelTimer [NTDLL.@]
390 NTSTATUS WINAPI
NtCancelTimer(IN HANDLE handle
, OUT BOOLEAN
* state
)
394 SERVER_START_REQ( cancel_timer
)
396 req
->handle
= handle
;
397 status
= wine_server_call( req
);
398 if (state
) *state
= reply
->signaled
;
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 /***********************************************************************
434 * Process a status event from the server.
436 static void WINAPI
check_async_list(async_private
*asp
, DWORD status
)
441 for( ovp
= NtCurrentTeb()->pending_list
; ovp
&& ovp
!= asp
; ovp
= ovp
->next
);
446 if( status
!= STATUS_ALERTED
)
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 /***********************************************************************
463 * Wait for a reply on the waiting pipe of the current thread.
465 static int wait_reply( void *cookie
)
468 struct wake_up_reply reply
;
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 */
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");
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 /***********************************************************************
502 * Call outstanding APCs.
504 static void call_apcs( BOOL alertable
)
508 void *arg1
, *arg2
, *arg3
;
513 SERVER_START_REQ( get_apc
)
515 req
->alertable
= alertable
;
516 if (!wine_server_call( req
)) type
= reply
->type
;
527 return; /* no more APCs */
532 proc( arg1
, arg2
, arg3
);
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
);
541 check_async_list( arg1
, (DWORD
) arg2
);
544 server_protocol_error( "get_apc_request: bad type %d\n", type
);
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
)
562 if (timeout
) flags
|= SELECT_TIMEOUT
;
565 SERVER_START_REQ( select
)
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
);
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;
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
);
632 NTDLL_get_server_timeout( &when
, timeout
);
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;
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
;