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
= wine_server_obj_handle( attr
? attr
->RootDirectory
: 0 );
157 objattr
.name_len
= len
;
160 ret
= NTDLL_create_struct_sd( attr
->SecurityDescriptor
, &sd
, &objattr
.sd_len
);
161 if (ret
!= STATUS_SUCCESS
) return ret
;
164 SERVER_START_REQ( create_semaphore
)
166 req
->access
= access
;
167 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
168 req
->initial
= InitialCount
;
169 req
->max
= MaximumCount
;
170 wine_server_add_data( req
, &objattr
, sizeof(objattr
) );
171 if (objattr
.sd_len
) wine_server_add_data( req
, sd
, objattr
.sd_len
);
172 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
173 ret
= wine_server_call( req
);
174 *SemaphoreHandle
= wine_server_ptr_handle( reply
->handle
);
178 NTDLL_free_struct_sd( sd
);
183 /******************************************************************************
184 * NtOpenSemaphore (NTDLL.@)
186 NTSTATUS WINAPI
NtOpenSemaphore( OUT PHANDLE SemaphoreHandle
,
187 IN ACCESS_MASK access
,
188 IN
const OBJECT_ATTRIBUTES
*attr
)
190 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
193 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
195 SERVER_START_REQ( open_semaphore
)
197 req
->access
= access
;
198 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
199 req
->rootdir
= wine_server_obj_handle( attr
? attr
->RootDirectory
: 0 );
200 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
201 ret
= wine_server_call( req
);
202 *SemaphoreHandle
= wine_server_ptr_handle( reply
->handle
);
208 /******************************************************************************
209 * NtQuerySemaphore (NTDLL.@)
211 NTSTATUS WINAPI
NtQuerySemaphore(
212 HANDLE SemaphoreHandle
,
213 SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass
,
214 PVOID SemaphoreInformation
,
218 FIXME("(%p,%d,%p,0x%08x,%p) stub!\n",
219 SemaphoreHandle
, SemaphoreInformationClass
, SemaphoreInformation
, Length
, ReturnLength
);
220 return STATUS_SUCCESS
;
223 /******************************************************************************
224 * NtReleaseSemaphore (NTDLL.@)
226 NTSTATUS WINAPI
NtReleaseSemaphore( HANDLE handle
, ULONG count
, PULONG previous
)
229 SERVER_START_REQ( release_semaphore
)
231 req
->handle
= wine_server_obj_handle( handle
);
233 if (!(ret
= wine_server_call( req
)))
235 if (previous
) *previous
= reply
->prev_count
;
246 /**************************************************************************
247 * NtCreateEvent (NTDLL.@)
248 * ZwCreateEvent (NTDLL.@)
250 NTSTATUS WINAPI
NtCreateEvent( PHANDLE EventHandle
, ACCESS_MASK DesiredAccess
,
251 const OBJECT_ATTRIBUTES
*attr
, EVENT_TYPE type
, BOOLEAN InitialState
)
253 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
255 struct security_descriptor
*sd
= NULL
;
256 struct object_attributes objattr
;
258 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
260 objattr
.rootdir
= wine_server_obj_handle( attr
? attr
->RootDirectory
: 0 );
262 objattr
.name_len
= len
;
265 ret
= NTDLL_create_struct_sd( attr
->SecurityDescriptor
, &sd
, &objattr
.sd_len
);
266 if (ret
!= STATUS_SUCCESS
) return ret
;
269 SERVER_START_REQ( create_event
)
271 req
->access
= DesiredAccess
;
272 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
273 req
->manual_reset
= (type
== NotificationEvent
);
274 req
->initial_state
= InitialState
;
275 wine_server_add_data( req
, &objattr
, sizeof(objattr
) );
276 if (objattr
.sd_len
) wine_server_add_data( req
, sd
, objattr
.sd_len
);
277 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
278 ret
= wine_server_call( req
);
279 *EventHandle
= wine_server_ptr_handle( reply
->handle
);
283 NTDLL_free_struct_sd( sd
);
288 /******************************************************************************
289 * NtOpenEvent (NTDLL.@)
290 * ZwOpenEvent (NTDLL.@)
292 NTSTATUS WINAPI
NtOpenEvent(
293 OUT PHANDLE EventHandle
,
294 IN ACCESS_MASK DesiredAccess
,
295 IN
const OBJECT_ATTRIBUTES
*attr
)
297 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
300 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
302 SERVER_START_REQ( open_event
)
304 req
->access
= DesiredAccess
;
305 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
306 req
->rootdir
= wine_server_obj_handle( attr
? attr
->RootDirectory
: 0 );
307 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
308 ret
= wine_server_call( req
);
309 *EventHandle
= wine_server_ptr_handle( reply
->handle
);
316 /******************************************************************************
317 * NtSetEvent (NTDLL.@)
318 * ZwSetEvent (NTDLL.@)
320 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
324 /* FIXME: set NumberOfThreadsReleased */
326 SERVER_START_REQ( event_op
)
328 req
->handle
= wine_server_obj_handle( handle
);
330 ret
= wine_server_call( req
);
336 /******************************************************************************
337 * NtResetEvent (NTDLL.@)
339 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, PULONG NumberOfThreadsReleased
)
343 /* resetting an event can't release any thread... */
344 if (NumberOfThreadsReleased
) *NumberOfThreadsReleased
= 0;
346 SERVER_START_REQ( event_op
)
348 req
->handle
= wine_server_obj_handle( handle
);
349 req
->op
= RESET_EVENT
;
350 ret
= wine_server_call( req
);
356 /******************************************************************************
357 * NtClearEvent (NTDLL.@)
360 * same as NtResetEvent ???
362 NTSTATUS WINAPI
NtClearEvent ( HANDLE handle
)
364 return NtResetEvent( handle
, NULL
);
367 /******************************************************************************
368 * NtPulseEvent (NTDLL.@)
373 NTSTATUS WINAPI
NtPulseEvent( HANDLE handle
, PULONG PulseCount
)
378 FIXME("(%p,%d)\n", handle
, *PulseCount
);
380 SERVER_START_REQ( event_op
)
382 req
->handle
= wine_server_obj_handle( handle
);
383 req
->op
= PULSE_EVENT
;
384 ret
= wine_server_call( req
);
390 /******************************************************************************
391 * NtQueryEvent (NTDLL.@)
393 NTSTATUS WINAPI
NtQueryEvent( HANDLE handle
, EVENT_INFORMATION_CLASS
class,
394 void *info
, ULONG len
, ULONG
*ret_len
)
397 EVENT_BASIC_INFORMATION
*out
= info
;
399 if (class != EventBasicInformation
)
401 FIXME("(%p, %d, %d) Unknown class\n",
403 return STATUS_INVALID_INFO_CLASS
;
406 if (len
!= sizeof(EVENT_BASIC_INFORMATION
)) return STATUS_INFO_LENGTH_MISMATCH
;
408 SERVER_START_REQ( query_event
)
410 req
->handle
= wine_server_obj_handle( handle
);
411 if (!(ret
= wine_server_call( req
)))
413 out
->EventType
= reply
->manual_reset
? NotificationEvent
: SynchronizationEvent
;
414 out
->EventState
= reply
->state
;
415 if (ret_len
) *ret_len
= sizeof(EVENT_BASIC_INFORMATION
);
424 * Mutants (known as Mutexes in Kernel32)
427 /******************************************************************************
428 * NtCreateMutant [NTDLL.@]
429 * ZwCreateMutant [NTDLL.@]
431 NTSTATUS WINAPI
NtCreateMutant(OUT HANDLE
* MutantHandle
,
432 IN ACCESS_MASK access
,
433 IN
const OBJECT_ATTRIBUTES
* attr OPTIONAL
,
434 IN BOOLEAN InitialOwner
)
437 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
438 struct security_descriptor
*sd
= NULL
;
439 struct object_attributes objattr
;
441 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
443 objattr
.rootdir
= wine_server_obj_handle( attr
? attr
->RootDirectory
: 0 );
445 objattr
.name_len
= len
;
448 status
= NTDLL_create_struct_sd( attr
->SecurityDescriptor
, &sd
, &objattr
.sd_len
);
449 if (status
!= STATUS_SUCCESS
) return status
;
452 SERVER_START_REQ( create_mutex
)
454 req
->access
= access
;
455 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
456 req
->owned
= InitialOwner
;
457 wine_server_add_data( req
, &objattr
, sizeof(objattr
) );
458 if (objattr
.sd_len
) wine_server_add_data( req
, sd
, objattr
.sd_len
);
459 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
460 status
= wine_server_call( req
);
461 *MutantHandle
= wine_server_ptr_handle( reply
->handle
);
465 NTDLL_free_struct_sd( sd
);
470 /**************************************************************************
471 * NtOpenMutant [NTDLL.@]
472 * ZwOpenMutant [NTDLL.@]
474 NTSTATUS WINAPI
NtOpenMutant(OUT HANDLE
* MutantHandle
,
475 IN ACCESS_MASK access
,
476 IN
const OBJECT_ATTRIBUTES
* attr
)
479 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
481 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
483 SERVER_START_REQ( open_mutex
)
485 req
->access
= access
;
486 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
487 req
->rootdir
= wine_server_obj_handle( attr
? attr
->RootDirectory
: 0 );
488 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
489 status
= wine_server_call( req
);
490 *MutantHandle
= wine_server_ptr_handle( reply
->handle
);
496 /**************************************************************************
497 * NtReleaseMutant [NTDLL.@]
498 * ZwReleaseMutant [NTDLL.@]
500 NTSTATUS WINAPI
NtReleaseMutant( IN HANDLE handle
, OUT PLONG prev_count OPTIONAL
)
504 SERVER_START_REQ( release_mutex
)
506 req
->handle
= wine_server_obj_handle( handle
);
507 status
= wine_server_call( req
);
508 if (prev_count
) *prev_count
= reply
->prev_count
;
514 /******************************************************************
515 * NtQueryMutant [NTDLL.@]
516 * ZwQueryMutant [NTDLL.@]
518 NTSTATUS WINAPI
NtQueryMutant(IN HANDLE handle
,
519 IN MUTANT_INFORMATION_CLASS MutantInformationClass
,
520 OUT PVOID MutantInformation
,
521 IN ULONG MutantInformationLength
,
522 OUT PULONG ResultLength OPTIONAL
)
524 FIXME("(%p %u %p %u %p): stub!\n",
525 handle
, MutantInformationClass
, MutantInformation
, MutantInformationLength
, ResultLength
);
526 return STATUS_NOT_IMPLEMENTED
;
533 /******************************************************************************
534 * NtCreateJobObject [NTDLL.@]
535 * ZwCreateJobObject [NTDLL.@]
537 NTSTATUS WINAPI
NtCreateJobObject( PHANDLE handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
539 FIXME( "stub: %p %x %s\n", handle
, access
, attr
? debugstr_us(attr
->ObjectName
) : "" );
540 *handle
= (HANDLE
)0xdead;
541 return STATUS_SUCCESS
;
544 /******************************************************************************
545 * NtOpenJobObject [NTDLL.@]
546 * ZwOpenJobObject [NTDLL.@]
548 NTSTATUS WINAPI
NtOpenJobObject( PHANDLE handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
550 FIXME( "stub: %p %x %s\n", handle
, access
, attr
? debugstr_us(attr
->ObjectName
) : "" );
551 return STATUS_NOT_IMPLEMENTED
;
554 /******************************************************************************
555 * NtTerminateJobObject [NTDLL.@]
556 * ZwTerminateJobObject [NTDLL.@]
558 NTSTATUS WINAPI
NtTerminateJobObject( HANDLE handle
, NTSTATUS status
)
560 FIXME( "stub: %p %x\n", handle
, status
);
561 return STATUS_SUCCESS
;
564 /******************************************************************************
565 * NtQueryInformationJobObject [NTDLL.@]
566 * ZwQueryInformationJobObject [NTDLL.@]
568 NTSTATUS WINAPI
NtQueryInformationJobObject( HANDLE handle
, JOBOBJECTINFOCLASS
class, PVOID info
,
569 ULONG len
, PULONG ret_len
)
571 FIXME( "stub: %p %u %p %u %p\n", handle
, class, info
, len
, ret_len
);
572 return STATUS_NOT_IMPLEMENTED
;
575 /******************************************************************************
576 * NtSetInformationJobObject [NTDLL.@]
577 * ZwSetInformationJobObject [NTDLL.@]
579 NTSTATUS WINAPI
NtSetInformationJobObject( HANDLE handle
, JOBOBJECTINFOCLASS
class, PVOID info
, ULONG len
)
581 FIXME( "stub: %p %u %p %u\n", handle
, class, info
, len
);
582 return STATUS_SUCCESS
;
585 /******************************************************************************
586 * NtIsProcessInJob [NTDLL.@]
587 * ZwIsProcessInJob [NTDLL.@]
589 NTSTATUS WINAPI
NtIsProcessInJob( HANDLE process
, HANDLE job
)
591 FIXME( "stub: %p %p\n", process
, job
);
592 return STATUS_PROCESS_NOT_IN_JOB
;
595 /******************************************************************************
596 * NtAssignProcessToJobObject [NTDLL.@]
597 * ZwAssignProcessToJobObject [NTDLL.@]
599 NTSTATUS WINAPI
NtAssignProcessToJobObject( HANDLE job
, HANDLE process
)
601 FIXME( "stub: %p %p\n", job
, process
);
602 return STATUS_SUCCESS
;
609 /**************************************************************************
610 * NtCreateTimer [NTDLL.@]
611 * ZwCreateTimer [NTDLL.@]
613 NTSTATUS WINAPI
NtCreateTimer(OUT HANDLE
*handle
,
614 IN ACCESS_MASK access
,
615 IN
const OBJECT_ATTRIBUTES
*attr OPTIONAL
,
616 IN TIMER_TYPE timer_type
)
618 DWORD len
= (attr
&& attr
->ObjectName
) ? attr
->ObjectName
->Length
: 0;
621 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
623 if (timer_type
!= NotificationTimer
&& timer_type
!= SynchronizationTimer
)
624 return STATUS_INVALID_PARAMETER
;
626 SERVER_START_REQ( create_timer
)
628 req
->access
= access
;
629 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
630 req
->rootdir
= wine_server_obj_handle( attr
? attr
->RootDirectory
: 0 );
631 req
->manual
= (timer_type
== NotificationTimer
) ? TRUE
: FALSE
;
632 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
633 status
= wine_server_call( req
);
634 *handle
= wine_server_ptr_handle( reply
->handle
);
641 /**************************************************************************
642 * NtOpenTimer [NTDLL.@]
643 * ZwOpenTimer [NTDLL.@]
645 NTSTATUS WINAPI
NtOpenTimer(OUT PHANDLE handle
,
646 IN ACCESS_MASK access
,
647 IN
const OBJECT_ATTRIBUTES
* attr
)
649 DWORD len
= (attr
&& attr
->ObjectName
) ? attr
->ObjectName
->Length
: 0;
652 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
654 SERVER_START_REQ( open_timer
)
656 req
->access
= access
;
657 req
->attributes
= (attr
) ? attr
->Attributes
: 0;
658 req
->rootdir
= wine_server_obj_handle( attr
? attr
->RootDirectory
: 0 );
659 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
660 status
= wine_server_call( req
);
661 *handle
= wine_server_ptr_handle( reply
->handle
);
667 /**************************************************************************
668 * NtSetTimer [NTDLL.@]
669 * ZwSetTimer [NTDLL.@]
671 NTSTATUS WINAPI
NtSetTimer(IN HANDLE handle
,
672 IN
const LARGE_INTEGER
* when
,
673 IN PTIMER_APC_ROUTINE callback
,
674 IN PVOID callback_arg
,
676 IN ULONG period OPTIONAL
,
677 OUT PBOOLEAN state OPTIONAL
)
679 NTSTATUS status
= STATUS_SUCCESS
;
681 TRACE("(%p,%p,%p,%p,%08x,0x%08x,%p) stub\n",
682 handle
, when
, callback
, callback_arg
, resume
, period
, state
);
684 SERVER_START_REQ( set_timer
)
686 req
->handle
= wine_server_obj_handle( handle
);
687 req
->period
= period
;
688 req
->expire
= when
->QuadPart
;
689 req
->callback
= wine_server_client_ptr( callback
);
690 req
->arg
= wine_server_client_ptr( callback_arg
);
691 status
= wine_server_call( req
);
692 if (state
) *state
= reply
->signaled
;
696 /* set error but can still succeed */
697 if (resume
&& status
== STATUS_SUCCESS
) return STATUS_TIMER_RESUME_IGNORED
;
701 /**************************************************************************
702 * NtCancelTimer [NTDLL.@]
703 * ZwCancelTimer [NTDLL.@]
705 NTSTATUS WINAPI
NtCancelTimer(IN HANDLE handle
, OUT BOOLEAN
* state
)
709 SERVER_START_REQ( cancel_timer
)
711 req
->handle
= wine_server_obj_handle( handle
);
712 status
= wine_server_call( req
);
713 if (state
) *state
= reply
->signaled
;
719 /******************************************************************************
720 * NtQueryTimer (NTDLL.@)
722 * Retrieves information about a timer.
725 * TimerHandle [I] The timer to retrieve information about.
726 * TimerInformationClass [I] The type of information to retrieve.
727 * TimerInformation [O] Pointer to buffer to store information in.
728 * Length [I] The length of the buffer pointed to by TimerInformation.
729 * ReturnLength [O] Optional. The size of buffer actually used.
732 * Success: STATUS_SUCCESS
733 * Failure: STATUS_INFO_LENGTH_MISMATCH, if Length doesn't match the required data
734 * size for the class specified.
735 * STATUS_INVALID_INFO_CLASS, if an invalid TimerInformationClass was specified.
736 * STATUS_ACCESS_DENIED, if TimerHandle does not have TIMER_QUERY_STATE access
739 NTSTATUS WINAPI
NtQueryTimer(
741 TIMER_INFORMATION_CLASS TimerInformationClass
,
742 PVOID TimerInformation
,
746 TIMER_BASIC_INFORMATION
* basic_info
= TimerInformation
;
750 TRACE("(%p,%d,%p,0x%08x,%p)\n", TimerHandle
, TimerInformationClass
,
751 TimerInformation
, Length
, ReturnLength
);
753 switch (TimerInformationClass
)
755 case TimerBasicInformation
:
756 if (Length
< sizeof(TIMER_BASIC_INFORMATION
))
757 return STATUS_INFO_LENGTH_MISMATCH
;
759 SERVER_START_REQ(get_timer_info
)
761 req
->handle
= wine_server_obj_handle( TimerHandle
);
762 status
= wine_server_call(req
);
764 /* convert server time to absolute NTDLL time */
765 basic_info
->RemainingTime
.QuadPart
= reply
->when
;
766 basic_info
->TimerState
= reply
->signaled
;
770 /* convert from absolute into relative time */
771 NtQuerySystemTime(&now
);
772 if (now
.QuadPart
> basic_info
->RemainingTime
.QuadPart
)
773 basic_info
->RemainingTime
.QuadPart
= 0;
775 basic_info
->RemainingTime
.QuadPart
-= now
.QuadPart
;
777 if (ReturnLength
) *ReturnLength
= sizeof(TIMER_BASIC_INFORMATION
);
782 FIXME("Unhandled class %d\n", TimerInformationClass
);
783 return STATUS_INVALID_INFO_CLASS
;
787 /******************************************************************************
788 * NtQueryTimerResolution [NTDLL.@]
790 NTSTATUS WINAPI
NtQueryTimerResolution(OUT ULONG
* min_resolution
,
791 OUT ULONG
* max_resolution
,
792 OUT ULONG
* current_resolution
)
794 FIXME("(%p,%p,%p), stub!\n",
795 min_resolution
, max_resolution
, current_resolution
);
797 return STATUS_NOT_IMPLEMENTED
;
800 /******************************************************************************
801 * NtSetTimerResolution [NTDLL.@]
803 NTSTATUS WINAPI
NtSetTimerResolution(IN ULONG resolution
,
804 IN BOOLEAN set_resolution
,
805 OUT ULONG
* current_resolution
)
807 FIXME("(%u,%u,%p), stub!\n",
808 resolution
, set_resolution
, current_resolution
);
810 return STATUS_NOT_IMPLEMENTED
;
814 /***********************************************************************
817 * Wait for a reply on the waiting pipe of the current thread.
819 static int wait_reply( void *cookie
)
822 struct wake_up_reply reply
;
826 ret
= read( ntdll_get_thread_data()->wait_fd
[0], &reply
, sizeof(reply
) );
827 if (ret
== sizeof(reply
))
829 if (!reply
.cookie
) abort_thread( reply
.signaled
); /* thread got killed */
830 if (wine_server_get_ptr(reply
.cookie
) == cookie
) return reply
.signaled
;
831 /* we stole another reply, wait for the real one */
832 signaled
= wait_reply( cookie
);
833 /* and now put the wrong one back in the pipe */
836 ret
= write( ntdll_get_thread_data()->wait_fd
[1], &reply
, sizeof(reply
) );
837 if (ret
== sizeof(reply
)) break;
838 if (ret
>= 0) server_protocol_error( "partial wakeup write %d\n", ret
);
839 if (errno
== EINTR
) continue;
840 server_protocol_perror("wakeup write");
844 if (ret
>= 0) server_protocol_error( "partial wakeup read %d\n", ret
);
845 if (errno
== EINTR
) continue;
846 server_protocol_perror("wakeup read");
851 /***********************************************************************
854 * Invoke a single APC. Return TRUE if a user APC has been run.
856 static BOOL
invoke_apc( const apc_call_t
*call
, apc_result_t
*result
)
858 BOOL user_apc
= FALSE
;
862 memset( result
, 0, sizeof(*result
) );
870 void (WINAPI
*func
)(ULONG_PTR
,ULONG_PTR
,ULONG_PTR
) = wine_server_get_ptr( call
->user
.func
);
871 func( call
->user
.args
[0], call
->user
.args
[1], call
->user
.args
[2] );
877 void (WINAPI
*func
)(void*, unsigned int, unsigned int) = wine_server_get_ptr( call
->timer
.func
);
878 func( wine_server_get_ptr( call
->timer
.arg
),
879 (DWORD
)call
->timer
.time
, (DWORD
)(call
->timer
.time
>> 32) );
886 IO_STATUS_BLOCK
*iosb
= wine_server_get_ptr( call
->async_io
.sb
);
887 NTSTATUS (*func
)(void *, IO_STATUS_BLOCK
*, NTSTATUS
, void **) = wine_server_get_ptr( call
->async_io
.func
);
888 result
->type
= call
->type
;
889 result
->async_io
.status
= func( wine_server_get_ptr( call
->async_io
.user
),
890 iosb
, call
->async_io
.status
, &apc
);
891 if (result
->async_io
.status
!= STATUS_PENDING
)
893 result
->async_io
.total
= iosb
->Information
;
894 result
->async_io
.apc
= wine_server_client_ptr( apc
);
898 case APC_VIRTUAL_ALLOC
:
899 result
->type
= call
->type
;
900 addr
= wine_server_get_ptr( call
->virtual_alloc
.addr
);
901 size
= call
->virtual_alloc
.size
;
902 if ((ULONG_PTR
)addr
== call
->virtual_alloc
.addr
&& size
== call
->virtual_alloc
.size
)
904 result
->virtual_alloc
.status
= NtAllocateVirtualMemory( NtCurrentProcess(), &addr
,
905 call
->virtual_alloc
.zero_bits
, &size
,
906 call
->virtual_alloc
.op_type
,
907 call
->virtual_alloc
.prot
);
908 result
->virtual_alloc
.addr
= wine_server_client_ptr( addr
);
909 result
->virtual_alloc
.size
= size
;
911 else result
->virtual_alloc
.status
= STATUS_WORKING_SET_LIMIT_RANGE
;
913 case APC_VIRTUAL_FREE
:
914 result
->type
= call
->type
;
915 addr
= wine_server_get_ptr( call
->virtual_free
.addr
);
916 size
= call
->virtual_free
.size
;
917 if ((ULONG_PTR
)addr
== call
->virtual_free
.addr
&& size
== call
->virtual_free
.size
)
919 result
->virtual_free
.status
= NtFreeVirtualMemory( NtCurrentProcess(), &addr
, &size
,
920 call
->virtual_free
.op_type
);
921 result
->virtual_free
.addr
= wine_server_client_ptr( addr
);
922 result
->virtual_free
.size
= size
;
924 else result
->virtual_free
.status
= STATUS_INVALID_PARAMETER
;
926 case APC_VIRTUAL_QUERY
:
928 MEMORY_BASIC_INFORMATION info
;
929 result
->type
= call
->type
;
930 addr
= wine_server_get_ptr( call
->virtual_query
.addr
);
931 if ((ULONG_PTR
)addr
== call
->virtual_query
.addr
)
932 result
->virtual_query
.status
= NtQueryVirtualMemory( NtCurrentProcess(),
933 addr
, MemoryBasicInformation
, &info
,
934 sizeof(info
), NULL
);
936 result
->virtual_query
.status
= STATUS_WORKING_SET_LIMIT_RANGE
;
938 if (result
->virtual_query
.status
== STATUS_SUCCESS
)
940 result
->virtual_query
.base
= wine_server_client_ptr( info
.BaseAddress
);
941 result
->virtual_query
.alloc_base
= wine_server_client_ptr( info
.AllocationBase
);
942 result
->virtual_query
.size
= info
.RegionSize
;
943 result
->virtual_query
.prot
= info
.Protect
;
944 result
->virtual_query
.alloc_prot
= info
.AllocationProtect
;
945 result
->virtual_query
.state
= info
.State
>> 12;
946 result
->virtual_query
.alloc_type
= info
.Type
>> 16;
950 case APC_VIRTUAL_PROTECT
:
951 result
->type
= call
->type
;
952 addr
= wine_server_get_ptr( call
->virtual_protect
.addr
);
953 size
= call
->virtual_protect
.size
;
954 if ((ULONG_PTR
)addr
== call
->virtual_protect
.addr
&& size
== call
->virtual_protect
.size
)
956 result
->virtual_protect
.status
= NtProtectVirtualMemory( NtCurrentProcess(), &addr
, &size
,
957 call
->virtual_protect
.prot
,
958 &result
->virtual_protect
.prot
);
959 result
->virtual_protect
.addr
= wine_server_client_ptr( addr
);
960 result
->virtual_protect
.size
= size
;
962 else result
->virtual_protect
.status
= STATUS_INVALID_PARAMETER
;
964 case APC_VIRTUAL_FLUSH
:
965 result
->type
= call
->type
;
966 addr
= wine_server_get_ptr( call
->virtual_flush
.addr
);
967 size
= call
->virtual_flush
.size
;
968 if ((ULONG_PTR
)addr
== call
->virtual_flush
.addr
&& size
== call
->virtual_flush
.size
)
970 result
->virtual_flush
.status
= NtFlushVirtualMemory( NtCurrentProcess(),
971 (const void **)&addr
, &size
, 0 );
972 result
->virtual_flush
.addr
= wine_server_client_ptr( addr
);
973 result
->virtual_flush
.size
= size
;
975 else result
->virtual_flush
.status
= STATUS_INVALID_PARAMETER
;
977 case APC_VIRTUAL_LOCK
:
978 result
->type
= call
->type
;
979 addr
= wine_server_get_ptr( call
->virtual_lock
.addr
);
980 size
= call
->virtual_lock
.size
;
981 if ((ULONG_PTR
)addr
== call
->virtual_lock
.addr
&& size
== call
->virtual_lock
.size
)
983 result
->virtual_lock
.status
= NtLockVirtualMemory( NtCurrentProcess(), &addr
, &size
, 0 );
984 result
->virtual_lock
.addr
= wine_server_client_ptr( addr
);
985 result
->virtual_lock
.size
= size
;
987 else result
->virtual_lock
.status
= STATUS_INVALID_PARAMETER
;
989 case APC_VIRTUAL_UNLOCK
:
990 result
->type
= call
->type
;
991 addr
= wine_server_get_ptr( call
->virtual_unlock
.addr
);
992 size
= call
->virtual_unlock
.size
;
993 if ((ULONG_PTR
)addr
== call
->virtual_unlock
.addr
&& size
== call
->virtual_unlock
.size
)
995 result
->virtual_unlock
.status
= NtUnlockVirtualMemory( NtCurrentProcess(), &addr
, &size
, 0 );
996 result
->virtual_unlock
.addr
= wine_server_client_ptr( addr
);
997 result
->virtual_unlock
.size
= size
;
999 else result
->virtual_unlock
.status
= STATUS_INVALID_PARAMETER
;
1002 result
->type
= call
->type
;
1003 addr
= wine_server_get_ptr( call
->map_view
.addr
);
1004 size
= call
->map_view
.size
;
1005 if ((ULONG_PTR
)addr
== call
->map_view
.addr
&& size
== call
->map_view
.size
)
1007 LARGE_INTEGER offset
;
1008 offset
.QuadPart
= call
->map_view
.offset
;
1009 result
->map_view
.status
= NtMapViewOfSection( wine_server_ptr_handle(call
->map_view
.handle
),
1010 NtCurrentProcess(), &addr
,
1011 call
->map_view
.zero_bits
, 0,
1012 &offset
, &size
, ViewShare
,
1013 call
->map_view
.alloc_type
, call
->map_view
.prot
);
1014 result
->map_view
.addr
= wine_server_client_ptr( addr
);
1015 result
->map_view
.size
= size
;
1017 else result
->map_view
.status
= STATUS_INVALID_PARAMETER
;
1018 NtClose( wine_server_ptr_handle(call
->map_view
.handle
) );
1020 case APC_UNMAP_VIEW
:
1021 result
->type
= call
->type
;
1022 addr
= wine_server_get_ptr( call
->unmap_view
.addr
);
1023 if ((ULONG_PTR
)addr
== call
->unmap_view
.addr
)
1024 result
->unmap_view
.status
= NtUnmapViewOfSection( NtCurrentProcess(), addr
);
1026 result
->unmap_view
.status
= STATUS_INVALID_PARAMETER
;
1028 case APC_CREATE_THREAD
:
1032 SIZE_T reserve
= call
->create_thread
.reserve
;
1033 SIZE_T commit
= call
->create_thread
.commit
;
1034 void *func
= wine_server_get_ptr( call
->create_thread
.func
);
1035 void *arg
= wine_server_get_ptr( call
->create_thread
.arg
);
1037 result
->type
= call
->type
;
1038 if (reserve
== call
->create_thread
.reserve
&& commit
== call
->create_thread
.commit
&&
1039 (ULONG_PTR
)func
== call
->create_thread
.func
&& (ULONG_PTR
)arg
== call
->create_thread
.arg
)
1041 result
->create_thread
.status
= RtlCreateUserThread( NtCurrentProcess(), NULL
,
1042 call
->create_thread
.suspend
, NULL
,
1043 reserve
, commit
, func
, arg
, &handle
, &id
);
1044 result
->create_thread
.handle
= wine_server_obj_handle( handle
);
1045 result
->create_thread
.tid
= HandleToULong(id
.UniqueThread
);
1047 else result
->create_thread
.status
= STATUS_INVALID_PARAMETER
;
1051 server_protocol_error( "get_apc_request: bad type %d\n", call
->type
);
1057 /***********************************************************************
1058 * NTDLL_queue_process_apc
1060 NTSTATUS
NTDLL_queue_process_apc( HANDLE process
, const apc_call_t
*call
, apc_result_t
*result
)
1068 SERVER_START_REQ( queue_apc
)
1070 req
->handle
= wine_server_obj_handle( process
);
1072 if (!(ret
= wine_server_call( req
)))
1074 handle
= wine_server_ptr_handle( reply
->handle
);
1079 if (ret
!= STATUS_SUCCESS
) return ret
;
1083 invoke_apc( call
, result
);
1087 NtWaitForSingleObject( handle
, FALSE
, NULL
);
1089 SERVER_START_REQ( get_apc_result
)
1091 req
->handle
= wine_server_obj_handle( handle
);
1092 if (!(ret
= wine_server_call( req
))) *result
= reply
->result
;
1096 if (!ret
&& result
->type
== APC_NONE
) continue; /* APC didn't run, try again */
1097 if (ret
) NtClose( handle
);
1104 /***********************************************************************
1105 * NTDLL_wait_for_multiple_objects
1107 * Implementation of NtWaitForMultipleObjects
1109 NTSTATUS
NTDLL_wait_for_multiple_objects( const select_op_t
*select_op
, data_size_t size
, UINT flags
,
1110 const LARGE_INTEGER
*timeout
, HANDLE signal_object
)
1114 BOOL user_apc
= FALSE
;
1115 obj_handle_t apc_handle
= 0;
1117 apc_result_t result
;
1118 timeout_t abs_timeout
= timeout
? timeout
->QuadPart
: TIMEOUT_INFINITE
;
1120 memset( &result
, 0, sizeof(result
) );
1124 SERVER_START_REQ( select
)
1127 req
->cookie
= wine_server_client_ptr( &cookie
);
1128 req
->signal
= wine_server_obj_handle( signal_object
);
1129 req
->prev_apc
= apc_handle
;
1130 req
->timeout
= abs_timeout
;
1131 wine_server_add_data( req
, &result
, sizeof(result
) );
1132 wine_server_add_data( req
, select_op
, size
);
1133 ret
= wine_server_call( req
);
1134 abs_timeout
= reply
->timeout
;
1135 apc_handle
= reply
->apc_handle
;
1139 if (ret
== STATUS_PENDING
) ret
= wait_reply( &cookie
);
1140 if (ret
!= STATUS_USER_APC
) break;
1141 if (invoke_apc( &call
, &result
))
1143 /* if we ran a user apc we have to check once more if an object got signaled,
1144 * but we don't want to wait */
1148 signal_object
= 0; /* don't signal it multiple times */
1151 if (ret
== STATUS_TIMEOUT
&& user_apc
) ret
= STATUS_USER_APC
;
1153 /* A test on Windows 2000 shows that Windows always yields during
1154 a wait, but a wait that is hit by an event gets a priority
1155 boost as well. This seems to model that behavior the closest. */
1156 if (ret
== STATUS_TIMEOUT
) NtYieldExecution();
1162 /* wait operations */
1164 /******************************************************************
1165 * NtWaitForMultipleObjects (NTDLL.@)
1167 NTSTATUS WINAPI
NtWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
,
1168 BOOLEAN wait_all
, BOOLEAN alertable
,
1169 const LARGE_INTEGER
*timeout
)
1171 select_op_t select_op
;
1172 UINT i
, flags
= SELECT_INTERRUPTIBLE
;
1174 if (!count
|| count
> MAXIMUM_WAIT_OBJECTS
) return STATUS_INVALID_PARAMETER_1
;
1176 if (wait_all
) flags
|= SELECT_ALL
;
1177 if (alertable
) flags
|= SELECT_ALERTABLE
;
1178 select_op
.wait
.op
= SELECT_WAIT
;
1179 for (i
= 0; i
< count
; i
++) select_op
.wait
.handles
[i
] = wine_server_obj_handle( handles
[i
] );
1180 return NTDLL_wait_for_multiple_objects( &select_op
, offsetof( select_op_t
, wait
.handles
[count
] ), flags
, timeout
, 0 );
1184 /******************************************************************
1185 * NtWaitForSingleObject (NTDLL.@)
1187 NTSTATUS WINAPI
NtWaitForSingleObject(HANDLE handle
, BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1189 return NtWaitForMultipleObjects( 1, &handle
, FALSE
, alertable
, timeout
);
1193 /******************************************************************
1194 * NtSignalAndWaitForSingleObject (NTDLL.@)
1196 NTSTATUS WINAPI
NtSignalAndWaitForSingleObject( HANDLE hSignalObject
, HANDLE hWaitObject
,
1197 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1199 select_op_t select_op
;
1200 UINT flags
= SELECT_INTERRUPTIBLE
;
1202 if (!hSignalObject
) return STATUS_INVALID_HANDLE
;
1203 if (alertable
) flags
|= SELECT_ALERTABLE
;
1204 select_op
.wait
.op
= SELECT_WAIT
;
1205 select_op
.wait
.handles
[0] = wine_server_obj_handle( hWaitObject
);
1206 return NTDLL_wait_for_multiple_objects( &select_op
, offsetof( select_op_t
, wait
.handles
[1] ), flags
, timeout
, hSignalObject
);
1210 /******************************************************************
1211 * NtYieldExecution (NTDLL.@)
1213 NTSTATUS WINAPI
NtYieldExecution(void)
1215 #ifdef HAVE_SCHED_YIELD
1217 return STATUS_SUCCESS
;
1219 return STATUS_NO_YIELD_PERFORMED
;
1224 /******************************************************************
1225 * NtDelayExecution (NTDLL.@)
1227 NTSTATUS WINAPI
NtDelayExecution( BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1229 /* if alertable, we need to query the server */
1231 return NTDLL_wait_for_multiple_objects( NULL
, 0, SELECT_INTERRUPTIBLE
| SELECT_ALERTABLE
,
1234 if (!timeout
|| timeout
->QuadPart
== TIMEOUT_INFINITE
) /* sleep forever */
1236 for (;;) select( 0, NULL
, NULL
, NULL
, NULL
);
1241 timeout_t when
, diff
;
1243 if ((when
= timeout
->QuadPart
) < 0)
1245 NtQuerySystemTime( &now
);
1246 when
= now
.QuadPart
- when
;
1249 /* Note that we yield after establishing the desired timeout */
1251 if (!when
) return STATUS_SUCCESS
;
1256 NtQuerySystemTime( &now
);
1257 diff
= (when
- now
.QuadPart
+ 9) / 10;
1258 if (diff
<= 0) break;
1259 tv
.tv_sec
= diff
/ 1000000;
1260 tv
.tv_usec
= diff
% 1000000;
1261 if (select( 0, NULL
, NULL
, NULL
, &tv
) != -1) break;
1264 return STATUS_SUCCESS
;
1268 /******************************************************************************
1269 * NtCreateKeyedEvent (NTDLL.@)
1271 NTSTATUS WINAPI
NtCreateKeyedEvent( HANDLE
*handle
, ACCESS_MASK access
,
1272 const OBJECT_ATTRIBUTES
*attr
, ULONG flags
)
1274 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
1276 struct security_descriptor
*sd
= NULL
;
1277 struct object_attributes objattr
;
1279 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
1281 objattr
.rootdir
= wine_server_obj_handle( attr
? attr
->RootDirectory
: 0 );
1283 objattr
.name_len
= len
;
1286 ret
= NTDLL_create_struct_sd( attr
->SecurityDescriptor
, &sd
, &objattr
.sd_len
);
1287 if (ret
!= STATUS_SUCCESS
) return ret
;
1290 SERVER_START_REQ( create_keyed_event
)
1292 req
->access
= access
;
1293 req
->attributes
= attr
? attr
->Attributes
: 0;
1294 wine_server_add_data( req
, &objattr
, sizeof(objattr
) );
1295 if (objattr
.sd_len
) wine_server_add_data( req
, sd
, objattr
.sd_len
);
1296 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
1297 ret
= wine_server_call( req
);
1298 *handle
= wine_server_ptr_handle( reply
->handle
);
1302 NTDLL_free_struct_sd( sd
);
1306 /******************************************************************************
1307 * NtOpenKeyedEvent (NTDLL.@)
1309 NTSTATUS WINAPI
NtOpenKeyedEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
1311 DWORD len
= attr
&& attr
->ObjectName
? attr
->ObjectName
->Length
: 0;
1314 if (len
>= MAX_PATH
* sizeof(WCHAR
)) return STATUS_NAME_TOO_LONG
;
1316 SERVER_START_REQ( open_keyed_event
)
1318 req
->access
= access
;
1319 req
->attributes
= attr
? attr
->Attributes
: 0;
1320 req
->rootdir
= wine_server_obj_handle( attr
? attr
->RootDirectory
: 0 );
1321 if (len
) wine_server_add_data( req
, attr
->ObjectName
->Buffer
, len
);
1322 ret
= wine_server_call( req
);
1323 *handle
= wine_server_ptr_handle( reply
->handle
);
1329 /******************************************************************************
1330 * NtWaitForKeyedEvent (NTDLL.@)
1332 NTSTATUS WINAPI
NtWaitForKeyedEvent( HANDLE handle
, const void *key
,
1333 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1336 return STATUS_NOT_IMPLEMENTED
;
1339 /******************************************************************************
1340 * NtReleaseKeyedEvent (NTDLL.@)
1342 NTSTATUS WINAPI
NtReleaseKeyedEvent( HANDLE handle
, const void *key
,
1343 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1346 return STATUS_NOT_IMPLEMENTED
;
1349 /******************************************************************
1350 * NtCreateIoCompletion (NTDLL.@)
1351 * ZwCreateIoCompletion (NTDLL.@)
1353 * Creates I/O completion object.
1356 * CompletionPort [O] created completion object handle will be placed there
1357 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1358 * ObjectAttributes [I] completion object attributes
1359 * NumberOfConcurrentThreads [I] desired number of concurrent active worker threads
1362 NTSTATUS WINAPI
NtCreateIoCompletion( PHANDLE CompletionPort
, ACCESS_MASK DesiredAccess
,
1363 POBJECT_ATTRIBUTES ObjectAttributes
, ULONG NumberOfConcurrentThreads
)
1367 TRACE("(%p, %x, %p, %d)\n", CompletionPort
, DesiredAccess
,
1368 ObjectAttributes
, NumberOfConcurrentThreads
);
1370 if (!CompletionPort
)
1371 return STATUS_INVALID_PARAMETER
;
1373 SERVER_START_REQ( create_completion
)
1375 req
->access
= DesiredAccess
;
1376 req
->attributes
= ObjectAttributes
? ObjectAttributes
->Attributes
: 0;
1377 req
->rootdir
= wine_server_obj_handle( ObjectAttributes
? ObjectAttributes
->RootDirectory
: 0 );
1378 req
->concurrent
= NumberOfConcurrentThreads
;
1379 if (ObjectAttributes
&& ObjectAttributes
->ObjectName
)
1380 wine_server_add_data( req
, ObjectAttributes
->ObjectName
->Buffer
,
1381 ObjectAttributes
->ObjectName
->Length
);
1382 if (!(status
= wine_server_call( req
)))
1383 *CompletionPort
= wine_server_ptr_handle( reply
->handle
);
1389 /******************************************************************
1390 * NtSetIoCompletion (NTDLL.@)
1391 * ZwSetIoCompletion (NTDLL.@)
1393 * Inserts completion message into queue
1396 * CompletionPort [I] HANDLE to completion object
1397 * CompletionKey [I] completion key
1398 * CompletionValue [I] completion value (usually pointer to OVERLAPPED)
1399 * Status [I] operation status
1400 * NumberOfBytesTransferred [I] number of bytes transferred
1402 NTSTATUS WINAPI
NtSetIoCompletion( HANDLE CompletionPort
, ULONG_PTR CompletionKey
,
1403 ULONG_PTR CompletionValue
, NTSTATUS Status
,
1404 SIZE_T NumberOfBytesTransferred
)
1408 TRACE("(%p, %lx, %lx, %x, %lx)\n", CompletionPort
, CompletionKey
,
1409 CompletionValue
, Status
, NumberOfBytesTransferred
);
1411 SERVER_START_REQ( add_completion
)
1413 req
->handle
= wine_server_obj_handle( CompletionPort
);
1414 req
->ckey
= CompletionKey
;
1415 req
->cvalue
= CompletionValue
;
1416 req
->status
= Status
;
1417 req
->information
= NumberOfBytesTransferred
;
1418 status
= wine_server_call( req
);
1424 /******************************************************************
1425 * NtRemoveIoCompletion (NTDLL.@)
1426 * ZwRemoveIoCompletion (NTDLL.@)
1428 * (Wait for and) retrieve first completion message from completion object's queue
1431 * CompletionPort [I] HANDLE to I/O completion object
1432 * CompletionKey [O] completion key
1433 * CompletionValue [O] Completion value given in NtSetIoCompletion or in async operation
1434 * iosb [O] IO_STATUS_BLOCK of completed asynchronous operation
1435 * WaitTime [I] optional wait time in NTDLL format
1438 NTSTATUS WINAPI
NtRemoveIoCompletion( HANDLE CompletionPort
, PULONG_PTR CompletionKey
,
1439 PULONG_PTR CompletionValue
, PIO_STATUS_BLOCK iosb
,
1440 PLARGE_INTEGER WaitTime
)
1444 TRACE("(%p, %p, %p, %p, %p)\n", CompletionPort
, CompletionKey
,
1445 CompletionValue
, iosb
, WaitTime
);
1449 SERVER_START_REQ( remove_completion
)
1451 req
->handle
= wine_server_obj_handle( CompletionPort
);
1452 if (!(status
= wine_server_call( req
)))
1454 *CompletionKey
= reply
->ckey
;
1455 *CompletionValue
= reply
->cvalue
;
1456 iosb
->Information
= reply
->information
;
1457 iosb
->u
.Status
= reply
->status
;
1461 if (status
!= STATUS_PENDING
) break;
1463 status
= NtWaitForSingleObject( CompletionPort
, FALSE
, WaitTime
);
1464 if (status
!= WAIT_OBJECT_0
) break;
1469 /******************************************************************
1470 * NtOpenIoCompletion (NTDLL.@)
1471 * ZwOpenIoCompletion (NTDLL.@)
1473 * Opens I/O completion object
1476 * CompletionPort [O] completion object handle will be placed there
1477 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1478 * ObjectAttributes [I] completion object name
1481 NTSTATUS WINAPI
NtOpenIoCompletion( PHANDLE CompletionPort
, ACCESS_MASK DesiredAccess
,
1482 POBJECT_ATTRIBUTES ObjectAttributes
)
1486 TRACE("(%p, 0x%x, %p)\n", CompletionPort
, DesiredAccess
, ObjectAttributes
);
1488 if (!CompletionPort
|| !ObjectAttributes
|| !ObjectAttributes
->ObjectName
)
1489 return STATUS_INVALID_PARAMETER
;
1491 SERVER_START_REQ( open_completion
)
1493 req
->access
= DesiredAccess
;
1494 req
->rootdir
= wine_server_obj_handle( ObjectAttributes
->RootDirectory
);
1495 wine_server_add_data( req
, ObjectAttributes
->ObjectName
->Buffer
,
1496 ObjectAttributes
->ObjectName
->Length
);
1497 if (!(status
= wine_server_call( req
)))
1498 *CompletionPort
= wine_server_ptr_handle( reply
->handle
);
1504 /******************************************************************
1505 * NtQueryIoCompletion (NTDLL.@)
1506 * ZwQueryIoCompletion (NTDLL.@)
1508 * Requests information about given I/O completion object
1511 * CompletionPort [I] HANDLE to completion port to request
1512 * InformationClass [I] information class
1513 * CompletionInformation [O] user-provided buffer for data
1514 * BufferLength [I] buffer length
1515 * RequiredLength [O] required buffer length
1518 NTSTATUS WINAPI
NtQueryIoCompletion( HANDLE CompletionPort
, IO_COMPLETION_INFORMATION_CLASS InformationClass
,
1519 PVOID CompletionInformation
, ULONG BufferLength
, PULONG RequiredLength
)
1523 TRACE("(%p, %d, %p, 0x%x, %p)\n", CompletionPort
, InformationClass
, CompletionInformation
,
1524 BufferLength
, RequiredLength
);
1526 if (!CompletionInformation
) return STATUS_INVALID_PARAMETER
;
1527 switch( InformationClass
)
1529 case IoCompletionBasicInformation
:
1531 ULONG
*info
= CompletionInformation
;
1533 if (RequiredLength
) *RequiredLength
= sizeof(*info
);
1534 if (BufferLength
!= sizeof(*info
))
1535 status
= STATUS_INFO_LENGTH_MISMATCH
;
1538 SERVER_START_REQ( query_completion
)
1540 req
->handle
= wine_server_obj_handle( CompletionPort
);
1541 if (!(status
= wine_server_call( req
)))
1542 *info
= reply
->depth
;
1549 status
= STATUS_INVALID_PARAMETER
;
1555 NTSTATUS
NTDLL_AddCompletion( HANDLE hFile
, ULONG_PTR CompletionValue
,
1556 NTSTATUS CompletionStatus
, ULONG Information
)
1560 SERVER_START_REQ( add_fd_completion
)
1562 req
->handle
= wine_server_obj_handle( hFile
);
1563 req
->cvalue
= CompletionValue
;
1564 req
->status
= CompletionStatus
;
1565 req
->information
= Information
;
1566 status
= wine_server_call( req
);
1572 VOID NTAPI
RtlRunOnceInitialize(PRTL_RUN_ONCE initonce
)
1574 initonce
->Ptr
= NULL
;