TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / ntdll / sync.c
blob6892732346fa49a4bd393c3851977f096934e961
1 /*
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
24 #include "config.h"
25 #include "wine/port.h"
27 #include <assert.h>
28 #include <errno.h>
29 #include <signal.h>
30 #ifdef HAVE_SYS_TIME_H
31 # include <sys/time.h>
32 #endif
33 #ifdef HAVE_POLL_H
34 #include <poll.h>
35 #endif
36 #ifdef HAVE_SYS_POLL_H
37 # include <sys/poll.h>
38 #endif
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif
42 #ifdef HAVE_SCHED_H
43 # include <sched.h>
44 #endif
45 #include <string.h>
46 #include <stdarg.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <time.h>
51 #include "ntstatus.h"
52 #define WIN32_NO_STATUS
53 #define NONAMELESSUNION
54 #include "windef.h"
55 #include "winternl.h"
56 #include "wine/server.h"
57 #include "wine/debug.h"
58 #include "ntdll_misc.h"
60 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
62 HANDLE keyed_event = NULL;
64 static inline int interlocked_dec_if_nonzero( int *dest )
66 int val, tmp;
67 for (val = *dest;; val = tmp)
69 if (!val || (tmp = interlocked_cmpxchg( dest, val - 1, val )) == val)
70 break;
72 return val;
75 /* creates a struct security_descriptor and contained information in one contiguous piece of memory */
76 NTSTATUS NTDLL_create_struct_sd(PSECURITY_DESCRIPTOR nt_sd, struct security_descriptor **server_sd,
77 data_size_t *server_sd_len)
79 unsigned int len;
80 PSID owner, group;
81 ACL *dacl, *sacl;
82 BOOLEAN owner_present, group_present, dacl_present, sacl_present;
83 BOOLEAN defaulted;
84 NTSTATUS status;
85 unsigned char *ptr;
87 if (!nt_sd)
89 *server_sd = NULL;
90 *server_sd_len = 0;
91 return STATUS_SUCCESS;
94 len = sizeof(struct security_descriptor);
96 status = RtlGetOwnerSecurityDescriptor(nt_sd, &owner, &owner_present);
97 if (status != STATUS_SUCCESS) return status;
98 status = RtlGetGroupSecurityDescriptor(nt_sd, &group, &group_present);
99 if (status != STATUS_SUCCESS) return status;
100 status = RtlGetSaclSecurityDescriptor(nt_sd, &sacl_present, &sacl, &defaulted);
101 if (status != STATUS_SUCCESS) return status;
102 status = RtlGetDaclSecurityDescriptor(nt_sd, &dacl_present, &dacl, &defaulted);
103 if (status != STATUS_SUCCESS) return status;
105 if (owner_present)
106 len += RtlLengthSid(owner);
107 if (group_present)
108 len += RtlLengthSid(group);
109 if (sacl_present && sacl)
110 len += sacl->AclSize;
111 if (dacl_present && dacl)
112 len += dacl->AclSize;
114 /* fix alignment for the Unicode name that follows the structure */
115 len = (len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
116 *server_sd = RtlAllocateHeap(GetProcessHeap(), 0, len);
117 if (!*server_sd) return STATUS_NO_MEMORY;
119 (*server_sd)->control = ((SECURITY_DESCRIPTOR *)nt_sd)->Control & ~SE_SELF_RELATIVE;
120 (*server_sd)->owner_len = owner_present ? RtlLengthSid(owner) : 0;
121 (*server_sd)->group_len = group_present ? RtlLengthSid(group) : 0;
122 (*server_sd)->sacl_len = (sacl_present && sacl) ? sacl->AclSize : 0;
123 (*server_sd)->dacl_len = (dacl_present && dacl) ? dacl->AclSize : 0;
125 ptr = (unsigned char *)(*server_sd + 1);
126 memcpy(ptr, owner, (*server_sd)->owner_len);
127 ptr += (*server_sd)->owner_len;
128 memcpy(ptr, group, (*server_sd)->group_len);
129 ptr += (*server_sd)->group_len;
130 memcpy(ptr, sacl, (*server_sd)->sacl_len);
131 ptr += (*server_sd)->sacl_len;
132 memcpy(ptr, dacl, (*server_sd)->dacl_len);
134 *server_sd_len = len;
136 return STATUS_SUCCESS;
139 /* frees a struct security_descriptor allocated by NTDLL_create_struct_sd */
140 void NTDLL_free_struct_sd(struct security_descriptor *server_sd)
142 RtlFreeHeap(GetProcessHeap(), 0, server_sd);
146 * Semaphores
149 /******************************************************************************
150 * NtCreateSemaphore (NTDLL.@)
152 NTSTATUS WINAPI NtCreateSemaphore( OUT PHANDLE SemaphoreHandle,
153 IN ACCESS_MASK access,
154 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
155 IN LONG InitialCount,
156 IN LONG MaximumCount )
158 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
159 NTSTATUS ret;
160 struct object_attributes objattr;
161 struct security_descriptor *sd = NULL;
163 if (MaximumCount <= 0 || InitialCount < 0 || InitialCount > MaximumCount)
164 return STATUS_INVALID_PARAMETER;
165 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
167 objattr.rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
168 objattr.sd_len = 0;
169 objattr.name_len = len;
170 if (attr)
172 ret = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
173 if (ret != STATUS_SUCCESS) return ret;
176 SERVER_START_REQ( create_semaphore )
178 req->access = access;
179 req->attributes = (attr) ? attr->Attributes : 0;
180 req->initial = InitialCount;
181 req->max = MaximumCount;
182 wine_server_add_data( req, &objattr, sizeof(objattr) );
183 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
184 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
185 ret = wine_server_call( req );
186 *SemaphoreHandle = wine_server_ptr_handle( reply->handle );
188 SERVER_END_REQ;
190 NTDLL_free_struct_sd( sd );
192 return ret;
195 /******************************************************************************
196 * NtOpenSemaphore (NTDLL.@)
198 NTSTATUS WINAPI NtOpenSemaphore( OUT PHANDLE SemaphoreHandle,
199 IN ACCESS_MASK access,
200 IN const OBJECT_ATTRIBUTES *attr )
202 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
203 NTSTATUS ret;
205 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
207 SERVER_START_REQ( open_semaphore )
209 req->access = access;
210 req->attributes = (attr) ? attr->Attributes : 0;
211 req->rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
212 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
213 ret = wine_server_call( req );
214 *SemaphoreHandle = wine_server_ptr_handle( reply->handle );
216 SERVER_END_REQ;
217 return ret;
220 /******************************************************************************
221 * NtQuerySemaphore (NTDLL.@)
223 NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS class,
224 void *info, ULONG len, ULONG *ret_len )
226 NTSTATUS ret;
227 SEMAPHORE_BASIC_INFORMATION *out = info;
229 if (class != SemaphoreBasicInformation)
231 FIXME("(%p,%d,%u) Unknown class\n", handle, class, len);
232 return STATUS_INVALID_INFO_CLASS;
235 if (len != sizeof(SEMAPHORE_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
237 SERVER_START_REQ( query_semaphore )
239 req->handle = wine_server_obj_handle( handle );
240 if (!(ret = wine_server_call( req )))
242 out->CurrentCount = reply->current;
243 out->MaximumCount = reply->max;
244 if (ret_len) *ret_len = sizeof(SEMAPHORE_BASIC_INFORMATION);
247 SERVER_END_REQ;
249 return ret;
252 /******************************************************************************
253 * NtReleaseSemaphore (NTDLL.@)
255 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
257 NTSTATUS ret;
258 SERVER_START_REQ( release_semaphore )
260 req->handle = wine_server_obj_handle( handle );
261 req->count = count;
262 if (!(ret = wine_server_call( req )))
264 if (previous) *previous = reply->prev_count;
267 SERVER_END_REQ;
268 return ret;
272 * Events
275 /**************************************************************************
276 * NtCreateEvent (NTDLL.@)
277 * ZwCreateEvent (NTDLL.@)
279 NTSTATUS WINAPI NtCreateEvent( PHANDLE EventHandle, ACCESS_MASK DesiredAccess,
280 const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN InitialState)
282 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
283 NTSTATUS ret;
284 struct security_descriptor *sd = NULL;
285 struct object_attributes objattr;
287 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
289 objattr.rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
290 objattr.sd_len = 0;
291 objattr.name_len = len;
292 if (attr)
294 ret = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
295 if (ret != STATUS_SUCCESS) return ret;
298 SERVER_START_REQ( create_event )
300 req->access = DesiredAccess;
301 req->attributes = (attr) ? attr->Attributes : 0;
302 req->manual_reset = (type == NotificationEvent);
303 req->initial_state = InitialState;
304 wine_server_add_data( req, &objattr, sizeof(objattr) );
305 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
306 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
307 ret = wine_server_call( req );
308 *EventHandle = wine_server_ptr_handle( reply->handle );
310 SERVER_END_REQ;
312 NTDLL_free_struct_sd( sd );
314 return ret;
317 /******************************************************************************
318 * NtOpenEvent (NTDLL.@)
319 * ZwOpenEvent (NTDLL.@)
321 NTSTATUS WINAPI NtOpenEvent(
322 OUT PHANDLE EventHandle,
323 IN ACCESS_MASK DesiredAccess,
324 IN const OBJECT_ATTRIBUTES *attr )
326 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
327 NTSTATUS ret;
329 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
331 SERVER_START_REQ( open_event )
333 req->access = DesiredAccess;
334 req->attributes = (attr) ? attr->Attributes : 0;
335 req->rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
336 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
337 ret = wine_server_call( req );
338 *EventHandle = wine_server_ptr_handle( reply->handle );
340 SERVER_END_REQ;
341 return ret;
345 /******************************************************************************
346 * NtSetEvent (NTDLL.@)
347 * ZwSetEvent (NTDLL.@)
349 NTSTATUS WINAPI NtSetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
351 NTSTATUS ret;
353 /* FIXME: set NumberOfThreadsReleased */
355 SERVER_START_REQ( event_op )
357 req->handle = wine_server_obj_handle( handle );
358 req->op = SET_EVENT;
359 ret = wine_server_call( req );
361 SERVER_END_REQ;
362 return ret;
365 /******************************************************************************
366 * NtResetEvent (NTDLL.@)
368 NTSTATUS WINAPI NtResetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
370 NTSTATUS ret;
372 /* resetting an event can't release any thread... */
373 if (NumberOfThreadsReleased) *NumberOfThreadsReleased = 0;
375 SERVER_START_REQ( event_op )
377 req->handle = wine_server_obj_handle( handle );
378 req->op = RESET_EVENT;
379 ret = wine_server_call( req );
381 SERVER_END_REQ;
382 return ret;
385 /******************************************************************************
386 * NtClearEvent (NTDLL.@)
388 * FIXME
389 * same as NtResetEvent ???
391 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
393 return NtResetEvent( handle, NULL );
396 /******************************************************************************
397 * NtPulseEvent (NTDLL.@)
399 * FIXME
400 * PulseCount
402 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, PULONG PulseCount )
404 NTSTATUS ret;
406 if (PulseCount)
407 FIXME("(%p,%d)\n", handle, *PulseCount);
409 SERVER_START_REQ( event_op )
411 req->handle = wine_server_obj_handle( handle );
412 req->op = PULSE_EVENT;
413 ret = wine_server_call( req );
415 SERVER_END_REQ;
416 return ret;
419 /******************************************************************************
420 * NtQueryEvent (NTDLL.@)
422 NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class,
423 void *info, ULONG len, ULONG *ret_len )
425 NTSTATUS ret;
426 EVENT_BASIC_INFORMATION *out = info;
428 if (class != EventBasicInformation)
430 FIXME("(%p, %d, %d) Unknown class\n",
431 handle, class, len);
432 return STATUS_INVALID_INFO_CLASS;
435 if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
437 SERVER_START_REQ( query_event )
439 req->handle = wine_server_obj_handle( handle );
440 if (!(ret = wine_server_call( req )))
442 out->EventType = reply->manual_reset ? NotificationEvent : SynchronizationEvent;
443 out->EventState = reply->state;
444 if (ret_len) *ret_len = sizeof(EVENT_BASIC_INFORMATION);
447 SERVER_END_REQ;
449 return ret;
453 * Mutants (known as Mutexes in Kernel32)
456 /******************************************************************************
457 * NtCreateMutant [NTDLL.@]
458 * ZwCreateMutant [NTDLL.@]
460 NTSTATUS WINAPI NtCreateMutant(OUT HANDLE* MutantHandle,
461 IN ACCESS_MASK access,
462 IN const OBJECT_ATTRIBUTES* attr OPTIONAL,
463 IN BOOLEAN InitialOwner)
465 NTSTATUS status;
466 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
467 struct security_descriptor *sd = NULL;
468 struct object_attributes objattr;
470 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
472 objattr.rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
473 objattr.sd_len = 0;
474 objattr.name_len = len;
475 if (attr)
477 status = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
478 if (status != STATUS_SUCCESS) return status;
481 SERVER_START_REQ( create_mutex )
483 req->access = access;
484 req->attributes = (attr) ? attr->Attributes : 0;
485 req->owned = InitialOwner;
486 wine_server_add_data( req, &objattr, sizeof(objattr) );
487 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
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 );
492 SERVER_END_REQ;
494 NTDLL_free_struct_sd( sd );
496 return status;
499 /**************************************************************************
500 * NtOpenMutant [NTDLL.@]
501 * ZwOpenMutant [NTDLL.@]
503 NTSTATUS WINAPI NtOpenMutant(OUT HANDLE* MutantHandle,
504 IN ACCESS_MASK access,
505 IN const OBJECT_ATTRIBUTES* attr )
507 NTSTATUS status;
508 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
510 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
512 SERVER_START_REQ( open_mutex )
514 req->access = access;
515 req->attributes = (attr) ? attr->Attributes : 0;
516 req->rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
517 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
518 status = wine_server_call( req );
519 *MutantHandle = wine_server_ptr_handle( reply->handle );
521 SERVER_END_REQ;
522 return status;
525 /**************************************************************************
526 * NtReleaseMutant [NTDLL.@]
527 * ZwReleaseMutant [NTDLL.@]
529 NTSTATUS WINAPI NtReleaseMutant( IN HANDLE handle, OUT PLONG prev_count OPTIONAL)
531 NTSTATUS status;
533 SERVER_START_REQ( release_mutex )
535 req->handle = wine_server_obj_handle( handle );
536 status = wine_server_call( req );
537 if (prev_count) *prev_count = reply->prev_count;
539 SERVER_END_REQ;
540 return status;
543 /******************************************************************
544 * NtQueryMutant [NTDLL.@]
545 * ZwQueryMutant [NTDLL.@]
547 NTSTATUS WINAPI NtQueryMutant(IN HANDLE handle,
548 IN MUTANT_INFORMATION_CLASS MutantInformationClass,
549 OUT PVOID MutantInformation,
550 IN ULONG MutantInformationLength,
551 OUT PULONG ResultLength OPTIONAL )
553 FIXME("(%p %u %p %u %p): stub!\n",
554 handle, MutantInformationClass, MutantInformation, MutantInformationLength, ResultLength);
555 return STATUS_NOT_IMPLEMENTED;
559 * Jobs
562 /******************************************************************************
563 * NtCreateJobObject [NTDLL.@]
564 * ZwCreateJobObject [NTDLL.@]
566 NTSTATUS WINAPI NtCreateJobObject( PHANDLE handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
568 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
569 NTSTATUS ret;
570 struct security_descriptor *sd = NULL;
571 struct object_attributes objattr;
573 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
575 objattr.rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
576 objattr.sd_len = 0;
577 objattr.name_len = len;
578 if (attr)
580 ret = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
581 if (ret != STATUS_SUCCESS) return ret;
584 SERVER_START_REQ( create_job )
586 req->access = access;
587 req->attributes = attr ? attr->Attributes : 0;
588 wine_server_add_data( req, &objattr, sizeof(objattr) );
589 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
590 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
591 ret = wine_server_call( req );
592 *handle = wine_server_ptr_handle( reply->handle );
594 SERVER_END_REQ;
596 NTDLL_free_struct_sd( sd );
597 return ret;
600 /******************************************************************************
601 * NtOpenJobObject [NTDLL.@]
602 * ZwOpenJobObject [NTDLL.@]
604 NTSTATUS WINAPI NtOpenJobObject( PHANDLE handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
606 FIXME( "stub: %p %x %s\n", handle, access, attr ? debugstr_us(attr->ObjectName) : "" );
607 return STATUS_NOT_IMPLEMENTED;
610 /******************************************************************************
611 * NtTerminateJobObject [NTDLL.@]
612 * ZwTerminateJobObject [NTDLL.@]
614 NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status )
616 NTSTATUS ret;
618 TRACE( "(%p, %d)\n", handle, status );
620 SERVER_START_REQ( terminate_job )
622 req->handle = wine_server_obj_handle( handle );
623 req->status = status;
624 ret = wine_server_call( req );
626 SERVER_END_REQ;
628 return ret;
631 /******************************************************************************
632 * NtQueryInformationJobObject [NTDLL.@]
633 * ZwQueryInformationJobObject [NTDLL.@]
635 NTSTATUS WINAPI NtQueryInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info,
636 ULONG len, PULONG ret_len )
638 FIXME( "stub: %p %u %p %u %p\n", handle, class, info, len, ret_len );
640 if (class >= MaxJobObjectInfoClass)
641 return STATUS_INVALID_PARAMETER;
643 switch (class)
645 case JobObjectExtendedLimitInformation:
647 JOBOBJECT_EXTENDED_LIMIT_INFORMATION *extended_limit;
648 if (len < sizeof(*extended_limit))
649 return STATUS_INFO_LENGTH_MISMATCH;
651 extended_limit = (JOBOBJECT_EXTENDED_LIMIT_INFORMATION *)info;
652 memset(extended_limit, 0, sizeof(*extended_limit));
653 if (ret_len) *ret_len = sizeof(*extended_limit);
654 return STATUS_SUCCESS;
657 case JobObjectBasicLimitInformation:
659 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit;
660 if (len < sizeof(*basic_limit))
661 return STATUS_INFO_LENGTH_MISMATCH;
663 basic_limit = (JOBOBJECT_BASIC_LIMIT_INFORMATION *)info;
664 memset(basic_limit, 0, sizeof(*basic_limit));
665 if (ret_len) *ret_len = sizeof(*basic_limit);
666 return STATUS_SUCCESS;
669 default:
670 return STATUS_NOT_IMPLEMENTED;
674 /******************************************************************************
675 * NtSetInformationJobObject [NTDLL.@]
676 * ZwSetInformationJobObject [NTDLL.@]
678 NTSTATUS WINAPI NtSetInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info, ULONG len )
680 NTSTATUS status = STATUS_NOT_IMPLEMENTED;
681 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit;
682 ULONG info_size = sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION);
683 DWORD limit_flags = JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS;
685 TRACE( "(%p, %u, %p, %u)\n", handle, class, info, len );
687 if (class >= MaxJobObjectInfoClass)
688 return STATUS_INVALID_PARAMETER;
690 switch (class)
693 case JobObjectExtendedLimitInformation:
694 info_size = sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION);
695 limit_flags = JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS;
696 /* fallthrough */
697 case JobObjectBasicLimitInformation:
698 if (len != info_size)
699 return STATUS_INVALID_PARAMETER;
701 basic_limit = info;
702 if (basic_limit->LimitFlags & ~limit_flags)
703 return STATUS_INVALID_PARAMETER;
705 SERVER_START_REQ( set_job_limits )
707 req->handle = wine_server_obj_handle( handle );
708 req->limit_flags = basic_limit->LimitFlags;
709 status = wine_server_call( req );
711 SERVER_END_REQ;
712 break;
714 case JobObjectAssociateCompletionPortInformation:
715 if (len != sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT))
716 return STATUS_INVALID_PARAMETER;
718 SERVER_START_REQ( set_job_completion_port )
720 JOBOBJECT_ASSOCIATE_COMPLETION_PORT *port_info = info;
721 req->job = wine_server_obj_handle( handle );
722 req->port = wine_server_obj_handle( port_info->CompletionPort );
723 req->key = wine_server_client_ptr( port_info->CompletionKey );
724 status = wine_server_call(req);
726 SERVER_END_REQ;
727 break;
729 case JobObjectBasicUIRestrictions:
730 status = STATUS_SUCCESS;
731 /* fallthrough */
732 default:
733 FIXME( "stub: %p %u %p %u\n", handle, class, info, len );
736 return status;
739 /******************************************************************************
740 * NtIsProcessInJob [NTDLL.@]
741 * ZwIsProcessInJob [NTDLL.@]
743 NTSTATUS WINAPI NtIsProcessInJob( HANDLE process, HANDLE job )
745 NTSTATUS status;
747 TRACE( "(%p %p)\n", job, process );
749 SERVER_START_REQ( process_in_job )
751 req->job = wine_server_obj_handle( job );
752 req->process = wine_server_obj_handle( process );
753 status = wine_server_call( req );
755 SERVER_END_REQ;
757 return status;
760 /******************************************************************************
761 * NtAssignProcessToJobObject [NTDLL.@]
762 * ZwAssignProcessToJobObject [NTDLL.@]
764 NTSTATUS WINAPI NtAssignProcessToJobObject( HANDLE job, HANDLE process )
766 NTSTATUS status;
768 TRACE( "(%p %p)\n", job, process );
770 SERVER_START_REQ( assign_job )
772 req->job = wine_server_obj_handle( job );
773 req->process = wine_server_obj_handle( process );
774 status = wine_server_call( req );
776 SERVER_END_REQ;
778 return status;
782 * Timers
785 /**************************************************************************
786 * NtCreateTimer [NTDLL.@]
787 * ZwCreateTimer [NTDLL.@]
789 NTSTATUS WINAPI NtCreateTimer(OUT HANDLE *handle,
790 IN ACCESS_MASK access,
791 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
792 IN TIMER_TYPE timer_type)
794 DWORD len = (attr && attr->ObjectName) ? attr->ObjectName->Length : 0;
795 NTSTATUS status;
797 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
799 if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
800 return STATUS_INVALID_PARAMETER;
802 SERVER_START_REQ( create_timer )
804 req->access = access;
805 req->attributes = (attr) ? attr->Attributes : 0;
806 req->rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
807 req->manual = (timer_type == NotificationTimer);
808 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
809 status = wine_server_call( req );
810 *handle = wine_server_ptr_handle( reply->handle );
812 SERVER_END_REQ;
813 return status;
817 /**************************************************************************
818 * NtOpenTimer [NTDLL.@]
819 * ZwOpenTimer [NTDLL.@]
821 NTSTATUS WINAPI NtOpenTimer(OUT PHANDLE handle,
822 IN ACCESS_MASK access,
823 IN const OBJECT_ATTRIBUTES* attr )
825 DWORD len = (attr && attr->ObjectName) ? attr->ObjectName->Length : 0;
826 NTSTATUS status;
828 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
830 SERVER_START_REQ( open_timer )
832 req->access = access;
833 req->attributes = (attr) ? attr->Attributes : 0;
834 req->rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
835 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
836 status = wine_server_call( req );
837 *handle = wine_server_ptr_handle( reply->handle );
839 SERVER_END_REQ;
840 return status;
843 /**************************************************************************
844 * NtSetTimer [NTDLL.@]
845 * ZwSetTimer [NTDLL.@]
847 NTSTATUS WINAPI NtSetTimer(IN HANDLE handle,
848 IN const LARGE_INTEGER* when,
849 IN PTIMER_APC_ROUTINE callback,
850 IN PVOID callback_arg,
851 IN BOOLEAN resume,
852 IN ULONG period OPTIONAL,
853 OUT PBOOLEAN state OPTIONAL)
855 NTSTATUS status = STATUS_SUCCESS;
857 TRACE("(%p,%p,%p,%p,%08x,0x%08x,%p) stub\n",
858 handle, when, callback, callback_arg, resume, period, state);
860 SERVER_START_REQ( set_timer )
862 req->handle = wine_server_obj_handle( handle );
863 req->period = period;
864 req->expire = when->QuadPart;
865 req->callback = wine_server_client_ptr( callback );
866 req->arg = wine_server_client_ptr( callback_arg );
867 status = wine_server_call( req );
868 if (state) *state = reply->signaled;
870 SERVER_END_REQ;
872 /* set error but can still succeed */
873 if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
874 return status;
877 /**************************************************************************
878 * NtCancelTimer [NTDLL.@]
879 * ZwCancelTimer [NTDLL.@]
881 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
883 NTSTATUS status;
885 SERVER_START_REQ( cancel_timer )
887 req->handle = wine_server_obj_handle( handle );
888 status = wine_server_call( req );
889 if (state) *state = reply->signaled;
891 SERVER_END_REQ;
892 return status;
895 /******************************************************************************
896 * NtQueryTimer (NTDLL.@)
898 * Retrieves information about a timer.
900 * PARAMS
901 * TimerHandle [I] The timer to retrieve information about.
902 * TimerInformationClass [I] The type of information to retrieve.
903 * TimerInformation [O] Pointer to buffer to store information in.
904 * Length [I] The length of the buffer pointed to by TimerInformation.
905 * ReturnLength [O] Optional. The size of buffer actually used.
907 * RETURNS
908 * Success: STATUS_SUCCESS
909 * Failure: STATUS_INFO_LENGTH_MISMATCH, if Length doesn't match the required data
910 * size for the class specified.
911 * STATUS_INVALID_INFO_CLASS, if an invalid TimerInformationClass was specified.
912 * STATUS_ACCESS_DENIED, if TimerHandle does not have TIMER_QUERY_STATE access
913 * to the timer.
915 NTSTATUS WINAPI NtQueryTimer(
916 HANDLE TimerHandle,
917 TIMER_INFORMATION_CLASS TimerInformationClass,
918 PVOID TimerInformation,
919 ULONG Length,
920 PULONG ReturnLength)
922 TIMER_BASIC_INFORMATION * basic_info = TimerInformation;
923 NTSTATUS status;
924 LARGE_INTEGER now;
926 TRACE("(%p,%d,%p,0x%08x,%p)\n", TimerHandle, TimerInformationClass,
927 TimerInformation, Length, ReturnLength);
929 switch (TimerInformationClass)
931 case TimerBasicInformation:
932 if (Length < sizeof(TIMER_BASIC_INFORMATION))
933 return STATUS_INFO_LENGTH_MISMATCH;
935 SERVER_START_REQ(get_timer_info)
937 req->handle = wine_server_obj_handle( TimerHandle );
938 status = wine_server_call(req);
940 /* convert server time to absolute NTDLL time */
941 basic_info->RemainingTime.QuadPart = reply->when;
942 basic_info->TimerState = reply->signaled;
944 SERVER_END_REQ;
946 /* convert from absolute into relative time */
947 NtQuerySystemTime(&now);
948 if (now.QuadPart > basic_info->RemainingTime.QuadPart)
949 basic_info->RemainingTime.QuadPart = 0;
950 else
951 basic_info->RemainingTime.QuadPart -= now.QuadPart;
953 if (ReturnLength) *ReturnLength = sizeof(TIMER_BASIC_INFORMATION);
955 return status;
958 FIXME("Unhandled class %d\n", TimerInformationClass);
959 return STATUS_INVALID_INFO_CLASS;
963 /******************************************************************************
964 * NtQueryTimerResolution [NTDLL.@]
966 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
967 OUT ULONG* max_resolution,
968 OUT ULONG* current_resolution)
970 FIXME("(%p,%p,%p), stub!\n",
971 min_resolution, max_resolution, current_resolution);
973 return STATUS_NOT_IMPLEMENTED;
976 /******************************************************************************
977 * NtSetTimerResolution [NTDLL.@]
979 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
980 IN BOOLEAN set_resolution,
981 OUT ULONG* current_resolution )
983 FIXME("(%u,%u,%p), stub!\n",
984 resolution, set_resolution, current_resolution);
986 return STATUS_NOT_IMPLEMENTED;
991 /* wait operations */
993 static NTSTATUS wait_objects( DWORD count, const HANDLE *handles,
994 BOOLEAN wait_any, BOOLEAN alertable,
995 const LARGE_INTEGER *timeout )
997 select_op_t select_op;
998 UINT i, flags = SELECT_INTERRUPTIBLE;
1000 if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
1002 if (alertable) flags |= SELECT_ALERTABLE;
1003 select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL;
1004 for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] );
1005 return server_select( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout );
1009 /******************************************************************
1010 * NtWaitForMultipleObjects (NTDLL.@)
1012 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
1013 BOOLEAN wait_any, BOOLEAN alertable,
1014 const LARGE_INTEGER *timeout )
1016 return wait_objects( count, handles, wait_any, alertable, timeout );
1020 /******************************************************************
1021 * NtWaitForSingleObject (NTDLL.@)
1023 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
1025 return wait_objects( 1, &handle, FALSE, alertable, timeout );
1029 /******************************************************************
1030 * NtSignalAndWaitForSingleObject (NTDLL.@)
1032 NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE hSignalObject, HANDLE hWaitObject,
1033 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1035 select_op_t select_op;
1036 UINT flags = SELECT_INTERRUPTIBLE;
1038 if (!hSignalObject) return STATUS_INVALID_HANDLE;
1040 if (alertable) flags |= SELECT_ALERTABLE;
1041 select_op.signal_and_wait.op = SELECT_SIGNAL_AND_WAIT;
1042 select_op.signal_and_wait.wait = wine_server_obj_handle( hWaitObject );
1043 select_op.signal_and_wait.signal = wine_server_obj_handle( hSignalObject );
1044 return server_select( &select_op, sizeof(select_op.signal_and_wait), flags, timeout );
1048 /******************************************************************
1049 * NtYieldExecution (NTDLL.@)
1051 NTSTATUS WINAPI NtYieldExecution(void)
1053 #ifdef HAVE_SCHED_YIELD
1054 sched_yield();
1055 return STATUS_SUCCESS;
1056 #else
1057 return STATUS_NO_YIELD_PERFORMED;
1058 #endif
1062 /******************************************************************
1063 * NtDelayExecution (NTDLL.@)
1065 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
1067 /* if alertable, we need to query the server */
1068 if (alertable)
1069 return server_select( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout );
1071 if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */
1073 for (;;) select( 0, NULL, NULL, NULL, NULL );
1075 else
1077 LARGE_INTEGER now;
1078 timeout_t when, diff;
1080 if ((when = timeout->QuadPart) < 0)
1082 NtQuerySystemTime( &now );
1083 when = now.QuadPart - when;
1086 /* Note that we yield after establishing the desired timeout */
1087 NtYieldExecution();
1088 if (!when) return STATUS_SUCCESS;
1090 for (;;)
1092 struct timeval tv;
1093 NtQuerySystemTime( &now );
1094 diff = (when - now.QuadPart + 9) / 10;
1095 if (diff <= 0) break;
1096 tv.tv_sec = diff / 1000000;
1097 tv.tv_usec = diff % 1000000;
1098 if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
1101 return STATUS_SUCCESS;
1105 /******************************************************************************
1106 * NtCreateKeyedEvent (NTDLL.@)
1108 NTSTATUS WINAPI NtCreateKeyedEvent( HANDLE *handle, ACCESS_MASK access,
1109 const OBJECT_ATTRIBUTES *attr, ULONG flags )
1111 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
1112 NTSTATUS ret;
1113 struct security_descriptor *sd = NULL;
1114 struct object_attributes objattr;
1116 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
1118 objattr.rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
1119 objattr.sd_len = 0;
1120 objattr.name_len = len;
1121 if (attr)
1123 ret = NTDLL_create_struct_sd( attr->SecurityDescriptor, &sd, &objattr.sd_len );
1124 if (ret != STATUS_SUCCESS) return ret;
1127 SERVER_START_REQ( create_keyed_event )
1129 req->access = access;
1130 req->attributes = attr ? attr->Attributes : 0;
1131 wine_server_add_data( req, &objattr, sizeof(objattr) );
1132 if (objattr.sd_len) wine_server_add_data( req, sd, objattr.sd_len );
1133 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
1134 ret = wine_server_call( req );
1135 *handle = wine_server_ptr_handle( reply->handle );
1137 SERVER_END_REQ;
1139 NTDLL_free_struct_sd( sd );
1140 return ret;
1143 /******************************************************************************
1144 * NtOpenKeyedEvent (NTDLL.@)
1146 NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1148 DWORD len = attr && attr->ObjectName ? attr->ObjectName->Length : 0;
1149 NTSTATUS ret;
1151 if (len >= MAX_PATH * sizeof(WCHAR)) return STATUS_NAME_TOO_LONG;
1153 SERVER_START_REQ( open_keyed_event )
1155 req->access = access;
1156 req->attributes = attr ? attr->Attributes : 0;
1157 req->rootdir = wine_server_obj_handle( attr ? attr->RootDirectory : 0 );
1158 if (len) wine_server_add_data( req, attr->ObjectName->Buffer, len );
1159 ret = wine_server_call( req );
1160 *handle = wine_server_ptr_handle( reply->handle );
1162 SERVER_END_REQ;
1163 return ret;
1166 /******************************************************************************
1167 * NtWaitForKeyedEvent (NTDLL.@)
1169 NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
1170 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1172 select_op_t select_op;
1173 UINT flags = SELECT_INTERRUPTIBLE;
1175 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1176 if (alertable) flags |= SELECT_ALERTABLE;
1177 select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT;
1178 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1179 select_op.keyed_event.key = wine_server_client_ptr( key );
1180 return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1183 /******************************************************************************
1184 * NtReleaseKeyedEvent (NTDLL.@)
1186 NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key,
1187 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1189 select_op_t select_op;
1190 UINT flags = SELECT_INTERRUPTIBLE;
1192 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1193 if (alertable) flags |= SELECT_ALERTABLE;
1194 select_op.keyed_event.op = SELECT_KEYED_EVENT_RELEASE;
1195 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1196 select_op.keyed_event.key = wine_server_client_ptr( key );
1197 return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1200 /******************************************************************
1201 * NtCreateIoCompletion (NTDLL.@)
1202 * ZwCreateIoCompletion (NTDLL.@)
1204 * Creates I/O completion object.
1206 * PARAMS
1207 * CompletionPort [O] created completion object handle will be placed there
1208 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1209 * ObjectAttributes [I] completion object attributes
1210 * NumberOfConcurrentThreads [I] desired number of concurrent active worker threads
1213 NTSTATUS WINAPI NtCreateIoCompletion( PHANDLE CompletionPort, ACCESS_MASK DesiredAccess,
1214 POBJECT_ATTRIBUTES ObjectAttributes, ULONG NumberOfConcurrentThreads )
1216 NTSTATUS status;
1218 TRACE("(%p, %x, %p, %d)\n", CompletionPort, DesiredAccess,
1219 ObjectAttributes, NumberOfConcurrentThreads);
1221 if (!CompletionPort)
1222 return STATUS_INVALID_PARAMETER;
1224 SERVER_START_REQ( create_completion )
1226 req->access = DesiredAccess;
1227 req->attributes = ObjectAttributes ? ObjectAttributes->Attributes : 0;
1228 req->rootdir = wine_server_obj_handle( ObjectAttributes ? ObjectAttributes->RootDirectory : 0 );
1229 req->concurrent = NumberOfConcurrentThreads;
1230 if (ObjectAttributes && ObjectAttributes->ObjectName)
1231 wine_server_add_data( req, ObjectAttributes->ObjectName->Buffer,
1232 ObjectAttributes->ObjectName->Length );
1233 if (!(status = wine_server_call( req )))
1234 *CompletionPort = wine_server_ptr_handle( reply->handle );
1236 SERVER_END_REQ;
1237 return status;
1240 /******************************************************************
1241 * NtSetIoCompletion (NTDLL.@)
1242 * ZwSetIoCompletion (NTDLL.@)
1244 * Inserts completion message into queue
1246 * PARAMS
1247 * CompletionPort [I] HANDLE to completion object
1248 * CompletionKey [I] completion key
1249 * CompletionValue [I] completion value (usually pointer to OVERLAPPED)
1250 * Status [I] operation status
1251 * NumberOfBytesTransferred [I] number of bytes transferred
1253 NTSTATUS WINAPI NtSetIoCompletion( HANDLE CompletionPort, ULONG_PTR CompletionKey,
1254 ULONG_PTR CompletionValue, NTSTATUS Status,
1255 SIZE_T NumberOfBytesTransferred )
1257 NTSTATUS status;
1259 TRACE("(%p, %lx, %lx, %x, %lx)\n", CompletionPort, CompletionKey,
1260 CompletionValue, Status, NumberOfBytesTransferred);
1262 SERVER_START_REQ( add_completion )
1264 req->handle = wine_server_obj_handle( CompletionPort );
1265 req->ckey = CompletionKey;
1266 req->cvalue = CompletionValue;
1267 req->status = Status;
1268 req->information = NumberOfBytesTransferred;
1269 status = wine_server_call( req );
1271 SERVER_END_REQ;
1272 return status;
1275 /******************************************************************
1276 * NtRemoveIoCompletion (NTDLL.@)
1277 * ZwRemoveIoCompletion (NTDLL.@)
1279 * (Wait for and) retrieve first completion message from completion object's queue
1281 * PARAMS
1282 * CompletionPort [I] HANDLE to I/O completion object
1283 * CompletionKey [O] completion key
1284 * CompletionValue [O] Completion value given in NtSetIoCompletion or in async operation
1285 * iosb [O] IO_STATUS_BLOCK of completed asynchronous operation
1286 * WaitTime [I] optional wait time in NTDLL format
1289 NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE CompletionPort, PULONG_PTR CompletionKey,
1290 PULONG_PTR CompletionValue, PIO_STATUS_BLOCK iosb,
1291 PLARGE_INTEGER WaitTime )
1293 NTSTATUS status;
1295 TRACE("(%p, %p, %p, %p, %p)\n", CompletionPort, CompletionKey,
1296 CompletionValue, iosb, WaitTime);
1298 for(;;)
1300 SERVER_START_REQ( remove_completion )
1302 req->handle = wine_server_obj_handle( CompletionPort );
1303 if (!(status = wine_server_call( req )))
1305 *CompletionKey = reply->ckey;
1306 *CompletionValue = reply->cvalue;
1307 iosb->Information = reply->information;
1308 iosb->u.Status = reply->status;
1311 SERVER_END_REQ;
1312 if (status != STATUS_PENDING) break;
1314 status = NtWaitForSingleObject( CompletionPort, FALSE, WaitTime );
1315 if (status != WAIT_OBJECT_0) break;
1317 return status;
1320 /******************************************************************
1321 * NtOpenIoCompletion (NTDLL.@)
1322 * ZwOpenIoCompletion (NTDLL.@)
1324 * Opens I/O completion object
1326 * PARAMS
1327 * CompletionPort [O] completion object handle will be placed there
1328 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1329 * ObjectAttributes [I] completion object name
1332 NTSTATUS WINAPI NtOpenIoCompletion( PHANDLE CompletionPort, ACCESS_MASK DesiredAccess,
1333 POBJECT_ATTRIBUTES ObjectAttributes )
1335 NTSTATUS status;
1337 TRACE("(%p, 0x%x, %p)\n", CompletionPort, DesiredAccess, ObjectAttributes);
1339 if (!CompletionPort || !ObjectAttributes || !ObjectAttributes->ObjectName)
1340 return STATUS_INVALID_PARAMETER;
1342 SERVER_START_REQ( open_completion )
1344 req->access = DesiredAccess;
1345 req->rootdir = wine_server_obj_handle( ObjectAttributes->RootDirectory );
1346 wine_server_add_data( req, ObjectAttributes->ObjectName->Buffer,
1347 ObjectAttributes->ObjectName->Length );
1348 if (!(status = wine_server_call( req )))
1349 *CompletionPort = wine_server_ptr_handle( reply->handle );
1351 SERVER_END_REQ;
1352 return status;
1355 /******************************************************************
1356 * NtQueryIoCompletion (NTDLL.@)
1357 * ZwQueryIoCompletion (NTDLL.@)
1359 * Requests information about given I/O completion object
1361 * PARAMS
1362 * CompletionPort [I] HANDLE to completion port to request
1363 * InformationClass [I] information class
1364 * CompletionInformation [O] user-provided buffer for data
1365 * BufferLength [I] buffer length
1366 * RequiredLength [O] required buffer length
1369 NTSTATUS WINAPI NtQueryIoCompletion( HANDLE CompletionPort, IO_COMPLETION_INFORMATION_CLASS InformationClass,
1370 PVOID CompletionInformation, ULONG BufferLength, PULONG RequiredLength )
1372 NTSTATUS status;
1374 TRACE("(%p, %d, %p, 0x%x, %p)\n", CompletionPort, InformationClass, CompletionInformation,
1375 BufferLength, RequiredLength);
1377 if (!CompletionInformation) return STATUS_INVALID_PARAMETER;
1378 switch( InformationClass )
1380 case IoCompletionBasicInformation:
1382 ULONG *info = CompletionInformation;
1384 if (RequiredLength) *RequiredLength = sizeof(*info);
1385 if (BufferLength != sizeof(*info))
1386 status = STATUS_INFO_LENGTH_MISMATCH;
1387 else
1389 SERVER_START_REQ( query_completion )
1391 req->handle = wine_server_obj_handle( CompletionPort );
1392 if (!(status = wine_server_call( req )))
1393 *info = reply->depth;
1395 SERVER_END_REQ;
1398 break;
1399 default:
1400 status = STATUS_INVALID_PARAMETER;
1401 break;
1403 return status;
1406 NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue,
1407 NTSTATUS CompletionStatus, ULONG Information )
1409 NTSTATUS status;
1411 SERVER_START_REQ( add_fd_completion )
1413 req->handle = wine_server_obj_handle( hFile );
1414 req->cvalue = CompletionValue;
1415 req->status = CompletionStatus;
1416 req->information = Information;
1417 status = wine_server_call( req );
1419 SERVER_END_REQ;
1420 return status;
1423 /******************************************************************
1424 * RtlRunOnceInitialize (NTDLL.@)
1426 void WINAPI RtlRunOnceInitialize( RTL_RUN_ONCE *once )
1428 once->Ptr = NULL;
1431 /******************************************************************
1432 * RtlRunOnceBeginInitialize (NTDLL.@)
1434 DWORD WINAPI RtlRunOnceBeginInitialize( RTL_RUN_ONCE *once, ULONG flags, void **context )
1436 if (flags & RTL_RUN_ONCE_CHECK_ONLY)
1438 ULONG_PTR val = (ULONG_PTR)once->Ptr;
1440 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1441 if ((val & 3) != 2) return STATUS_UNSUCCESSFUL;
1442 if (context) *context = (void *)(val & ~3);
1443 return STATUS_SUCCESS;
1446 for (;;)
1448 ULONG_PTR next, val = (ULONG_PTR)once->Ptr;
1450 switch (val & 3)
1452 case 0: /* first time */
1453 if (!interlocked_cmpxchg_ptr( &once->Ptr,
1454 (flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0 ))
1455 return STATUS_PENDING;
1456 break;
1458 case 1: /* in progress, wait */
1459 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1460 next = val & ~3;
1461 if (interlocked_cmpxchg_ptr( &once->Ptr, (void *)((ULONG_PTR)&next | 1),
1462 (void *)val ) == (void *)val)
1463 NtWaitForKeyedEvent( keyed_event, &next, FALSE, NULL );
1464 break;
1466 case 2: /* done */
1467 if (context) *context = (void *)(val & ~3);
1468 return STATUS_SUCCESS;
1470 case 3: /* in progress, async */
1471 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
1472 return STATUS_PENDING;
1477 /******************************************************************
1478 * RtlRunOnceComplete (NTDLL.@)
1480 DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context )
1482 if ((ULONG_PTR)context & 3) return STATUS_INVALID_PARAMETER;
1484 if (flags & RTL_RUN_ONCE_INIT_FAILED)
1486 if (context) return STATUS_INVALID_PARAMETER;
1487 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1489 else context = (void *)((ULONG_PTR)context | 2);
1491 for (;;)
1493 ULONG_PTR val = (ULONG_PTR)once->Ptr;
1495 switch (val & 3)
1497 case 1: /* in progress */
1498 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break;
1499 val &= ~3;
1500 while (val)
1502 ULONG_PTR next = *(ULONG_PTR *)val;
1503 NtReleaseKeyedEvent( keyed_event, (void *)val, FALSE, NULL );
1504 val = next;
1506 return STATUS_SUCCESS;
1508 case 3: /* in progress, async */
1509 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
1510 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break;
1511 return STATUS_SUCCESS;
1513 default:
1514 return STATUS_UNSUCCESSFUL;
1519 /******************************************************************
1520 * RtlRunOnceExecuteOnce (NTDLL.@)
1522 DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN func,
1523 void *param, void **context )
1525 DWORD ret = RtlRunOnceBeginInitialize( once, 0, context );
1527 if (ret != STATUS_PENDING) return ret;
1529 if (!func( once, param, context ))
1531 RtlRunOnceComplete( once, RTL_RUN_ONCE_INIT_FAILED, NULL );
1532 return STATUS_UNSUCCESSFUL;
1535 return RtlRunOnceComplete( once, 0, context ? *context : NULL );
1539 /* SRW locks implementation
1541 * The memory layout used by the lock is:
1543 * 32 31 16 0
1544 * ________________ ________________
1545 * | X| #exclusive | #shared |
1546 * ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
1547 * Since there is no space left for a separate counter of shared access
1548 * threads inside the locked section the #shared field is used for multiple
1549 * purposes. The following table lists all possible states the lock can be
1550 * in, notation: [X, #exclusive, #shared]:
1552 * [0, 0, N] -> locked by N shared access threads, if N=0 its unlocked
1553 * [0, >=1, >=1] -> threads are requesting exclusive locks, but there are
1554 * still shared access threads inside. #shared should not be incremented
1555 * anymore!
1556 * [1, >=1, >=0] -> lock is owned by an exclusive thread and the #shared
1557 * counter can be used again to count the number of threads waiting in the
1558 * queue for shared access.
1560 * the following states are invalid and will never occur:
1561 * [0, >=1, 0], [1, 0, >=0]
1563 * The main problem arising from the fact that we have no separate counter
1564 * of shared access threads inside the locked section is that in the state
1565 * [0, >=1, >=1] above we cannot add additional waiting threads to the
1566 * shared access queue - it wouldn't be possible to distinguish waiting
1567 * threads and those that are still inside. To solve this problem the lock
1568 * uses the following approach: a thread that isn't able to allocate a
1569 * shared lock just uses the exclusive queue instead. As soon as the thread
1570 * is woken up it is in the state [1, >=1, >=0]. In this state it's again
1571 * possible to use the shared access queue. The thread atomically moves
1572 * itself to the shared access queue and releases the exclusive lock, so
1573 * that the "real" exclusive access threads have a chance. As soon as they
1574 * are all ready the shared access threads are processed.
1577 #define SRWLOCK_MASK_IN_EXCLUSIVE 0x80000000
1578 #define SRWLOCK_MASK_EXCLUSIVE_QUEUE 0x7fff0000
1579 #define SRWLOCK_MASK_SHARED_QUEUE 0x0000ffff
1580 #define SRWLOCK_RES_EXCLUSIVE 0x00010000
1581 #define SRWLOCK_RES_SHARED 0x00000001
1583 #ifdef WORDS_BIGENDIAN
1584 #define srwlock_key_exclusive(lock) (&lock->Ptr)
1585 #define srwlock_key_shared(lock) ((void *)((char *)&lock->Ptr + 2))
1586 #else
1587 #define srwlock_key_exclusive(lock) ((void *)((char *)&lock->Ptr + 2))
1588 #define srwlock_key_shared(lock) (&lock->Ptr)
1589 #endif
1591 static inline void srwlock_check_invalid( unsigned int val )
1593 /* Throw exception if it's impossible to acquire/release this lock. */
1594 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) == SRWLOCK_MASK_EXCLUSIVE_QUEUE ||
1595 (val & SRWLOCK_MASK_SHARED_QUEUE) == SRWLOCK_MASK_SHARED_QUEUE)
1596 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED);
1599 static inline unsigned int srwlock_lock_exclusive( unsigned int *dest, int incr )
1601 unsigned int val, tmp;
1602 /* Atomically modifies the value of *dest by adding incr. If the shared
1603 * queue is empty and there are threads waiting for exclusive access, then
1604 * sets the mark SRWLOCK_MASK_IN_EXCLUSIVE to signal other threads that
1605 * they are allowed again to use the shared queue counter. */
1606 for (val = *dest;; val = tmp)
1608 tmp = val + incr;
1609 srwlock_check_invalid( tmp );
1610 if ((tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(tmp & SRWLOCK_MASK_SHARED_QUEUE))
1611 tmp |= SRWLOCK_MASK_IN_EXCLUSIVE;
1612 if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val)
1613 break;
1615 return val;
1618 static inline unsigned int srwlock_unlock_exclusive( unsigned int *dest, int incr )
1620 unsigned int val, tmp;
1621 /* Atomically modifies the value of *dest by adding incr. If the queue of
1622 * threads waiting for exclusive access is empty, then remove the
1623 * SRWLOCK_MASK_IN_EXCLUSIVE flag (only the shared queue counter will
1624 * remain). */
1625 for (val = *dest;; val = tmp)
1627 tmp = val + incr;
1628 srwlock_check_invalid( tmp );
1629 if (!(tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE))
1630 tmp &= SRWLOCK_MASK_SHARED_QUEUE;
1631 if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val)
1632 break;
1634 return val;
1637 static inline void srwlock_leave_exclusive( RTL_SRWLOCK *lock, unsigned int val )
1639 /* Used when a thread leaves an exclusive section. If there are other
1640 * exclusive access threads they are processed first, followed by
1641 * the shared waiters. */
1642 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
1643 NtReleaseKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1644 else
1646 val &= SRWLOCK_MASK_SHARED_QUEUE; /* remove SRWLOCK_MASK_IN_EXCLUSIVE */
1647 while (val--)
1648 NtReleaseKeyedEvent( keyed_event, srwlock_key_shared(lock), FALSE, NULL );
1652 static inline void srwlock_leave_shared( RTL_SRWLOCK *lock, unsigned int val )
1654 /* Wake up one exclusive thread as soon as the last shared access thread
1655 * has left. */
1656 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_SHARED_QUEUE))
1657 NtReleaseKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1660 /***********************************************************************
1661 * RtlInitializeSRWLock (NTDLL.@)
1663 * NOTES
1664 * Please note that SRWLocks do not keep track of the owner of a lock.
1665 * It doesn't make any difference which thread for example unlocks an
1666 * SRWLock (see corresponding tests). This implementation uses two
1667 * keyed events (one for the exclusive waiters and one for the shared
1668 * waiters) and is limited to 2^15-1 waiting threads.
1670 void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock )
1672 lock->Ptr = NULL;
1675 /***********************************************************************
1676 * RtlAcquireSRWLockExclusive (NTDLL.@)
1678 * NOTES
1679 * Unlike RtlAcquireResourceExclusive this function doesn't allow
1680 * nested calls from the same thread. "Upgrading" a shared access lock
1681 * to an exclusive access lock also doesn't seem to be supported.
1683 void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
1685 if (srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, SRWLOCK_RES_EXCLUSIVE ))
1686 NtWaitForKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1689 /***********************************************************************
1690 * RtlAcquireSRWLockShared (NTDLL.@)
1692 * NOTES
1693 * Do not call this function recursively - it will only succeed when
1694 * there are no threads waiting for an exclusive lock!
1696 void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
1698 unsigned int val, tmp;
1699 /* Acquires a shared lock. If it's currently not possible to add elements to
1700 * the shared queue, then request exclusive access instead. */
1701 for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
1703 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
1704 tmp = val + SRWLOCK_RES_EXCLUSIVE;
1705 else
1706 tmp = val + SRWLOCK_RES_SHARED;
1707 if ((tmp = interlocked_cmpxchg( (int *)&lock->Ptr, tmp, val )) == val)
1708 break;
1711 /* Drop exclusive access again and instead requeue for shared access. */
1712 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
1714 NtWaitForKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1715 val = srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr, (SRWLOCK_RES_SHARED
1716 - SRWLOCK_RES_EXCLUSIVE) ) - SRWLOCK_RES_EXCLUSIVE;
1717 srwlock_leave_exclusive( lock, val );
1720 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
1721 NtWaitForKeyedEvent( keyed_event, srwlock_key_shared(lock), FALSE, NULL );
1724 /***********************************************************************
1725 * RtlReleaseSRWLockExclusive (NTDLL.@)
1727 void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
1729 srwlock_leave_exclusive( lock, srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr,
1730 - SRWLOCK_RES_EXCLUSIVE ) - SRWLOCK_RES_EXCLUSIVE );
1733 /***********************************************************************
1734 * RtlReleaseSRWLockShared (NTDLL.@)
1736 void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
1738 srwlock_leave_shared( lock, srwlock_lock_exclusive( (unsigned int *)&lock->Ptr,
1739 - SRWLOCK_RES_SHARED ) - SRWLOCK_RES_SHARED );
1742 /***********************************************************************
1743 * RtlTryAcquireSRWLockExclusive (NTDLL.@)
1745 * NOTES
1746 * Similar to AcquireSRWLockExclusive recusive calls are not allowed
1747 * and will fail with return value FALSE.
1749 BOOLEAN WINAPI RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
1751 return interlocked_cmpxchg( (int *)&lock->Ptr, SRWLOCK_MASK_IN_EXCLUSIVE |
1752 SRWLOCK_RES_EXCLUSIVE, 0 ) == 0;
1755 /***********************************************************************
1756 * RtlTryAcquireSRWLockShared (NTDLL.@)
1758 BOOLEAN WINAPI RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock )
1760 unsigned int val, tmp;
1761 for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
1763 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
1764 return FALSE;
1765 if ((tmp = interlocked_cmpxchg( (int *)&lock->Ptr, val + SRWLOCK_RES_SHARED, val )) == val)
1766 break;
1768 return TRUE;
1771 /***********************************************************************
1772 * RtlInitializeConditionVariable (NTDLL.@)
1774 * Initializes the condition variable with NULL.
1776 * PARAMS
1777 * variable [O] condition variable
1779 * RETURNS
1780 * Nothing.
1782 void WINAPI RtlInitializeConditionVariable( RTL_CONDITION_VARIABLE *variable )
1784 variable->Ptr = NULL;
1787 /***********************************************************************
1788 * RtlWakeConditionVariable (NTDLL.@)
1790 * Wakes up one thread waiting on the condition variable.
1792 * PARAMS
1793 * variable [I/O] condition variable to wake up.
1795 * RETURNS
1796 * Nothing.
1798 * NOTES
1799 * The calling thread does not have to own any lock in order to call
1800 * this function.
1802 void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable )
1804 if (interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
1805 NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1808 /***********************************************************************
1809 * RtlWakeAllConditionVariable (NTDLL.@)
1811 * See WakeConditionVariable, wakes up all waiting threads.
1813 void WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *variable )
1815 int val = interlocked_xchg( (int *)&variable->Ptr, 0 );
1816 while (val-- > 0)
1817 NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1820 /***********************************************************************
1821 * RtlSleepConditionVariableCS (NTDLL.@)
1823 * Atomically releases the critical section and suspends the thread,
1824 * waiting for a Wake(All)ConditionVariable event. Afterwards it enters
1825 * the critical section again and returns.
1827 * PARAMS
1828 * variable [I/O] condition variable
1829 * crit [I/O] critical section to leave temporarily
1830 * timeout [I] timeout
1832 * RETURNS
1833 * see NtWaitForKeyedEvent for all possible return values.
1835 NTSTATUS WINAPI RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, RTL_CRITICAL_SECTION *crit,
1836 const LARGE_INTEGER *timeout )
1838 NTSTATUS status;
1839 interlocked_xchg_add( (int *)&variable->Ptr, 1 );
1840 RtlLeaveCriticalSection( crit );
1842 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, timeout );
1843 if (status != STATUS_SUCCESS)
1845 if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
1846 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1849 RtlEnterCriticalSection( crit );
1850 return status;
1853 /***********************************************************************
1854 * RtlSleepConditionVariableSRW (NTDLL.@)
1856 * Atomically releases the SRWLock and suspends the thread,
1857 * waiting for a Wake(All)ConditionVariable event. Afterwards it enters
1858 * the SRWLock again with the same access rights and returns.
1860 * PARAMS
1861 * variable [I/O] condition variable
1862 * lock [I/O] SRWLock to leave temporarily
1863 * timeout [I] timeout
1864 * flags [I] type of the current lock (exclusive / shared)
1866 * RETURNS
1867 * see NtWaitForKeyedEvent for all possible return values.
1869 * NOTES
1870 * the behaviour is undefined if the thread doesn't own the lock.
1872 NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, RTL_SRWLOCK *lock,
1873 const LARGE_INTEGER *timeout, ULONG flags )
1875 NTSTATUS status;
1876 interlocked_xchg_add( (int *)&variable->Ptr, 1 );
1878 if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
1879 RtlReleaseSRWLockShared( lock );
1880 else
1881 RtlReleaseSRWLockExclusive( lock );
1883 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, timeout );
1884 if (status != STATUS_SUCCESS)
1886 if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
1887 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1890 if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
1891 RtlAcquireSRWLockShared( lock );
1892 else
1893 RtlAcquireSRWLockExclusive( lock );
1894 return status;