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>
44 #define NONAMELESSUNION
45 #define NONAMELESSSTRUCT
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
);
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;
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
;
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;
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
;
115 /******************************************************************************
116 * NtQuerySemaphore (NTDLL.@)
118 NTSTATUS WINAPI
NtQuerySemaphore(
119 HANDLE SemaphoreHandle
,
120 PVOID SemaphoreInformationClass
,
121 OUT PVOID SemaphoreInformation
,
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
)
136 SERVER_START_REQ( release_semaphore
)
138 req
->handle
= handle
;
140 if (!(ret
= wine_server_call( req
)))
142 if (previous
) *previous
= reply
->prev_count
;
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;
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
;
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;
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
;
205 /******************************************************************************
206 * NtSetEvent (NTDLL.@)
207 * ZwSetEvent (NTDLL.@)
209 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
213 /* FIXME: set NumberOfThreadsReleased */
215 SERVER_START_REQ( event_op
)
217 req
->handle
= handle
;
219 ret
= wine_server_call( req
);
225 /******************************************************************************
226 * NtResetEvent (NTDLL.@)
228 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
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
);
245 /******************************************************************************
246 * NtClearEvent (NTDLL.@)
249 * same as NtResetEvent ???
251 NTSTATUS WINAPI
NtClearEvent ( HANDLE handle
)
253 return NtResetEvent( handle
, NULL
);
256 /******************************************************************************
257 * NtPulseEvent (NTDLL.@)
262 NTSTATUS WINAPI
NtPulseEvent( HANDLE handle
, PULONG PulseCount
)
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
);
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
;
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;
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
;
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;
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
;
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
,
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 */
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
;
385 /* set error but can still succeed */
386 if (resume
&& status
== STATUS_SUCCESS
) return STATUS_TIMER_RESUME_IGNORED
;
390 /**************************************************************************
391 * NtCancelTimer [NTDLL.@]
392 * ZwCancelTimer [NTDLL.@]
394 NTSTATUS WINAPI
NtCancelTimer(IN HANDLE handle
, OUT BOOLEAN
* state
)
398 SERVER_START_REQ( cancel_timer
)
400 req
->handle
= handle
;
401 status
= wine_server_call( req
);
402 if (state
) *state
= reply
->signaled
;
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 /***********************************************************************
438 * Process a status event from the server.
440 static void WINAPI
check_async_list(async_private
*asp
, DWORD status
)
445 for( ovp
= NtCurrentTeb()->pending_list
; ovp
&& ovp
!= asp
; ovp
= ovp
->next
);
450 if( status
!= STATUS_ALERTED
)
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 /***********************************************************************
467 * Wait for a reply on the waiting pipe of the current thread.
469 static int wait_reply( void *cookie
)
472 struct wake_up_reply reply
;
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 */
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");
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 /***********************************************************************
506 * Call outstanding APCs.
508 static void call_apcs( BOOL alertable
)
512 void *arg1
, *arg2
, *arg3
;
517 SERVER_START_REQ( get_apc
)
519 req
->alertable
= alertable
;
520 if (!wine_server_call( req
)) type
= reply
->type
;
531 return; /* no more APCs */
536 proc( arg1
, arg2
, arg3
);
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
);
545 check_async_list( arg1
, (DWORD
) arg2
);
548 server_protocol_error( "get_apc_request: bad type %d\n", type
);
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
)
566 if (timeout
) flags
|= SELECT_TIMEOUT
;
569 SERVER_START_REQ( select
)
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
);
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;
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
);
636 NTDLL_get_server_timeout( &when
, timeout
);
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;
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
;