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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #ifdef HAVE_SYS_TIME_H
30 # include <sys/time.h>
35 #ifdef HAVE_SYS_POLL_H
36 # include <sys/poll.h>
50 #define NONAMELESSUNION
51 #define NONAMELESSSTRUCT
54 #define WIN32_NO_STATUS
57 #include "wine/server.h"
58 #include "wine/debug.h"
59 #include "ntdll_misc.h"
61 WINE_DEFAULT_DEBUG_CHANNEL(ntdll
);
63 /* creates a struct security_descriptor and contained information in one contiguous piece of memory */
64 NTSTATUS
NTDLL_create_struct_sd(PSECURITY_DESCRIPTOR nt_sd
, struct security_descriptor
**server_sd
,
65 data_size_t
*server_sd_len
)
70 BOOLEAN owner_present
, group_present
, dacl_present
, sacl_present
;
79 return STATUS_SUCCESS
;
82 len
= sizeof(struct security_descriptor
);
84 status
= RtlGetOwnerSecurityDescriptor(nt_sd
, &owner
, &owner_present
);
85 if (status
!= STATUS_SUCCESS
) return status
;
86 status
= RtlGetGroupSecurityDescriptor(nt_sd
, &group
, &group_present
);
87 if (status
!= STATUS_SUCCESS
) return status
;
88 status
= RtlGetSaclSecurityDescriptor(nt_sd
, &sacl_present
, &sacl
, &defaulted
);
89 if (status
!= STATUS_SUCCESS
) return status
;
90 status
= RtlGetDaclSecurityDescriptor(nt_sd
, &dacl_present
, &dacl
, &defaulted
);
91 if (status
!= STATUS_SUCCESS
) return status
;
94 len
+= RtlLengthSid(owner
);
96 len
+= RtlLengthSid(group
);
97 if (sacl_present
&& sacl
)
99 if (dacl_present
&& dacl
)
100 len
+= dacl
->AclSize
;
102 /* fix alignment for the Unicode name that follows the structure */
103 len
= (len
+ sizeof(WCHAR
) - 1) & ~(sizeof(WCHAR
) - 1);
104 *server_sd
= RtlAllocateHeap(GetProcessHeap(), 0, len
);
105 if (!*server_sd
) return STATUS_NO_MEMORY
;
107 (*server_sd
)->control
= ((SECURITY_DESCRIPTOR
*)nt_sd
)->Control
& ~SE_SELF_RELATIVE
;
108 (*server_sd
)->owner_len
= owner_present
? RtlLengthSid(owner
) : 0;
109 (*server_sd
)->group_len
= group_present
? RtlLengthSid(group
) : 0;
110 (*server_sd
)->sacl_len
= (sacl_present
&& sacl
) ? sacl
->AclSize
: 0;
111 (*server_sd
)->dacl_len
= (dacl_present
&& dacl
) ? dacl
->AclSize
: 0;
113 ptr
= (unsigned char *)(*server_sd
+ 1);
114 memcpy(ptr
, owner
, (*server_sd
)->owner_len
);
115 ptr
+= (*server_sd
)->owner_len
;
116 memcpy(ptr
, group
, (*server_sd
)->group_len
);
117 ptr
+= (*server_sd
)->group_len
;
118 memcpy(ptr
, sacl
, (*server_sd
)->sacl_len
);
119 ptr
+= (*server_sd
)->sacl_len
;
120 memcpy(ptr
, dacl
, (*server_sd
)->dacl_len
);
122 *server_sd_len
= len
;
124 return STATUS_SUCCESS
;
127 /* frees a struct security_descriptor allocated by NTDLL_create_struct_sd */
128 void NTDLL_free_struct_sd(struct security_descriptor
*server_sd
)
130 RtlFreeHeap(GetProcessHeap(), 0, server_sd
);
137 /******************************************************************************
138 * NtCreateSemaphore (NTDLL.@)
140 NTSTATUS WINAPI
NtCreateSemaphore( OUT PHANDLE SemaphoreHandle
,
141 IN ACCESS_MASK access
,
142 IN
const OBJECT_ATTRIBUTES
*attr OPTIONAL
,
143 IN LONG InitialCount
,
144 IN LONG MaximumCount
)
146 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
148 struct object_attributes objattr
;
149 struct security_descriptor
*sd
= NULL
;
151 if (MaximumCount
<= 0 || InitialCount
< 0 || InitialCount
> MaximumCount
)
152 return STATUS_INVALID_PARAMETER
;
153 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
155 objattr
.rootdir
= attr
? attr
->RootDirectory
: 0;
159 ret
= NTDLL_create_struct_sd( attr
->SecurityDescriptor
, &sd
, &objattr
.sd_len
);
160 if (ret
!= STATUS_SUCCESS
) return ret
;
163 SERVER_START_REQ( create_semaphore
)
165 req
->access
= access
;
166 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
167 req
->initial
= InitialCount
;
168 req
->max
= MaximumCount
;
169 wine_server_add_data( req
, &objattr
, sizeof(objattr
) );
170 if (objattr
.sd_len
) wine_server_add_data( req
, sd
, objattr
.sd_len
);
171 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
172 ret
= wine_server_call( req
);
173 *SemaphoreHandle
= reply
->handle
;
177 NTDLL_free_struct_sd( sd
);
182 /******************************************************************************
183 * NtOpenSemaphore (NTDLL.@)
185 NTSTATUS WINAPI
NtOpenSemaphore( OUT PHANDLE SemaphoreHandle
,
186 IN ACCESS_MASK access
,
187 IN
const OBJECT_ATTRIBUTES
*attr
)
189 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
192 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
194 SERVER_START_REQ( open_semaphore
)
196 req
->access
= access
;
197 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
198 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
199 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
200 ret
= wine_server_call( req
);
201 *SemaphoreHandle
= reply
->handle
;
207 /******************************************************************************
208 * NtQuerySemaphore (NTDLL.@)
210 NTSTATUS WINAPI
NtQuerySemaphore(
211 HANDLE SemaphoreHandle
,
212 SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass
,
213 PVOID SemaphoreInformation
,
217 FIXME("(%p,%d,%p,0x%08x,%p) stub!\n",
218 SemaphoreHandle
, SemaphoreInformationClass
, SemaphoreInformation
, Length
, ReturnLength
);
219 return STATUS_SUCCESS
;
222 /******************************************************************************
223 * NtReleaseSemaphore (NTDLL.@)
225 NTSTATUS WINAPI
NtReleaseSemaphore( HANDLE handle
, ULONG count
, PULONG previous
)
228 SERVER_START_REQ( release_semaphore
)
230 req
->handle
= handle
;
232 if (!(ret
= wine_server_call( req
)))
234 if (previous
) *previous
= reply
->prev_count
;
245 /**************************************************************************
246 * NtCreateEvent (NTDLL.@)
247 * ZwCreateEvent (NTDLL.@)
249 NTSTATUS WINAPI
NtCreateEvent(
250 OUT PHANDLE EventHandle
,
251 IN ACCESS_MASK DesiredAccess
,
252 IN
const OBJECT_ATTRIBUTES
*attr
,
253 IN BOOLEAN ManualReset
,
254 IN BOOLEAN InitialState
)
256 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
258 struct security_descriptor
*sd
= NULL
;
259 struct object_attributes objattr
;
261 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
263 objattr
.rootdir
= attr
? attr
->RootDirectory
: 0;
267 ret
= NTDLL_create_struct_sd( attr
->SecurityDescriptor
, &sd
, &objattr
.sd_len
);
268 if (ret
!= STATUS_SUCCESS
) return ret
;
271 SERVER_START_REQ( create_event
)
273 req
->access
= DesiredAccess
;
274 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
275 req
->manual_reset
= ManualReset
;
276 req
->initial_state
= InitialState
;
277 wine_server_add_data( req
, &objattr
, sizeof(objattr
) );
278 if (objattr
.sd_len
) wine_server_add_data( req
, sd
, objattr
.sd_len
);
279 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
280 ret
= wine_server_call( req
);
281 *EventHandle
= reply
->handle
;
285 NTDLL_free_struct_sd( sd
);
290 /******************************************************************************
291 * NtOpenEvent (NTDLL.@)
292 * ZwOpenEvent (NTDLL.@)
294 NTSTATUS WINAPI
NtOpenEvent(
295 OUT PHANDLE EventHandle
,
296 IN ACCESS_MASK DesiredAccess
,
297 IN
const OBJECT_ATTRIBUTES
*attr
)
299 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
302 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
304 SERVER_START_REQ( open_event
)
306 req
->access
= DesiredAccess
;
307 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
308 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
309 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
310 ret
= wine_server_call( req
);
311 *EventHandle
= reply
->handle
;
318 /******************************************************************************
319 * NtSetEvent (NTDLL.@)
320 * ZwSetEvent (NTDLL.@)
322 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
326 /* FIXME: set NumberOfThreadsReleased */
328 SERVER_START_REQ( event_op
)
330 req
->handle
= handle
;
332 ret
= wine_server_call( req
);
338 /******************************************************************************
339 * NtResetEvent (NTDLL.@)
341 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
345 /* resetting an event can't release any thread... */
346 if (NumberOfThreadsReleased
) *NumberOfThreadsReleased
= 0;
348 SERVER_START_REQ( event_op
)
350 req
->handle
= handle
;
351 req
->op
= RESET_EVENT
;
352 ret
= wine_server_call( req
);
358 /******************************************************************************
359 * NtClearEvent (NTDLL.@)
362 * same as NtResetEvent ???
364 NTSTATUS WINAPI
NtClearEvent ( HANDLE handle
)
366 return NtResetEvent( handle
, NULL
);
369 /******************************************************************************
370 * NtPulseEvent (NTDLL.@)
375 NTSTATUS WINAPI
NtPulseEvent( HANDLE handle
, PULONG PulseCount
)
380 FIXME("(%p,%d)\n", handle
, *PulseCount
);
382 SERVER_START_REQ( event_op
)
384 req
->handle
= handle
;
385 req
->op
= PULSE_EVENT
;
386 ret
= wine_server_call( req
);
392 /******************************************************************************
393 * NtQueryEvent (NTDLL.@)
395 NTSTATUS WINAPI
NtQueryEvent (
396 IN HANDLE EventHandle
,
397 IN EVENT_INFORMATION_CLASS EventInformationClass
,
398 OUT PVOID EventInformation
,
399 IN ULONG EventInformationLength
,
400 OUT PULONG ReturnLength
)
402 FIXME("(%p)\n", EventHandle
);
403 return STATUS_SUCCESS
;
407 * Mutants (known as Mutexes in Kernel32)
410 /******************************************************************************
411 * NtCreateMutant [NTDLL.@]
412 * ZwCreateMutant [NTDLL.@]
414 NTSTATUS WINAPI
NtCreateMutant(OUT HANDLE
* MutantHandle
,
415 IN ACCESS_MASK access
,
416 IN
const OBJECT_ATTRIBUTES
* attr OPTIONAL
,
417 IN BOOLEAN InitialOwner
)
420 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
421 struct security_descriptor
*sd
= NULL
;
422 struct object_attributes objattr
;
424 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
426 objattr
.rootdir
= attr
? attr
->RootDirectory
: 0;
430 status
= NTDLL_create_struct_sd( attr
->SecurityDescriptor
, &sd
, &objattr
.sd_len
);
431 if (status
!= STATUS_SUCCESS
) return status
;
434 SERVER_START_REQ( create_mutex
)
436 req
->access
= access
;
437 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
438 req
->owned
= InitialOwner
;
439 wine_server_add_data( req
, &objattr
, sizeof(objattr
) );
440 if (objattr
.sd_len
) wine_server_add_data( req
, sd
, objattr
.sd_len
);
441 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
442 status
= wine_server_call( req
);
443 *MutantHandle
= reply
->handle
;
447 NTDLL_free_struct_sd( sd
);
452 /**************************************************************************
453 * NtOpenMutant [NTDLL.@]
454 * ZwOpenMutant [NTDLL.@]
456 NTSTATUS WINAPI
NtOpenMutant(OUT HANDLE
* MutantHandle
,
457 IN ACCESS_MASK access
,
458 IN
const OBJECT_ATTRIBUTES
* attr
)
461 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
463 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
465 SERVER_START_REQ( open_mutex
)
467 req
->access
= access
;
468 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
469 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
470 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
471 status
= wine_server_call( req
);
472 *MutantHandle
= reply
->handle
;
478 /**************************************************************************
479 * NtReleaseMutant [NTDLL.@]
480 * ZwReleaseMutant [NTDLL.@]
482 NTSTATUS WINAPI
NtReleaseMutant( IN HANDLE handle
, OUT PLONG prev_count OPTIONAL
)
486 SERVER_START_REQ( release_mutex
)
488 req
->handle
= handle
;
489 status
= wine_server_call( req
);
490 if (prev_count
) *prev_count
= reply
->prev_count
;
496 /******************************************************************
497 * NtQueryMutant [NTDLL.@]
498 * ZwQueryMutant [NTDLL.@]
500 NTSTATUS WINAPI
NtQueryMutant(IN HANDLE handle
,
501 IN MUTANT_INFORMATION_CLASS MutantInformationClass
,
502 OUT PVOID MutantInformation
,
503 IN ULONG MutantInformationLength
,
504 OUT PULONG ResultLength OPTIONAL
)
506 FIXME("(%p %u %p %u %p): stub!\n",
507 handle
, MutantInformationClass
, MutantInformation
, MutantInformationLength
, ResultLength
);
508 return STATUS_NOT_IMPLEMENTED
;
515 /**************************************************************************
516 * NtCreateTimer [NTDLL.@]
517 * ZwCreateTimer [NTDLL.@]
519 NTSTATUS WINAPI
NtCreateTimer(OUT HANDLE
*handle
,
520 IN ACCESS_MASK access
,
521 IN
const OBJECT_ATTRIBUTES
*attr OPTIONAL
,
522 IN TIMER_TYPE timer_type
)
524 DWORD len
= (attr
&& attr
->ObjectName
) ? attr
->ObjectName
->Length
: 0;
527 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
529 if (timer_type
!= NotificationTimer
&& timer_type
!= SynchronizationTimer
)
530 return STATUS_INVALID_PARAMETER
;
532 SERVER_START_REQ( create_timer
)
534 req
->access
= access
;
535 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
536 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
537 req
->manual
= (timer_type
== NotificationTimer
) ? TRUE
: FALSE
;
538 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
539 status
= wine_server_call( req
);
540 *handle
= reply
->handle
;
547 /**************************************************************************
548 * NtOpenTimer [NTDLL.@]
549 * ZwOpenTimer [NTDLL.@]
551 NTSTATUS WINAPI
NtOpenTimer(OUT PHANDLE handle
,
552 IN ACCESS_MASK access
,
553 IN
const OBJECT_ATTRIBUTES
* attr
)
555 DWORD len
= (attr
&& attr
->ObjectName
) ? attr
->ObjectName
->Length
: 0;
558 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
560 SERVER_START_REQ( open_timer
)
562 req
->access
= access
;
563 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
564 req
->rootdir
= attr
? attr
->RootDirectory
: 0;
565 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
566 status
= wine_server_call( req
);
567 *handle
= reply
->handle
;
573 /**************************************************************************
574 * NtSetTimer [NTDLL.@]
575 * ZwSetTimer [NTDLL.@]
577 NTSTATUS WINAPI
NtSetTimer(IN HANDLE handle
,
578 IN
const LARGE_INTEGER
* when
,
579 IN PTIMER_APC_ROUTINE callback
,
580 IN PVOID callback_arg
,
582 IN ULONG period OPTIONAL
,
583 OUT PBOOLEAN state OPTIONAL
)
585 NTSTATUS status
= STATUS_SUCCESS
;
587 TRACE("(%p,%p,%p,%p,%08x,0x%08x,%p) stub\n",
588 handle
, when
, callback
, callback_arg
, resume
, period
, state
);
590 SERVER_START_REQ( set_timer
)
592 req
->handle
= handle
;
593 req
->period
= period
;
594 req
->expire
= when
->QuadPart
;
595 req
->callback
= callback
;
596 req
->arg
= callback_arg
;
597 status
= wine_server_call( req
);
598 if (state
) *state
= reply
->signaled
;
602 /* set error but can still succeed */
603 if (resume
&& status
== STATUS_SUCCESS
) return STATUS_TIMER_RESUME_IGNORED
;
607 /**************************************************************************
608 * NtCancelTimer [NTDLL.@]
609 * ZwCancelTimer [NTDLL.@]
611 NTSTATUS WINAPI
NtCancelTimer(IN HANDLE handle
, OUT BOOLEAN
* state
)
615 SERVER_START_REQ( cancel_timer
)
617 req
->handle
= handle
;
618 status
= wine_server_call( req
);
619 if (state
) *state
= reply
->signaled
;
625 /******************************************************************************
626 * NtQueryTimer (NTDLL.@)
628 * Retrieves information about a timer.
631 * TimerHandle [I] The timer to retrieve information about.
632 * TimerInformationClass [I] The type of information to retrieve.
633 * TimerInformation [O] Pointer to buffer to store information in.
634 * Length [I] The length of the buffer pointed to by TimerInformation.
635 * ReturnLength [O] Optional. The size of buffer actually used.
638 * Success: STATUS_SUCCESS
639 * Failure: STATUS_INFO_LENGTH_MISMATCH, if Length doesn't match the required data
640 * size for the class specified.
641 * STATUS_INVALID_INFO_CLASS, if an invalid TimerInformationClass was specified.
642 * STATUS_ACCESS_DENIED, if TimerHandle does not have TIMER_QUERY_STATE access
645 NTSTATUS WINAPI
NtQueryTimer(
647 TIMER_INFORMATION_CLASS TimerInformationClass
,
648 PVOID TimerInformation
,
652 TIMER_BASIC_INFORMATION
* basic_info
= (TIMER_BASIC_INFORMATION
*)TimerInformation
;
656 TRACE("(%p,%d,%p,0x%08x,%p)\n", TimerHandle
, TimerInformationClass
,
657 TimerInformation
, Length
, ReturnLength
);
659 switch (TimerInformationClass
)
661 case TimerBasicInformation
:
662 if (Length
< sizeof(TIMER_BASIC_INFORMATION
))
663 return STATUS_INFO_LENGTH_MISMATCH
;
665 SERVER_START_REQ(get_timer_info
)
667 req
->handle
= TimerHandle
;
668 status
= wine_server_call(req
);
670 /* convert server time to absolute NTDLL time */
671 basic_info
->RemainingTime
.QuadPart
= reply
->when
;
672 basic_info
->TimerState
= reply
->signaled
;
676 /* convert from absolute into relative time */
677 NtQuerySystemTime(&now
);
678 if (now
.QuadPart
> basic_info
->RemainingTime
.QuadPart
)
679 basic_info
->RemainingTime
.QuadPart
= 0;
681 basic_info
->RemainingTime
.QuadPart
-= now
.QuadPart
;
683 if (ReturnLength
) *ReturnLength
= sizeof(TIMER_BASIC_INFORMATION
);
688 FIXME("Unhandled class %d\n", TimerInformationClass
);
689 return STATUS_INVALID_INFO_CLASS
;
693 /******************************************************************************
694 * NtQueryTimerResolution [NTDLL.@]
696 NTSTATUS WINAPI
NtQueryTimerResolution(OUT ULONG
* min_resolution
,
697 OUT ULONG
* max_resolution
,
698 OUT ULONG
* current_resolution
)
700 FIXME("(%p,%p,%p), stub!\n",
701 min_resolution
, max_resolution
, current_resolution
);
703 return STATUS_NOT_IMPLEMENTED
;
706 /******************************************************************************
707 * NtSetTimerResolution [NTDLL.@]
709 NTSTATUS WINAPI
NtSetTimerResolution(IN ULONG resolution
,
710 IN BOOLEAN set_resolution
,
711 OUT ULONG
* current_resolution
)
713 FIXME("(%u,%u,%p), stub!\n",
714 resolution
, set_resolution
, current_resolution
);
716 return STATUS_NOT_IMPLEMENTED
;
720 /***********************************************************************
723 * Wait for a reply on the waiting pipe of the current thread.
725 static int wait_reply( void *cookie
)
728 struct wake_up_reply reply
;
732 ret
= read( ntdll_get_thread_data()->wait_fd
[0], &reply
, sizeof(reply
) );
733 if (ret
== sizeof(reply
))
735 if (!reply
.cookie
) break; /* thread got killed */
736 if (reply
.cookie
== cookie
) return reply
.signaled
;
737 /* we stole another reply, wait for the real one */
738 signaled
= wait_reply( cookie
);
739 /* and now put the wrong one back in the pipe */
742 ret
= write( ntdll_get_thread_data()->wait_fd
[1], &reply
, sizeof(reply
) );
743 if (ret
== sizeof(reply
)) break;
744 if (ret
>= 0) server_protocol_error( "partial wakeup write %d\n", ret
);
745 if (errno
== EINTR
) continue;
746 server_protocol_perror("wakeup write");
750 if (ret
>= 0) server_protocol_error( "partial wakeup read %d\n", ret
);
751 if (errno
== EINTR
) continue;
752 server_protocol_perror("wakeup read");
754 /* the server closed the connection; time to die... */
755 server_abort_thread(0);
759 /***********************************************************************
762 * Invoke a single APC. Return TRUE if a user APC has been run.
764 static BOOL
invoke_apc( const apc_call_t
*call
, apc_result_t
*result
)
766 BOOL user_apc
= FALSE
;
768 memset( result
, 0, sizeof(*result
) );
775 call
->user
.func( call
->user
.args
[0], call
->user
.args
[1], call
->user
.args
[2] );
779 call
->timer
.func( call
->timer
.arg
, (DWORD
)call
->timer
.time
, (DWORD
)(call
->timer
.time
>> 32) );
783 result
->type
= call
->type
;
784 result
->async_io
.status
= call
->async_io
.func( call
->async_io
.user
,
786 call
->async_io
.status
);
788 case APC_VIRTUAL_ALLOC
:
789 result
->type
= call
->type
;
790 result
->virtual_alloc
.addr
= call
->virtual_alloc
.addr
;
791 result
->virtual_alloc
.size
= call
->virtual_alloc
.size
;
792 result
->virtual_alloc
.status
= NtAllocateVirtualMemory( NtCurrentProcess(),
793 &result
->virtual_alloc
.addr
,
794 call
->virtual_alloc
.zero_bits
,
795 &result
->virtual_alloc
.size
,
796 call
->virtual_alloc
.op_type
,
797 call
->virtual_alloc
.prot
);
799 case APC_VIRTUAL_FREE
:
800 result
->type
= call
->type
;
801 result
->virtual_free
.addr
= call
->virtual_free
.addr
;
802 result
->virtual_free
.size
= call
->virtual_free
.size
;
803 result
->virtual_free
.status
= NtFreeVirtualMemory( NtCurrentProcess(),
804 &result
->virtual_free
.addr
,
805 &result
->virtual_free
.size
,
806 call
->virtual_free
.op_type
);
808 case APC_VIRTUAL_QUERY
:
810 MEMORY_BASIC_INFORMATION info
;
811 result
->type
= call
->type
;
812 result
->virtual_query
.status
= NtQueryVirtualMemory( NtCurrentProcess(),
813 call
->virtual_query
.addr
,
814 MemoryBasicInformation
, &info
,
815 sizeof(info
), NULL
);
816 if (result
->virtual_query
.status
== STATUS_SUCCESS
)
818 result
->virtual_query
.base
= info
.BaseAddress
;
819 result
->virtual_query
.alloc_base
= info
.AllocationBase
;
820 result
->virtual_query
.size
= info
.RegionSize
;
821 result
->virtual_query
.state
= info
.State
;
822 result
->virtual_query
.prot
= info
.Protect
;
823 result
->virtual_query
.alloc_prot
= info
.AllocationProtect
;
824 result
->virtual_query
.alloc_type
= info
.Type
;
828 case APC_VIRTUAL_PROTECT
:
829 result
->type
= call
->type
;
830 result
->virtual_protect
.addr
= call
->virtual_protect
.addr
;
831 result
->virtual_protect
.size
= call
->virtual_protect
.size
;
832 result
->virtual_protect
.status
= NtProtectVirtualMemory( NtCurrentProcess(),
833 &result
->virtual_protect
.addr
,
834 &result
->virtual_protect
.size
,
835 call
->virtual_protect
.prot
,
836 &result
->virtual_protect
.prot
);
838 case APC_VIRTUAL_FLUSH
:
839 result
->type
= call
->type
;
840 result
->virtual_flush
.addr
= call
->virtual_flush
.addr
;
841 result
->virtual_flush
.size
= call
->virtual_flush
.size
;
842 result
->virtual_flush
.status
= NtFlushVirtualMemory( NtCurrentProcess(),
843 &result
->virtual_flush
.addr
,
844 &result
->virtual_flush
.size
, 0 );
846 case APC_VIRTUAL_LOCK
:
847 result
->type
= call
->type
;
848 result
->virtual_lock
.addr
= call
->virtual_lock
.addr
;
849 result
->virtual_lock
.size
= call
->virtual_lock
.size
;
850 result
->virtual_lock
.status
= NtLockVirtualMemory( NtCurrentProcess(),
851 &result
->virtual_lock
.addr
,
852 &result
->virtual_lock
.size
, 0 );
854 case APC_VIRTUAL_UNLOCK
:
855 result
->type
= call
->type
;
856 result
->virtual_unlock
.addr
= call
->virtual_unlock
.addr
;
857 result
->virtual_unlock
.size
= call
->virtual_unlock
.size
;
858 result
->virtual_unlock
.status
= NtUnlockVirtualMemory( NtCurrentProcess(),
859 &result
->virtual_unlock
.addr
,
860 &result
->virtual_unlock
.size
, 0 );
864 LARGE_INTEGER offset
;
865 result
->type
= call
->type
;
866 result
->map_view
.addr
= call
->map_view
.addr
;
867 result
->map_view
.size
= call
->map_view
.size
;
868 offset
.QuadPart
= call
->map_view
.offset
;
869 result
->map_view
.status
= NtMapViewOfSection( call
->map_view
.handle
, NtCurrentProcess(),
870 &result
->map_view
.addr
, call
->map_view
.zero_bits
,
871 0, &offset
, &result
->map_view
.size
, ViewShare
,
872 call
->map_view
.alloc_type
, call
->map_view
.prot
);
873 NtClose( call
->map_view
.handle
);
877 result
->type
= call
->type
;
878 result
->unmap_view
.status
= NtUnmapViewOfSection( NtCurrentProcess(), call
->unmap_view
.addr
);
880 case APC_CREATE_THREAD
:
883 result
->type
= call
->type
;
884 result
->create_thread
.status
= RtlCreateUserThread( NtCurrentProcess(), NULL
,
885 call
->create_thread
.suspend
, NULL
,
886 call
->create_thread
.reserve
,
887 call
->create_thread
.commit
,
888 call
->create_thread
.func
,
889 call
->create_thread
.arg
,
890 &result
->create_thread
.handle
, &id
);
891 result
->create_thread
.tid
= HandleToULong(id
.UniqueThread
);
895 server_protocol_error( "get_apc_request: bad type %d\n", call
->type
);
901 /***********************************************************************
902 * NTDLL_queue_process_apc
904 NTSTATUS
NTDLL_queue_process_apc( HANDLE process
, const apc_call_t
*call
, apc_result_t
*result
)
912 SERVER_START_REQ( queue_apc
)
914 req
->process
= process
;
916 if (!(ret
= wine_server_call( req
)))
918 handle
= reply
->handle
;
923 if (ret
!= STATUS_SUCCESS
) return ret
;
927 invoke_apc( call
, result
);
931 NtWaitForSingleObject( handle
, FALSE
, NULL
);
933 SERVER_START_REQ( get_apc_result
)
935 req
->handle
= handle
;
936 if (!(ret
= wine_server_call( req
))) *result
= reply
->result
;
940 if (!ret
&& result
->type
== APC_NONE
) continue; /* APC didn't run, try again */
941 if (ret
) NtClose( handle
);
948 /***********************************************************************
949 * NTDLL_wait_for_multiple_objects
951 * Implementation of NtWaitForMultipleObjects
953 NTSTATUS
NTDLL_wait_for_multiple_objects( UINT count
, const HANDLE
*handles
, UINT flags
,
954 const LARGE_INTEGER
*timeout
, HANDLE signal_object
)
958 BOOL user_apc
= FALSE
;
959 obj_handle_t apc_handle
= 0;
962 timeout_t abs_timeout
= timeout
? timeout
->QuadPart
: TIMEOUT_INFINITE
;
964 memset( &result
, 0, sizeof(result
) );
968 SERVER_START_REQ( select
)
971 req
->cookie
= &cookie
;
972 req
->signal
= signal_object
;
973 req
->prev_apc
= apc_handle
;
974 req
->timeout
= abs_timeout
;
975 wine_server_add_data( req
, &result
, sizeof(result
) );
976 wine_server_add_data( req
, handles
, count
* sizeof(HANDLE
) );
977 ret
= wine_server_call( req
);
978 abs_timeout
= reply
->timeout
;
979 apc_handle
= reply
->apc_handle
;
983 if (ret
== STATUS_PENDING
) ret
= wait_reply( &cookie
);
984 if (ret
!= STATUS_USER_APC
) break;
985 if (invoke_apc( &call
, &result
))
987 /* if we ran a user apc we have to check once more if an object got signaled,
988 * but we don't want to wait */
992 signal_object
= 0; /* don't signal it multiple times */
995 if (ret
== STATUS_TIMEOUT
&& user_apc
) ret
= STATUS_USER_APC
;
997 /* A test on Windows 2000 shows that Windows always yields during
998 a wait, but a wait that is hit by an event gets a priority
999 boost as well. This seems to model that behavior the closest. */
1000 if (ret
== STATUS_TIMEOUT
) NtYieldExecution();
1006 /* wait operations */
1008 /******************************************************************
1009 * NtWaitForMultipleObjects (NTDLL.@)
1011 NTSTATUS WINAPI
NtWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
,
1012 BOOLEAN wait_all
, BOOLEAN alertable
,
1013 const LARGE_INTEGER
*timeout
)
1015 UINT flags
= SELECT_INTERRUPTIBLE
;
1017 if (!count
|| count
> MAXIMUM_WAIT_OBJECTS
) return STATUS_INVALID_PARAMETER_1
;
1019 if (wait_all
) flags
|= SELECT_ALL
;
1020 if (alertable
) flags
|= SELECT_ALERTABLE
;
1021 return NTDLL_wait_for_multiple_objects( count
, handles
, flags
, timeout
, 0 );
1025 /******************************************************************
1026 * NtWaitForSingleObject (NTDLL.@)
1028 NTSTATUS WINAPI
NtWaitForSingleObject(HANDLE handle
, BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1030 return NtWaitForMultipleObjects( 1, &handle
, FALSE
, alertable
, timeout
);
1034 /******************************************************************
1035 * NtSignalAndWaitForSingleObject (NTDLL.@)
1037 NTSTATUS WINAPI
NtSignalAndWaitForSingleObject( HANDLE hSignalObject
, HANDLE hWaitObject
,
1038 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1040 UINT flags
= SELECT_INTERRUPTIBLE
;
1042 if (!hSignalObject
) return STATUS_INVALID_HANDLE
;
1043 if (alertable
) flags
|= SELECT_ALERTABLE
;
1044 return NTDLL_wait_for_multiple_objects( 1, &hWaitObject
, flags
, timeout
, hSignalObject
);
1048 /******************************************************************
1049 * NtYieldExecution (NTDLL.@)
1051 NTSTATUS WINAPI
NtYieldExecution(void)
1053 #ifdef HAVE_SCHED_YIELD
1055 return STATUS_SUCCESS
;
1057 return STATUS_NO_YIELD_PERFORMED
;
1062 /******************************************************************
1063 * NtDelayExecution (NTDLL.@)
1065 NTSTATUS WINAPI
NtDelayExecution( BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1067 /* if alertable, we need to query the server */
1069 return NTDLL_wait_for_multiple_objects( 0, NULL
, SELECT_INTERRUPTIBLE
| SELECT_ALERTABLE
,
1072 if (!timeout
|| timeout
->QuadPart
== TIMEOUT_INFINITE
) /* sleep forever */
1074 for (;;) select( 0, NULL
, NULL
, NULL
, NULL
);
1079 timeout_t when
, diff
;
1081 if ((when
= timeout
->QuadPart
) < 0)
1083 NtQuerySystemTime( &now
);
1084 when
= now
.QuadPart
- when
;
1087 /* Note that we yield after establishing the desired timeout */
1089 if (!when
) return STATUS_SUCCESS
;
1094 NtQuerySystemTime( &now
);
1095 diff
= (when
- now
.QuadPart
+ 9) / 10;
1096 if (diff
<= 0) break;
1097 tv
.tv_sec
= diff
/ 1000000;
1098 tv
.tv_usec
= diff
% 1000000;
1099 if (select( 0, NULL
, NULL
, NULL
, &tv
) != -1) break;
1102 return STATUS_SUCCESS
;
1105 /******************************************************************
1106 * NtCreateIoCompletion (NTDLL.@)
1107 * ZwCreateIoCompletion (NTDLL.@)
1109 * Creates I/O completion object.
1112 * CompletionPort [O] created completion object handle will be placed there
1113 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1114 * ObjectAttributes [I] completion object attributes
1115 * NumberOfConcurrentThreads [I] desired number of concurrent active worker threads
1118 NTSTATUS WINAPI
NtCreateIoCompletion( PHANDLE CompletionPort
, ACCESS_MASK DesiredAccess
,
1119 POBJECT_ATTRIBUTES ObjectAttributes
, ULONG NumberOfConcurrentThreads
)
1123 TRACE("(%p, %x, %p, %d)\n", CompletionPort
, DesiredAccess
,
1124 ObjectAttributes
, NumberOfConcurrentThreads
);
1126 if (!CompletionPort
)
1127 return STATUS_INVALID_PARAMETER
;
1129 SERVER_START_REQ( create_completion
)
1131 req
->access
= DesiredAccess
;
1132 req
->attributes
= ObjectAttributes
? ObjectAttributes
->Attributes
: 0;
1133 req
->rootdir
= ObjectAttributes
? ObjectAttributes
->RootDirectory
: NULL
;
1134 req
->concurrent
= NumberOfConcurrentThreads
;
1135 if (ObjectAttributes
&& ObjectAttributes
->ObjectName
)
1136 wine_server_add_data( req
, ObjectAttributes
->ObjectName
->Buffer
,
1137 ObjectAttributes
->ObjectName
->Length
);
1138 if (!(status
= wine_server_call( req
)))
1139 *CompletionPort
= reply
->handle
;
1145 /******************************************************************
1146 * NtSetIoCompletion (NTDLL.@)
1147 * ZwSetIoCompletion (NTDLL.@)
1149 * Inserts completion message into queue
1152 * CompletionPort [I] HANDLE to completion object
1153 * CompletionKey [I] completion key
1154 * CompletionValue [I] completion value (usually pointer to OVERLAPPED)
1155 * Status [I] operation status
1156 * NumberOfBytesTransferred [I] number of bytes transferred
1158 NTSTATUS WINAPI
NtSetIoCompletion( HANDLE CompletionPort
, ULONG_PTR CompletionKey
,
1159 ULONG_PTR CompletionValue
, NTSTATUS Status
,
1160 ULONG NumberOfBytesTransferred
)
1164 TRACE("(%p, %lx, %lx, %x, %d)\n", CompletionPort
, CompletionKey
,
1165 CompletionValue
, Status
, NumberOfBytesTransferred
);
1167 SERVER_START_REQ( add_completion
)
1169 req
->handle
= CompletionPort
;
1170 req
->ckey
= CompletionKey
;
1171 req
->cvalue
= CompletionValue
;
1172 req
->status
= Status
;
1173 req
->information
= NumberOfBytesTransferred
;
1174 status
= wine_server_call( req
);
1180 /******************************************************************
1181 * NtRemoveIoCompletion (NTDLL.@)
1182 * ZwRemoveIoCompletion (NTDLL.@)
1184 * (Wait for and) retrieve first completion message from completion object's queue
1187 * CompletionPort [I] HANDLE to I/O completion object
1188 * CompletionKey [O] completion key
1189 * CompletionValue [O] Completion value given in NtSetIoCompletion or in async operation
1190 * iosb [O] IO_STATUS_BLOCK of completed asynchronous operation
1191 * WaitTime [I] optional wait time in NTDLL format
1194 NTSTATUS WINAPI
NtRemoveIoCompletion( HANDLE CompletionPort
, PULONG_PTR CompletionKey
,
1195 PULONG_PTR CompletionValue
, PIO_STATUS_BLOCK iosb
,
1196 PLARGE_INTEGER WaitTime
)
1200 TRACE("(%p, %p, %p, %p, %p)\n", CompletionPort
, CompletionKey
,
1201 CompletionValue
, iosb
, WaitTime
);
1205 SERVER_START_REQ( remove_completion
)
1207 req
->handle
= CompletionPort
;
1208 if (!(status
= wine_server_call( req
)))
1210 *CompletionKey
= reply
->ckey
;
1211 *CompletionValue
= reply
->cvalue
;
1212 iosb
->Information
= reply
->information
;
1213 iosb
->u
.Status
= reply
->status
;
1217 if (status
!= STATUS_PENDING
) break;
1219 status
= NtWaitForSingleObject( CompletionPort
, FALSE
, WaitTime
);
1220 if (status
!= WAIT_OBJECT_0
) break;
1225 /******************************************************************
1226 * NtOpenIoCompletion (NTDLL.@)
1227 * ZwOpenIoCompletion (NTDLL.@)
1229 * Opens I/O completion object
1232 * CompletionPort [O] completion object handle will be placed there
1233 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1234 * ObjectAttributes [I] completion object name
1237 NTSTATUS WINAPI
NtOpenIoCompletion( PHANDLE CompletionPort
, ACCESS_MASK DesiredAccess
,
1238 POBJECT_ATTRIBUTES ObjectAttributes
)
1242 TRACE("(%p, 0x%x, %p)\n", CompletionPort
, DesiredAccess
, ObjectAttributes
);
1244 if (!CompletionPort
|| !ObjectAttributes
|| !ObjectAttributes
->ObjectName
)
1245 return STATUS_INVALID_PARAMETER
;
1247 SERVER_START_REQ( open_completion
)
1249 req
->access
= DesiredAccess
;
1250 req
->rootdir
= ObjectAttributes
->RootDirectory
;
1251 wine_server_add_data( req
, ObjectAttributes
->ObjectName
->Buffer
,
1252 ObjectAttributes
->ObjectName
->Length
);
1253 if (!(status
= wine_server_call( req
)))
1254 *CompletionPort
= reply
->handle
;
1260 /******************************************************************
1261 * NtQueryIoCompletion (NTDLL.@)
1262 * ZwQueryIoCompletion (NTDLL.@)
1264 * Requests information about given I/O completion object
1267 * CompletionPort [I] HANDLE to completion port to request
1268 * InformationClass [I] information class
1269 * CompletionInformation [O] user-provided buffer for data
1270 * BufferLength [I] buffer length
1271 * RequiredLength [O] required buffer length
1274 NTSTATUS WINAPI
NtQueryIoCompletion( HANDLE CompletionPort
, IO_COMPLETION_INFORMATION_CLASS InformationClass
,
1275 PVOID CompletionInformation
, ULONG BufferLength
, PULONG RequiredLength
)
1279 TRACE("(%p, %d, %p, 0x%x, %p)\n", CompletionPort
, InformationClass
, CompletionInformation
,
1280 BufferLength
, RequiredLength
);
1282 if (!CompletionInformation
) return STATUS_INVALID_PARAMETER
;
1283 switch( InformationClass
)
1285 case IoCompletionBasicInformation
:
1287 ULONG
*info
= (ULONG
*)CompletionInformation
;
1289 if (RequiredLength
) *RequiredLength
= sizeof(*info
);
1290 if (BufferLength
!= sizeof(*info
))
1291 status
= STATUS_INFO_LENGTH_MISMATCH
;
1294 SERVER_START_REQ( query_completion
)
1296 req
->handle
= CompletionPort
;
1297 if (!(status
= wine_server_call( req
)))
1298 *info
= reply
->depth
;
1305 status
= STATUS_INVALID_PARAMETER
;