2 * Process synchronisation
4 * Copyright 1997 Alexandre Julliard
5 * Copyright 1999, 2000 Juergen Schmied
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #ifdef HAVE_SYS_TIME_H
28 # include <sys/time.h>
30 #ifdef HAVE_SYS_POLL_H
31 # include <sys/poll.h>
41 #define NONAMELESSUNION
42 #define NONAMELESSSTRUCT
47 #include "wine/server.h"
48 #include "wine/unicode.h"
49 #include "wine/debug.h"
50 #include "ntdll_misc.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(ntdll
);
59 /******************************************************************************
60 * NtCreateSemaphore (NTDLL.@)
62 NTSTATUS WINAPI
NtCreateSemaphore( OUT PHANDLE SemaphoreHandle
,
63 IN ACCESS_MASK access
,
64 IN
const OBJECT_ATTRIBUTES
*attr OPTIONAL
,
65 IN ULONG InitialCount
,
66 IN ULONG MaximumCount
)
68 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
71 if ((MaximumCount
<= 0) || (InitialCount
> MaximumCount
))
72 return STATUS_INVALID_PARAMETER
;
74 SERVER_START_REQ( create_semaphore
)
76 req
->initial
= InitialCount
;
77 req
->max
= MaximumCount
;
78 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
79 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
80 ret
= wine_server_call( req
);
81 *SemaphoreHandle
= reply
->handle
;
87 /******************************************************************************
88 * NtOpenSemaphore (NTDLL.@)
90 NTSTATUS WINAPI
NtOpenSemaphore( OUT PHANDLE SemaphoreHandle
,
91 IN ACCESS_MASK access
,
92 IN
const OBJECT_ATTRIBUTES
*attr
)
94 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
97 SERVER_START_REQ( open_semaphore
)
100 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
101 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
102 ret
= wine_server_call( req
);
103 *SemaphoreHandle
= reply
->handle
;
109 /******************************************************************************
110 * NtQuerySemaphore (NTDLL.@)
112 NTSTATUS WINAPI
NtQuerySemaphore(
113 HANDLE SemaphoreHandle
,
114 PVOID SemaphoreInformationClass
,
115 OUT PVOID SemaphoreInformation
,
119 FIXME("(%p,%p,%p,0x%08lx,%p) stub!\n",
120 SemaphoreHandle
, SemaphoreInformationClass
, SemaphoreInformation
, Length
, ReturnLength
);
121 return STATUS_SUCCESS
;
124 /******************************************************************************
125 * NtReleaseSemaphore (NTDLL.@)
127 NTSTATUS WINAPI
NtReleaseSemaphore( HANDLE handle
, ULONG count
, PULONG previous
)
130 SERVER_START_REQ( release_semaphore
)
132 req
->handle
= handle
;
134 if (!(ret
= wine_server_call( req
)))
136 if (previous
) *previous
= reply
->prev_count
;
147 /**************************************************************************
148 * NtCreateEvent (NTDLL.@)
149 * ZwCreateEvent (NTDLL.@)
151 NTSTATUS WINAPI
NtCreateEvent(
152 OUT PHANDLE EventHandle
,
153 IN ACCESS_MASK DesiredAccess
,
154 IN
const OBJECT_ATTRIBUTES
*attr
,
155 IN BOOLEAN ManualReset
,
156 IN BOOLEAN InitialState
)
158 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
161 SERVER_START_REQ( create_event
)
163 req
->manual_reset
= ManualReset
;
164 req
->initial_state
= InitialState
;
165 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
166 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
167 ret
= wine_server_call( req
);
168 *EventHandle
= reply
->handle
;
174 /******************************************************************************
175 * NtOpenEvent (NTDLL.@)
176 * ZwOpenEvent (NTDLL.@)
178 NTSTATUS WINAPI
NtOpenEvent(
179 OUT PHANDLE EventHandle
,
180 IN ACCESS_MASK DesiredAccess
,
181 IN
const OBJECT_ATTRIBUTES
*attr
)
183 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
186 SERVER_START_REQ( open_event
)
188 req
->access
= DesiredAccess
;
189 req
->inherit
= attr
&& (attr
->Attributes
& OBJ_INHERIT
);
190 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
191 ret
= wine_server_call( req
);
192 *EventHandle
= reply
->handle
;
199 /******************************************************************************
200 * NtSetEvent (NTDLL.@)
201 * ZwSetEvent (NTDLL.@)
203 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
207 /* FIXME: set NumberOfThreadsReleased */
209 SERVER_START_REQ( event_op
)
211 req
->handle
= handle
;
213 ret
= wine_server_call( req
);
219 /******************************************************************************
220 * NtResetEvent (NTDLL.@)
222 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
226 /* resetting an event can't release any thread... */
227 if (NumberOfThreadsReleased
) *NumberOfThreadsReleased
= 0;
229 SERVER_START_REQ( event_op
)
231 req
->handle
= handle
;
232 req
->op
= RESET_EVENT
;
233 ret
= wine_server_call( req
);
239 /******************************************************************************
240 * NtClearEvent (NTDLL.@)
243 * same as NtResetEvent ???
245 NTSTATUS WINAPI
NtClearEvent ( HANDLE handle
)
247 return NtResetEvent( handle
, NULL
);
250 /******************************************************************************
251 * NtPulseEvent (NTDLL.@)
256 NTSTATUS WINAPI
NtPulseEvent( HANDLE handle
, PULONG PulseCount
)
259 FIXME("(%p,%p)\n", handle
, PulseCount
);
260 SERVER_START_REQ( event_op
)
262 req
->handle
= handle
;
263 req
->op
= PULSE_EVENT
;
264 ret
= wine_server_call( req
);
270 /******************************************************************************
271 * NtQueryEvent (NTDLL.@)
273 NTSTATUS WINAPI
NtQueryEvent (
274 IN HANDLE EventHandle
,
275 IN UINT EventInformationClass
,
276 OUT PVOID EventInformation
,
277 IN ULONG EventInformationLength
,
278 OUT PULONG ReturnLength
)
280 FIXME("(%p)\n", EventHandle
);
281 return STATUS_SUCCESS
;
285 /***********************************************************************
288 * Process a status event from the server.
290 static void WINAPI
check_async_list(async_private
*asp
, DWORD status
)
295 for( ovp
= NtCurrentTeb()->pending_list
; ovp
&& ovp
!= asp
; ovp
= ovp
->next
);
300 if( status
!= STATUS_ALERTED
)
303 ovp
->ops
->set_status (ovp
, status
);
305 else ovp_status
= ovp
->ops
->get_status (ovp
);
307 if( ovp_status
== STATUS_PENDING
) ovp
->func( ovp
);
309 /* This will destroy all but PENDING requests */
310 register_old_async( ovp
);
314 /***********************************************************************
317 * Wait for a reply on the waiting pipe of the current thread.
319 static int wait_reply( void *cookie
)
322 struct wake_up_reply reply
;
326 ret
= read( NtCurrentTeb()->wait_fd
[0], &reply
, sizeof(reply
) );
327 if (ret
== sizeof(reply
))
329 if (!reply
.cookie
) break; /* thread got killed */
330 if (reply
.cookie
== cookie
) return reply
.signaled
;
331 /* we stole another reply, wait for the real one */
332 signaled
= wait_reply( cookie
);
333 /* and now put the wrong one back in the pipe */
336 ret
= write( NtCurrentTeb()->wait_fd
[1], &reply
, sizeof(reply
) );
337 if (ret
== sizeof(reply
)) break;
338 if (ret
>= 0) server_protocol_error( "partial wakeup write %d\n", ret
);
339 if (errno
== EINTR
) continue;
340 server_protocol_perror("wakeup write");
344 if (ret
>= 0) server_protocol_error( "partial wakeup read %d\n", ret
);
345 if (errno
== EINTR
) continue;
346 server_protocol_perror("wakeup read");
348 /* the server closed the connection; time to die... */
349 SYSDEPS_AbortThread(0);
353 /***********************************************************************
356 * Call outstanding APCs.
358 static void call_apcs( BOOL alertable
)
362 void *arg1
, *arg2
, *arg3
;
367 SERVER_START_REQ( get_apc
)
369 req
->alertable
= alertable
;
370 if (!wine_server_call( req
)) type
= reply
->type
;
381 return; /* no more APCs */
386 proc( arg1
, arg2
, arg3
);
389 /* convert sec/usec to NT time */
390 RtlSecondsSince1970ToTime( (time_t)arg1
, &time
);
391 time
.QuadPart
+= (DWORD
)arg2
* 10;
392 proc( arg3
, time
.s
.LowPart
, time
.s
.HighPart
);
395 check_async_list( arg1
, (DWORD
) arg2
);
398 server_protocol_error( "get_apc_request: bad type %d\n", type
);
404 /* wait operations */
406 /******************************************************************
407 * NtWaitForMultipleObjects (NTDLL.@)
409 NTSTATUS WINAPI
NtWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
,
410 BOOLEAN wait_all
, BOOLEAN alertable
,
411 PLARGE_INTEGER timeout
)
415 if (count
> MAXIMUM_WAIT_OBJECTS
) return STATUS_INVALID_PARAMETER_1
;
419 SERVER_START_REQ( select
)
421 req
->flags
= SELECT_INTERRUPTIBLE
;
422 req
->cookie
= &cookie
;
423 NTDLL_get_server_timeout( &req
->timeout
, timeout
);
424 wine_server_add_data( req
, handles
, count
* sizeof(HANDLE
) );
426 if (wait_all
) req
->flags
|= SELECT_ALL
;
427 if (alertable
) req
->flags
|= SELECT_ALERTABLE
;
428 if (timeout
) req
->flags
|= SELECT_TIMEOUT
;
430 ret
= wine_server_call( req
);
433 if (ret
== STATUS_PENDING
) ret
= wait_reply( &cookie
);
434 if (ret
!= STATUS_USER_APC
) break;
435 call_apcs( alertable
);
436 if (alertable
) break;
442 /******************************************************************
443 * NtWaitForSingleObject (NTDLL.@)
445 NTSTATUS WINAPI
NtWaitForSingleObject(HANDLE handle
, BOOLEAN alertable
, PLARGE_INTEGER timeout
)
447 return NtWaitForMultipleObjects( 1, &handle
, FALSE
, alertable
, timeout
);