usp10/tests: A spelling fix in an ok() message.
[wine.git] / dlls / ntdll / sync.c
blob35b89df52ed7bc5e7d22415024b868d92cf4da13
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 <limits.h>
30 #include <signal.h>
31 #ifdef HAVE_SYS_SYSCALL_H
32 #include <sys/syscall.h>
33 #endif
34 #ifdef HAVE_SYS_TIME_H
35 # include <sys/time.h>
36 #endif
37 #ifdef HAVE_POLL_H
38 #include <poll.h>
39 #endif
40 #ifdef HAVE_SYS_POLL_H
41 # include <sys/poll.h>
42 #endif
43 #ifdef HAVE_UNISTD_H
44 # include <unistd.h>
45 #endif
46 #ifdef HAVE_SCHED_H
47 # include <sched.h>
48 #endif
49 #include <string.h>
50 #include <stdarg.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <time.h>
55 #include "ntstatus.h"
56 #define WIN32_NO_STATUS
57 #define NONAMELESSUNION
58 #include "windef.h"
59 #include "winternl.h"
60 #include "wine/server.h"
61 #include "wine/debug.h"
62 #include "ntdll_misc.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(sync);
66 HANDLE keyed_event = NULL;
68 static const LARGE_INTEGER zero_timeout;
70 #define TICKSPERSEC 10000000
72 #ifdef __linux__
74 #define FUTEX_WAIT 0
75 #define FUTEX_WAKE 1
76 #define FUTEX_WAIT_BITSET 9
77 #define FUTEX_WAKE_BITSET 10
79 static int futex_private = 128;
81 static inline int futex_wait( const int *addr, int val, struct timespec *timeout )
83 return syscall( __NR_futex, addr, FUTEX_WAIT | futex_private, val, timeout, 0, 0 );
86 static inline int futex_wake( const int *addr, int val )
88 return syscall( __NR_futex, addr, FUTEX_WAKE | futex_private, val, NULL, 0, 0 );
91 static inline int futex_wait_bitset( const int *addr, int val, struct timespec *timeout, int mask )
93 return syscall( __NR_futex, addr, FUTEX_WAIT_BITSET | futex_private, val, timeout, 0, mask );
96 static inline int futex_wake_bitset( const int *addr, int val, int mask )
98 return syscall( __NR_futex, addr, FUTEX_WAKE_BITSET | futex_private, val, NULL, 0, mask );
101 static inline int use_futexes(void)
103 static int supported = -1;
105 if (supported == -1)
107 futex_wait( &supported, 10, NULL );
108 if (errno == ENOSYS)
110 futex_private = 0;
111 futex_wait( &supported, 10, NULL );
113 supported = (errno != ENOSYS);
115 return supported;
118 static void timespec_from_timeout( struct timespec *timespec, const LARGE_INTEGER *timeout )
120 LARGE_INTEGER now;
121 timeout_t diff;
123 if (timeout->QuadPart > 0)
125 NtQuerySystemTime( &now );
126 diff = timeout->QuadPart - now.QuadPart;
128 else
129 diff = -timeout->QuadPart;
131 timespec->tv_sec = diff / TICKSPERSEC;
132 timespec->tv_nsec = (diff % TICKSPERSEC) * 100;
134 #endif
136 /* creates a struct security_descriptor and contained information in one contiguous piece of memory */
137 NTSTATUS alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_attributes **ret,
138 data_size_t *ret_len )
140 unsigned int len = sizeof(**ret);
141 PSID owner = NULL, group = NULL;
142 ACL *dacl, *sacl;
143 BOOLEAN dacl_present, sacl_present, defaulted;
144 PSECURITY_DESCRIPTOR sd;
145 NTSTATUS status;
147 *ret = NULL;
148 *ret_len = 0;
150 if (!attr) return STATUS_SUCCESS;
152 if (attr->Length != sizeof(*attr)) return STATUS_INVALID_PARAMETER;
154 if ((sd = attr->SecurityDescriptor))
156 len += sizeof(struct security_descriptor);
158 if ((status = RtlGetOwnerSecurityDescriptor( sd, &owner, &defaulted ))) return status;
159 if ((status = RtlGetGroupSecurityDescriptor( sd, &group, &defaulted ))) return status;
160 if ((status = RtlGetSaclSecurityDescriptor( sd, &sacl_present, &sacl, &defaulted ))) return status;
161 if ((status = RtlGetDaclSecurityDescriptor( sd, &dacl_present, &dacl, &defaulted ))) return status;
162 if (owner) len += RtlLengthSid( owner );
163 if (group) len += RtlLengthSid( group );
164 if (sacl_present && sacl) len += sacl->AclSize;
165 if (dacl_present && dacl) len += dacl->AclSize;
167 /* fix alignment for the Unicode name that follows the structure */
168 len = (len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
171 if (attr->ObjectName)
173 if (attr->ObjectName->Length & (sizeof(WCHAR) - 1)) return STATUS_OBJECT_NAME_INVALID;
174 len += attr->ObjectName->Length;
176 else if (attr->RootDirectory) return STATUS_OBJECT_NAME_INVALID;
178 len = (len + 3) & ~3; /* DWORD-align the entire structure */
180 *ret = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, len );
181 if (!*ret) return STATUS_NO_MEMORY;
183 (*ret)->rootdir = wine_server_obj_handle( attr->RootDirectory );
184 (*ret)->attributes = attr->Attributes;
186 if (attr->SecurityDescriptor)
188 struct security_descriptor *descr = (struct security_descriptor *)(*ret + 1);
189 unsigned char *ptr = (unsigned char *)(descr + 1);
191 descr->control = ((SECURITY_DESCRIPTOR *)sd)->Control & ~SE_SELF_RELATIVE;
192 if (owner) descr->owner_len = RtlLengthSid( owner );
193 if (group) descr->group_len = RtlLengthSid( group );
194 if (sacl_present && sacl) descr->sacl_len = sacl->AclSize;
195 if (dacl_present && dacl) descr->dacl_len = dacl->AclSize;
197 memcpy( ptr, owner, descr->owner_len );
198 ptr += descr->owner_len;
199 memcpy( ptr, group, descr->group_len );
200 ptr += descr->group_len;
201 memcpy( ptr, sacl, descr->sacl_len );
202 ptr += descr->sacl_len;
203 memcpy( ptr, dacl, descr->dacl_len );
204 (*ret)->sd_len = (sizeof(*descr) + descr->owner_len + descr->group_len + descr->sacl_len +
205 descr->dacl_len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
208 if (attr->ObjectName)
210 unsigned char *ptr = (unsigned char *)(*ret + 1) + (*ret)->sd_len;
211 (*ret)->name_len = attr->ObjectName->Length;
212 memcpy( ptr, attr->ObjectName->Buffer, (*ret)->name_len );
215 *ret_len = len;
216 return STATUS_SUCCESS;
219 NTSTATUS validate_open_object_attributes( const OBJECT_ATTRIBUTES *attr )
221 if (!attr || attr->Length != sizeof(*attr)) return STATUS_INVALID_PARAMETER;
223 if (attr->ObjectName)
225 if (attr->ObjectName->Length & (sizeof(WCHAR) - 1)) return STATUS_OBJECT_NAME_INVALID;
227 else if (attr->RootDirectory) return STATUS_OBJECT_NAME_INVALID;
229 return STATUS_SUCCESS;
233 * Semaphores
236 /******************************************************************************
237 * NtCreateSemaphore (NTDLL.@)
239 NTSTATUS WINAPI NtCreateSemaphore( OUT PHANDLE SemaphoreHandle,
240 IN ACCESS_MASK access,
241 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
242 IN LONG InitialCount,
243 IN LONG MaximumCount )
245 NTSTATUS ret;
246 data_size_t len;
247 struct object_attributes *objattr;
249 if (MaximumCount <= 0 || InitialCount < 0 || InitialCount > MaximumCount)
250 return STATUS_INVALID_PARAMETER;
252 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
254 SERVER_START_REQ( create_semaphore )
256 req->access = access;
257 req->initial = InitialCount;
258 req->max = MaximumCount;
259 wine_server_add_data( req, objattr, len );
260 ret = wine_server_call( req );
261 *SemaphoreHandle = wine_server_ptr_handle( reply->handle );
263 SERVER_END_REQ;
265 RtlFreeHeap( GetProcessHeap(), 0, objattr );
266 return ret;
269 /******************************************************************************
270 * NtOpenSemaphore (NTDLL.@)
272 NTSTATUS WINAPI NtOpenSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
274 NTSTATUS ret;
276 if ((ret = validate_open_object_attributes( attr ))) return ret;
278 SERVER_START_REQ( open_semaphore )
280 req->access = access;
281 req->attributes = attr->Attributes;
282 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
283 if (attr->ObjectName)
284 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
285 ret = wine_server_call( req );
286 *handle = wine_server_ptr_handle( reply->handle );
288 SERVER_END_REQ;
289 return ret;
292 /******************************************************************************
293 * NtQuerySemaphore (NTDLL.@)
295 NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS class,
296 void *info, ULONG len, ULONG *ret_len )
298 NTSTATUS ret;
299 SEMAPHORE_BASIC_INFORMATION *out = info;
301 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, len, ret_len);
303 if (class != SemaphoreBasicInformation)
305 FIXME("(%p,%d,%u) Unknown class\n", handle, class, len);
306 return STATUS_INVALID_INFO_CLASS;
309 if (len != sizeof(SEMAPHORE_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
311 SERVER_START_REQ( query_semaphore )
313 req->handle = wine_server_obj_handle( handle );
314 if (!(ret = wine_server_call( req )))
316 out->CurrentCount = reply->current;
317 out->MaximumCount = reply->max;
318 if (ret_len) *ret_len = sizeof(SEMAPHORE_BASIC_INFORMATION);
321 SERVER_END_REQ;
323 return ret;
326 /******************************************************************************
327 * NtReleaseSemaphore (NTDLL.@)
329 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
331 NTSTATUS ret;
332 SERVER_START_REQ( release_semaphore )
334 req->handle = wine_server_obj_handle( handle );
335 req->count = count;
336 if (!(ret = wine_server_call( req )))
338 if (previous) *previous = reply->prev_count;
341 SERVER_END_REQ;
342 return ret;
346 * Events
349 /**************************************************************************
350 * NtCreateEvent (NTDLL.@)
351 * ZwCreateEvent (NTDLL.@)
353 NTSTATUS WINAPI NtCreateEvent( PHANDLE EventHandle, ACCESS_MASK DesiredAccess,
354 const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN InitialState)
356 NTSTATUS ret;
357 data_size_t len;
358 struct object_attributes *objattr;
360 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
362 SERVER_START_REQ( create_event )
364 req->access = DesiredAccess;
365 req->manual_reset = (type == NotificationEvent);
366 req->initial_state = InitialState;
367 wine_server_add_data( req, objattr, len );
368 ret = wine_server_call( req );
369 *EventHandle = wine_server_ptr_handle( reply->handle );
371 SERVER_END_REQ;
373 RtlFreeHeap( GetProcessHeap(), 0, objattr );
374 return ret;
377 /******************************************************************************
378 * NtOpenEvent (NTDLL.@)
379 * ZwOpenEvent (NTDLL.@)
381 NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
383 NTSTATUS ret;
385 if ((ret = validate_open_object_attributes( attr ))) return ret;
387 SERVER_START_REQ( open_event )
389 req->access = access;
390 req->attributes = attr->Attributes;
391 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
392 if (attr->ObjectName)
393 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
394 ret = wine_server_call( req );
395 *handle = wine_server_ptr_handle( reply->handle );
397 SERVER_END_REQ;
398 return ret;
402 /******************************************************************************
403 * NtSetEvent (NTDLL.@)
404 * ZwSetEvent (NTDLL.@)
406 NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state )
408 NTSTATUS ret;
409 SERVER_START_REQ( event_op )
411 req->handle = wine_server_obj_handle( handle );
412 req->op = SET_EVENT;
413 ret = wine_server_call( req );
414 if (!ret && prev_state) *prev_state = reply->state;
416 SERVER_END_REQ;
417 return ret;
420 /******************************************************************************
421 * NtResetEvent (NTDLL.@)
423 NTSTATUS WINAPI NtResetEvent( HANDLE handle, LONG *prev_state )
425 NTSTATUS ret;
426 SERVER_START_REQ( event_op )
428 req->handle = wine_server_obj_handle( handle );
429 req->op = RESET_EVENT;
430 ret = wine_server_call( req );
431 if (!ret && prev_state) *prev_state = reply->state;
433 SERVER_END_REQ;
434 return ret;
437 /******************************************************************************
438 * NtClearEvent (NTDLL.@)
440 * FIXME
441 * same as NtResetEvent ???
443 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
445 return NtResetEvent( handle, NULL );
448 /******************************************************************************
449 * NtPulseEvent (NTDLL.@)
451 * FIXME
452 * PulseCount
454 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, LONG *prev_state )
456 NTSTATUS ret;
458 SERVER_START_REQ( event_op )
460 req->handle = wine_server_obj_handle( handle );
461 req->op = PULSE_EVENT;
462 ret = wine_server_call( req );
463 if (!ret && prev_state) *prev_state = reply->state;
465 SERVER_END_REQ;
466 return ret;
469 /******************************************************************************
470 * NtQueryEvent (NTDLL.@)
472 NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class,
473 void *info, ULONG len, ULONG *ret_len )
475 NTSTATUS ret;
476 EVENT_BASIC_INFORMATION *out = info;
478 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, len, ret_len);
480 if (class != EventBasicInformation)
482 FIXME("(%p, %d, %d) Unknown class\n",
483 handle, class, len);
484 return STATUS_INVALID_INFO_CLASS;
487 if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
489 SERVER_START_REQ( query_event )
491 req->handle = wine_server_obj_handle( handle );
492 if (!(ret = wine_server_call( req )))
494 out->EventType = reply->manual_reset ? NotificationEvent : SynchronizationEvent;
495 out->EventState = reply->state;
496 if (ret_len) *ret_len = sizeof(EVENT_BASIC_INFORMATION);
499 SERVER_END_REQ;
501 return ret;
505 * Mutants (known as Mutexes in Kernel32)
508 /******************************************************************************
509 * NtCreateMutant [NTDLL.@]
510 * ZwCreateMutant [NTDLL.@]
512 NTSTATUS WINAPI NtCreateMutant(OUT HANDLE* MutantHandle,
513 IN ACCESS_MASK access,
514 IN const OBJECT_ATTRIBUTES* attr OPTIONAL,
515 IN BOOLEAN InitialOwner)
517 NTSTATUS status;
518 data_size_t len;
519 struct object_attributes *objattr;
521 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
523 SERVER_START_REQ( create_mutex )
525 req->access = access;
526 req->owned = InitialOwner;
527 wine_server_add_data( req, objattr, len );
528 status = wine_server_call( req );
529 *MutantHandle = wine_server_ptr_handle( reply->handle );
531 SERVER_END_REQ;
533 RtlFreeHeap( GetProcessHeap(), 0, objattr );
534 return status;
537 /**************************************************************************
538 * NtOpenMutant [NTDLL.@]
539 * ZwOpenMutant [NTDLL.@]
541 NTSTATUS WINAPI NtOpenMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
543 NTSTATUS status;
545 if ((status = validate_open_object_attributes( attr ))) return status;
547 SERVER_START_REQ( open_mutex )
549 req->access = access;
550 req->attributes = attr->Attributes;
551 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
552 if (attr->ObjectName)
553 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
554 status = wine_server_call( req );
555 *handle = wine_server_ptr_handle( reply->handle );
557 SERVER_END_REQ;
558 return status;
561 /**************************************************************************
562 * NtReleaseMutant [NTDLL.@]
563 * ZwReleaseMutant [NTDLL.@]
565 NTSTATUS WINAPI NtReleaseMutant( IN HANDLE handle, OUT PLONG prev_count OPTIONAL)
567 NTSTATUS status;
569 SERVER_START_REQ( release_mutex )
571 req->handle = wine_server_obj_handle( handle );
572 status = wine_server_call( req );
573 if (prev_count) *prev_count = 1 - reply->prev_count;
575 SERVER_END_REQ;
576 return status;
579 /******************************************************************
580 * NtQueryMutant [NTDLL.@]
581 * ZwQueryMutant [NTDLL.@]
583 NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class,
584 void *info, ULONG len, ULONG *ret_len )
586 NTSTATUS ret;
587 MUTANT_BASIC_INFORMATION *out = info;
589 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, len, ret_len);
591 if (class != MutantBasicInformation)
593 FIXME("(%p, %d, %d) Unknown class\n",
594 handle, class, len);
595 return STATUS_INVALID_INFO_CLASS;
598 if (len != sizeof(MUTANT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
600 SERVER_START_REQ( query_mutex )
602 req->handle = wine_server_obj_handle( handle );
603 if (!(ret = wine_server_call( req )))
605 out->CurrentCount = 1 - reply->count;
606 out->OwnedByCaller = reply->owned;
607 out->AbandonedState = reply->abandoned;
608 if (ret_len) *ret_len = sizeof(MUTANT_BASIC_INFORMATION);
611 SERVER_END_REQ;
613 return ret;
617 * Jobs
620 /******************************************************************************
621 * NtCreateJobObject [NTDLL.@]
622 * ZwCreateJobObject [NTDLL.@]
624 NTSTATUS WINAPI NtCreateJobObject( PHANDLE handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
626 NTSTATUS ret;
627 data_size_t len;
628 struct object_attributes *objattr;
630 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
632 SERVER_START_REQ( create_job )
634 req->access = access;
635 wine_server_add_data( req, objattr, len );
636 ret = wine_server_call( req );
637 *handle = wine_server_ptr_handle( reply->handle );
639 SERVER_END_REQ;
641 RtlFreeHeap( GetProcessHeap(), 0, objattr );
642 return ret;
645 /******************************************************************************
646 * NtOpenJobObject [NTDLL.@]
647 * ZwOpenJobObject [NTDLL.@]
649 NTSTATUS WINAPI NtOpenJobObject( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
651 NTSTATUS ret;
653 if ((ret = validate_open_object_attributes( attr ))) return ret;
655 SERVER_START_REQ( open_job )
657 req->access = access;
658 req->attributes = attr->Attributes;
659 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
660 if (attr->ObjectName)
661 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
662 ret = wine_server_call( req );
663 *handle = wine_server_ptr_handle( reply->handle );
665 SERVER_END_REQ;
666 return ret;
669 /******************************************************************************
670 * NtTerminateJobObject [NTDLL.@]
671 * ZwTerminateJobObject [NTDLL.@]
673 NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status )
675 NTSTATUS ret;
677 TRACE( "(%p, %d)\n", handle, status );
679 SERVER_START_REQ( terminate_job )
681 req->handle = wine_server_obj_handle( handle );
682 req->status = status;
683 ret = wine_server_call( req );
685 SERVER_END_REQ;
687 return ret;
690 /******************************************************************************
691 * NtQueryInformationJobObject [NTDLL.@]
692 * ZwQueryInformationJobObject [NTDLL.@]
694 NTSTATUS WINAPI NtQueryInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info,
695 ULONG len, PULONG ret_len )
697 FIXME( "stub: %p %u %p %u %p\n", handle, class, info, len, ret_len );
699 if (class >= MaxJobObjectInfoClass)
700 return STATUS_INVALID_PARAMETER;
702 switch (class)
704 case JobObjectBasicAccountingInformation:
706 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION *accounting;
707 if (len < sizeof(*accounting))
708 return STATUS_INFO_LENGTH_MISMATCH;
710 accounting = (JOBOBJECT_BASIC_ACCOUNTING_INFORMATION *)info;
711 memset(accounting, 0, sizeof(*accounting));
712 if (ret_len) *ret_len = sizeof(*accounting);
713 return STATUS_SUCCESS;
716 case JobObjectBasicProcessIdList:
718 JOBOBJECT_BASIC_PROCESS_ID_LIST *process;
719 if (len < sizeof(*process))
720 return STATUS_INFO_LENGTH_MISMATCH;
722 process = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)info;
723 memset(process, 0, sizeof(*process));
724 if (ret_len) *ret_len = sizeof(*process);
725 return STATUS_SUCCESS;
728 case JobObjectExtendedLimitInformation:
730 JOBOBJECT_EXTENDED_LIMIT_INFORMATION *extended_limit;
731 if (len < sizeof(*extended_limit))
732 return STATUS_INFO_LENGTH_MISMATCH;
734 extended_limit = (JOBOBJECT_EXTENDED_LIMIT_INFORMATION *)info;
735 memset(extended_limit, 0, sizeof(*extended_limit));
736 if (ret_len) *ret_len = sizeof(*extended_limit);
737 return STATUS_SUCCESS;
740 case JobObjectBasicLimitInformation:
742 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit;
743 if (len < sizeof(*basic_limit))
744 return STATUS_INFO_LENGTH_MISMATCH;
746 basic_limit = (JOBOBJECT_BASIC_LIMIT_INFORMATION *)info;
747 memset(basic_limit, 0, sizeof(*basic_limit));
748 if (ret_len) *ret_len = sizeof(*basic_limit);
749 return STATUS_SUCCESS;
752 default:
753 return STATUS_NOT_IMPLEMENTED;
757 /******************************************************************************
758 * NtSetInformationJobObject [NTDLL.@]
759 * ZwSetInformationJobObject [NTDLL.@]
761 NTSTATUS WINAPI NtSetInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info, ULONG len )
763 NTSTATUS status = STATUS_NOT_IMPLEMENTED;
764 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit;
765 ULONG info_size = sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION);
766 DWORD limit_flags = JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS;
768 TRACE( "(%p, %u, %p, %u)\n", handle, class, info, len );
770 if (class >= MaxJobObjectInfoClass)
771 return STATUS_INVALID_PARAMETER;
773 switch (class)
776 case JobObjectExtendedLimitInformation:
777 info_size = sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION);
778 limit_flags = JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS;
779 /* fallthrough */
780 case JobObjectBasicLimitInformation:
781 if (len != info_size)
782 return STATUS_INVALID_PARAMETER;
784 basic_limit = info;
785 if (basic_limit->LimitFlags & ~limit_flags)
786 return STATUS_INVALID_PARAMETER;
788 SERVER_START_REQ( set_job_limits )
790 req->handle = wine_server_obj_handle( handle );
791 req->limit_flags = basic_limit->LimitFlags;
792 status = wine_server_call( req );
794 SERVER_END_REQ;
795 break;
797 case JobObjectAssociateCompletionPortInformation:
798 if (len != sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT))
799 return STATUS_INVALID_PARAMETER;
801 SERVER_START_REQ( set_job_completion_port )
803 JOBOBJECT_ASSOCIATE_COMPLETION_PORT *port_info = info;
804 req->job = wine_server_obj_handle( handle );
805 req->port = wine_server_obj_handle( port_info->CompletionPort );
806 req->key = wine_server_client_ptr( port_info->CompletionKey );
807 status = wine_server_call(req);
809 SERVER_END_REQ;
810 break;
812 case JobObjectBasicUIRestrictions:
813 status = STATUS_SUCCESS;
814 /* fallthrough */
815 default:
816 FIXME( "stub: %p %u %p %u\n", handle, class, info, len );
819 return status;
822 /******************************************************************************
823 * NtIsProcessInJob [NTDLL.@]
824 * ZwIsProcessInJob [NTDLL.@]
826 NTSTATUS WINAPI NtIsProcessInJob( HANDLE process, HANDLE job )
828 NTSTATUS status;
830 TRACE( "(%p %p)\n", job, process );
832 SERVER_START_REQ( process_in_job )
834 req->job = wine_server_obj_handle( job );
835 req->process = wine_server_obj_handle( process );
836 status = wine_server_call( req );
838 SERVER_END_REQ;
840 return status;
843 /******************************************************************************
844 * NtAssignProcessToJobObject [NTDLL.@]
845 * ZwAssignProcessToJobObject [NTDLL.@]
847 NTSTATUS WINAPI NtAssignProcessToJobObject( HANDLE job, HANDLE process )
849 NTSTATUS status;
851 TRACE( "(%p %p)\n", job, process );
853 SERVER_START_REQ( assign_job )
855 req->job = wine_server_obj_handle( job );
856 req->process = wine_server_obj_handle( process );
857 status = wine_server_call( req );
859 SERVER_END_REQ;
861 return status;
865 * Timers
868 /**************************************************************************
869 * NtCreateTimer [NTDLL.@]
870 * ZwCreateTimer [NTDLL.@]
872 NTSTATUS WINAPI NtCreateTimer(OUT HANDLE *handle,
873 IN ACCESS_MASK access,
874 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
875 IN TIMER_TYPE timer_type)
877 NTSTATUS status;
878 data_size_t len;
879 struct object_attributes *objattr;
881 if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
882 return STATUS_INVALID_PARAMETER;
884 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
886 SERVER_START_REQ( create_timer )
888 req->access = access;
889 req->manual = (timer_type == NotificationTimer);
890 wine_server_add_data( req, objattr, len );
891 status = wine_server_call( req );
892 *handle = wine_server_ptr_handle( reply->handle );
894 SERVER_END_REQ;
896 RtlFreeHeap( GetProcessHeap(), 0, objattr );
897 return status;
901 /**************************************************************************
902 * NtOpenTimer [NTDLL.@]
903 * ZwOpenTimer [NTDLL.@]
905 NTSTATUS WINAPI NtOpenTimer( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
907 NTSTATUS status;
909 if ((status = validate_open_object_attributes( attr ))) return status;
911 SERVER_START_REQ( open_timer )
913 req->access = access;
914 req->attributes = attr->Attributes;
915 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
916 if (attr->ObjectName)
917 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
918 status = wine_server_call( req );
919 *handle = wine_server_ptr_handle( reply->handle );
921 SERVER_END_REQ;
922 return status;
925 /**************************************************************************
926 * NtSetTimer [NTDLL.@]
927 * ZwSetTimer [NTDLL.@]
929 NTSTATUS WINAPI NtSetTimer(IN HANDLE handle,
930 IN const LARGE_INTEGER* when,
931 IN PTIMER_APC_ROUTINE callback,
932 IN PVOID callback_arg,
933 IN BOOLEAN resume,
934 IN ULONG period OPTIONAL,
935 OUT PBOOLEAN state OPTIONAL)
937 NTSTATUS status = STATUS_SUCCESS;
939 TRACE("(%p,%p,%p,%p,%08x,0x%08x,%p)\n",
940 handle, when, callback, callback_arg, resume, period, state);
942 SERVER_START_REQ( set_timer )
944 req->handle = wine_server_obj_handle( handle );
945 req->period = period;
946 req->expire = when->QuadPart;
947 req->callback = wine_server_client_ptr( callback );
948 req->arg = wine_server_client_ptr( callback_arg );
949 status = wine_server_call( req );
950 if (state) *state = reply->signaled;
952 SERVER_END_REQ;
954 /* set error but can still succeed */
955 if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
956 return status;
959 /**************************************************************************
960 * NtCancelTimer [NTDLL.@]
961 * ZwCancelTimer [NTDLL.@]
963 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
965 NTSTATUS status;
967 SERVER_START_REQ( cancel_timer )
969 req->handle = wine_server_obj_handle( handle );
970 status = wine_server_call( req );
971 if (state) *state = reply->signaled;
973 SERVER_END_REQ;
974 return status;
977 /******************************************************************************
978 * NtQueryTimer (NTDLL.@)
980 * Retrieves information about a timer.
982 * PARAMS
983 * TimerHandle [I] The timer to retrieve information about.
984 * TimerInformationClass [I] The type of information to retrieve.
985 * TimerInformation [O] Pointer to buffer to store information in.
986 * Length [I] The length of the buffer pointed to by TimerInformation.
987 * ReturnLength [O] Optional. The size of buffer actually used.
989 * RETURNS
990 * Success: STATUS_SUCCESS
991 * Failure: STATUS_INFO_LENGTH_MISMATCH, if Length doesn't match the required data
992 * size for the class specified.
993 * STATUS_INVALID_INFO_CLASS, if an invalid TimerInformationClass was specified.
994 * STATUS_ACCESS_DENIED, if TimerHandle does not have TIMER_QUERY_STATE access
995 * to the timer.
997 NTSTATUS WINAPI NtQueryTimer(
998 HANDLE TimerHandle,
999 TIMER_INFORMATION_CLASS TimerInformationClass,
1000 PVOID TimerInformation,
1001 ULONG Length,
1002 PULONG ReturnLength)
1004 TIMER_BASIC_INFORMATION * basic_info = TimerInformation;
1005 NTSTATUS status;
1006 LARGE_INTEGER now;
1008 TRACE("(%p,%d,%p,0x%08x,%p)\n", TimerHandle, TimerInformationClass,
1009 TimerInformation, Length, ReturnLength);
1011 switch (TimerInformationClass)
1013 case TimerBasicInformation:
1014 if (Length < sizeof(TIMER_BASIC_INFORMATION))
1015 return STATUS_INFO_LENGTH_MISMATCH;
1017 SERVER_START_REQ(get_timer_info)
1019 req->handle = wine_server_obj_handle( TimerHandle );
1020 status = wine_server_call(req);
1022 /* convert server time to absolute NTDLL time */
1023 basic_info->RemainingTime.QuadPart = reply->when;
1024 basic_info->TimerState = reply->signaled;
1026 SERVER_END_REQ;
1028 /* convert from absolute into relative time */
1029 NtQuerySystemTime(&now);
1030 if (now.QuadPart > basic_info->RemainingTime.QuadPart)
1031 basic_info->RemainingTime.QuadPart = 0;
1032 else
1033 basic_info->RemainingTime.QuadPart -= now.QuadPart;
1035 if (ReturnLength) *ReturnLength = sizeof(TIMER_BASIC_INFORMATION);
1037 return status;
1040 FIXME("Unhandled class %d\n", TimerInformationClass);
1041 return STATUS_INVALID_INFO_CLASS;
1045 /******************************************************************************
1046 * NtQueryTimerResolution [NTDLL.@]
1048 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
1049 OUT ULONG* max_resolution,
1050 OUT ULONG* current_resolution)
1052 FIXME("(%p,%p,%p), stub!\n",
1053 min_resolution, max_resolution, current_resolution);
1055 return STATUS_NOT_IMPLEMENTED;
1058 /******************************************************************************
1059 * NtSetTimerResolution [NTDLL.@]
1061 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
1062 IN BOOLEAN set_resolution,
1063 OUT ULONG* current_resolution )
1065 FIXME("(%u,%u,%p), stub!\n",
1066 resolution, set_resolution, current_resolution);
1068 return STATUS_NOT_IMPLEMENTED;
1073 /* wait operations */
1075 static NTSTATUS wait_objects( DWORD count, const HANDLE *handles,
1076 BOOLEAN wait_any, BOOLEAN alertable,
1077 const LARGE_INTEGER *timeout )
1079 select_op_t select_op;
1080 UINT i, flags = SELECT_INTERRUPTIBLE;
1082 if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
1084 if (alertable) flags |= SELECT_ALERTABLE;
1085 select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL;
1086 for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] );
1087 return server_select( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout );
1091 /******************************************************************
1092 * NtWaitForMultipleObjects (NTDLL.@)
1094 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
1095 BOOLEAN wait_any, BOOLEAN alertable,
1096 const LARGE_INTEGER *timeout )
1098 return wait_objects( count, handles, wait_any, alertable, timeout );
1102 /******************************************************************
1103 * NtWaitForSingleObject (NTDLL.@)
1105 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
1107 return wait_objects( 1, &handle, FALSE, alertable, timeout );
1111 /******************************************************************
1112 * NtSignalAndWaitForSingleObject (NTDLL.@)
1114 NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE hSignalObject, HANDLE hWaitObject,
1115 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1117 select_op_t select_op;
1118 UINT flags = SELECT_INTERRUPTIBLE;
1120 if (!hSignalObject) return STATUS_INVALID_HANDLE;
1122 if (alertable) flags |= SELECT_ALERTABLE;
1123 select_op.signal_and_wait.op = SELECT_SIGNAL_AND_WAIT;
1124 select_op.signal_and_wait.wait = wine_server_obj_handle( hWaitObject );
1125 select_op.signal_and_wait.signal = wine_server_obj_handle( hSignalObject );
1126 return server_select( &select_op, sizeof(select_op.signal_and_wait), flags, timeout );
1130 /******************************************************************
1131 * NtYieldExecution (NTDLL.@)
1133 NTSTATUS WINAPI NtYieldExecution(void)
1135 #ifdef HAVE_SCHED_YIELD
1136 sched_yield();
1137 return STATUS_SUCCESS;
1138 #else
1139 return STATUS_NO_YIELD_PERFORMED;
1140 #endif
1144 /******************************************************************
1145 * NtDelayExecution (NTDLL.@)
1147 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
1149 /* if alertable, we need to query the server */
1150 if (alertable)
1151 return server_select( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout );
1153 if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */
1155 for (;;) select( 0, NULL, NULL, NULL, NULL );
1157 else
1159 LARGE_INTEGER now;
1160 timeout_t when, diff;
1162 if ((when = timeout->QuadPart) < 0)
1164 NtQuerySystemTime( &now );
1165 when = now.QuadPart - when;
1168 /* Note that we yield after establishing the desired timeout */
1169 NtYieldExecution();
1170 if (!when) return STATUS_SUCCESS;
1172 for (;;)
1174 struct timeval tv;
1175 NtQuerySystemTime( &now );
1176 diff = (when - now.QuadPart + 9) / 10;
1177 if (diff <= 0) break;
1178 tv.tv_sec = diff / 1000000;
1179 tv.tv_usec = diff % 1000000;
1180 if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
1183 return STATUS_SUCCESS;
1187 /******************************************************************************
1188 * NtCreateKeyedEvent (NTDLL.@)
1190 NTSTATUS WINAPI NtCreateKeyedEvent( HANDLE *handle, ACCESS_MASK access,
1191 const OBJECT_ATTRIBUTES *attr, ULONG flags )
1193 NTSTATUS ret;
1194 data_size_t len;
1195 struct object_attributes *objattr;
1197 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1199 SERVER_START_REQ( create_keyed_event )
1201 req->access = access;
1202 wine_server_add_data( req, objattr, len );
1203 ret = wine_server_call( req );
1204 *handle = wine_server_ptr_handle( reply->handle );
1206 SERVER_END_REQ;
1208 RtlFreeHeap( GetProcessHeap(), 0, objattr );
1209 return ret;
1212 /******************************************************************************
1213 * NtOpenKeyedEvent (NTDLL.@)
1215 NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1217 NTSTATUS ret;
1219 if ((ret = validate_open_object_attributes( attr ))) return ret;
1221 SERVER_START_REQ( open_keyed_event )
1223 req->access = access;
1224 req->attributes = attr->Attributes;
1225 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1226 if (attr->ObjectName)
1227 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1228 ret = wine_server_call( req );
1229 *handle = wine_server_ptr_handle( reply->handle );
1231 SERVER_END_REQ;
1232 return ret;
1235 /******************************************************************************
1236 * NtWaitForKeyedEvent (NTDLL.@)
1238 NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
1239 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1241 select_op_t select_op;
1242 UINT flags = SELECT_INTERRUPTIBLE;
1244 if (!handle) handle = keyed_event;
1245 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1246 if (alertable) flags |= SELECT_ALERTABLE;
1247 select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT;
1248 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1249 select_op.keyed_event.key = wine_server_client_ptr( key );
1250 return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1253 /******************************************************************************
1254 * NtReleaseKeyedEvent (NTDLL.@)
1256 NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key,
1257 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1259 select_op_t select_op;
1260 UINT flags = SELECT_INTERRUPTIBLE;
1262 if (!handle) handle = keyed_event;
1263 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1264 if (alertable) flags |= SELECT_ALERTABLE;
1265 select_op.keyed_event.op = SELECT_KEYED_EVENT_RELEASE;
1266 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1267 select_op.keyed_event.key = wine_server_client_ptr( key );
1268 return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1271 /******************************************************************
1272 * NtCreateIoCompletion (NTDLL.@)
1273 * ZwCreateIoCompletion (NTDLL.@)
1275 * Creates I/O completion object.
1277 * PARAMS
1278 * CompletionPort [O] created completion object handle will be placed there
1279 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1280 * ObjectAttributes [I] completion object attributes
1281 * NumberOfConcurrentThreads [I] desired number of concurrent active worker threads
1284 NTSTATUS WINAPI NtCreateIoCompletion( PHANDLE CompletionPort, ACCESS_MASK DesiredAccess,
1285 POBJECT_ATTRIBUTES attr, ULONG NumberOfConcurrentThreads )
1287 NTSTATUS status;
1288 data_size_t len;
1289 struct object_attributes *objattr;
1291 TRACE("(%p, %x, %p, %d)\n", CompletionPort, DesiredAccess, attr, NumberOfConcurrentThreads);
1293 if (!CompletionPort)
1294 return STATUS_INVALID_PARAMETER;
1296 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
1298 SERVER_START_REQ( create_completion )
1300 req->access = DesiredAccess;
1301 req->concurrent = NumberOfConcurrentThreads;
1302 wine_server_add_data( req, objattr, len );
1303 if (!(status = wine_server_call( req )))
1304 *CompletionPort = wine_server_ptr_handle( reply->handle );
1306 SERVER_END_REQ;
1308 RtlFreeHeap( GetProcessHeap(), 0, objattr );
1309 return status;
1312 /******************************************************************
1313 * NtSetIoCompletion (NTDLL.@)
1314 * ZwSetIoCompletion (NTDLL.@)
1316 * Inserts completion message into queue
1318 * PARAMS
1319 * CompletionPort [I] HANDLE to completion object
1320 * CompletionKey [I] completion key
1321 * CompletionValue [I] completion value (usually pointer to OVERLAPPED)
1322 * Status [I] operation status
1323 * NumberOfBytesTransferred [I] number of bytes transferred
1325 NTSTATUS WINAPI NtSetIoCompletion( HANDLE CompletionPort, ULONG_PTR CompletionKey,
1326 ULONG_PTR CompletionValue, NTSTATUS Status,
1327 SIZE_T NumberOfBytesTransferred )
1329 NTSTATUS status;
1331 TRACE("(%p, %lx, %lx, %x, %lx)\n", CompletionPort, CompletionKey,
1332 CompletionValue, Status, NumberOfBytesTransferred);
1334 SERVER_START_REQ( add_completion )
1336 req->handle = wine_server_obj_handle( CompletionPort );
1337 req->ckey = CompletionKey;
1338 req->cvalue = CompletionValue;
1339 req->status = Status;
1340 req->information = NumberOfBytesTransferred;
1341 status = wine_server_call( req );
1343 SERVER_END_REQ;
1344 return status;
1347 /******************************************************************
1348 * NtRemoveIoCompletion (NTDLL.@)
1349 * ZwRemoveIoCompletion (NTDLL.@)
1351 * (Wait for and) retrieve first completion message from completion object's queue
1353 * PARAMS
1354 * CompletionPort [I] HANDLE to I/O completion object
1355 * CompletionKey [O] completion key
1356 * CompletionValue [O] Completion value given in NtSetIoCompletion or in async operation
1357 * iosb [O] IO_STATUS_BLOCK of completed asynchronous operation
1358 * WaitTime [I] optional wait time in NTDLL format
1361 NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE CompletionPort, PULONG_PTR CompletionKey,
1362 PULONG_PTR CompletionValue, PIO_STATUS_BLOCK iosb,
1363 PLARGE_INTEGER WaitTime )
1365 NTSTATUS status;
1367 TRACE("(%p, %p, %p, %p, %p)\n", CompletionPort, CompletionKey,
1368 CompletionValue, iosb, WaitTime);
1370 for(;;)
1372 SERVER_START_REQ( remove_completion )
1374 req->handle = wine_server_obj_handle( CompletionPort );
1375 if (!(status = wine_server_call( req )))
1377 *CompletionKey = reply->ckey;
1378 *CompletionValue = reply->cvalue;
1379 iosb->Information = reply->information;
1380 iosb->u.Status = reply->status;
1383 SERVER_END_REQ;
1384 if (status != STATUS_PENDING) break;
1386 status = NtWaitForSingleObject( CompletionPort, FALSE, WaitTime );
1387 if (status != WAIT_OBJECT_0) break;
1389 return status;
1392 /******************************************************************
1393 * NtRemoveIoCompletionEx (NTDLL.@)
1394 * ZwRemoveIoCompletionEx (NTDLL.@)
1396 NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE port, FILE_IO_COMPLETION_INFORMATION *info, ULONG count,
1397 ULONG *written, LARGE_INTEGER *timeout, BOOLEAN alertable )
1399 NTSTATUS ret;
1400 ULONG i = 0;
1402 TRACE("%p %p %u %p %p %u\n", port, info, count, written, timeout, alertable);
1404 for (;;)
1406 while (i < count)
1408 SERVER_START_REQ( remove_completion )
1410 req->handle = wine_server_obj_handle( port );
1411 if (!(ret = wine_server_call( req )))
1413 info[i].CompletionKey = reply->ckey;
1414 info[i].CompletionValue = reply->cvalue;
1415 info[i].IoStatusBlock.Information = reply->information;
1416 info[i].IoStatusBlock.u.Status = reply->status;
1419 SERVER_END_REQ;
1421 if (ret != STATUS_SUCCESS) break;
1423 ++i;
1426 if (i || ret != STATUS_PENDING)
1428 if (ret == STATUS_PENDING)
1429 ret = STATUS_SUCCESS;
1430 break;
1433 ret = NtWaitForSingleObject( port, alertable, timeout );
1434 if (ret != WAIT_OBJECT_0) break;
1437 *written = i ? i : 1;
1438 return ret;
1441 /******************************************************************
1442 * NtOpenIoCompletion (NTDLL.@)
1443 * ZwOpenIoCompletion (NTDLL.@)
1445 * Opens I/O completion object
1447 * PARAMS
1448 * CompletionPort [O] completion object handle will be placed there
1449 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1450 * ObjectAttributes [I] completion object name
1453 NTSTATUS WINAPI NtOpenIoCompletion( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1455 NTSTATUS status;
1457 if (!handle) return STATUS_INVALID_PARAMETER;
1458 if ((status = validate_open_object_attributes( attr ))) return status;
1460 SERVER_START_REQ( open_completion )
1462 req->access = access;
1463 req->attributes = attr->Attributes;
1464 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1465 if (attr->ObjectName)
1466 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1467 status = wine_server_call( req );
1468 *handle = wine_server_ptr_handle( reply->handle );
1470 SERVER_END_REQ;
1471 return status;
1474 /******************************************************************
1475 * NtQueryIoCompletion (NTDLL.@)
1476 * ZwQueryIoCompletion (NTDLL.@)
1478 * Requests information about given I/O completion object
1480 * PARAMS
1481 * CompletionPort [I] HANDLE to completion port to request
1482 * InformationClass [I] information class
1483 * CompletionInformation [O] user-provided buffer for data
1484 * BufferLength [I] buffer length
1485 * RequiredLength [O] required buffer length
1488 NTSTATUS WINAPI NtQueryIoCompletion( HANDLE CompletionPort, IO_COMPLETION_INFORMATION_CLASS InformationClass,
1489 PVOID CompletionInformation, ULONG BufferLength, PULONG RequiredLength )
1491 NTSTATUS status;
1493 TRACE("(%p, %d, %p, 0x%x, %p)\n", CompletionPort, InformationClass, CompletionInformation,
1494 BufferLength, RequiredLength);
1496 if (!CompletionInformation) return STATUS_INVALID_PARAMETER;
1497 switch( InformationClass )
1499 case IoCompletionBasicInformation:
1501 ULONG *info = CompletionInformation;
1503 if (RequiredLength) *RequiredLength = sizeof(*info);
1504 if (BufferLength != sizeof(*info))
1505 status = STATUS_INFO_LENGTH_MISMATCH;
1506 else
1508 SERVER_START_REQ( query_completion )
1510 req->handle = wine_server_obj_handle( CompletionPort );
1511 if (!(status = wine_server_call( req )))
1512 *info = reply->depth;
1514 SERVER_END_REQ;
1517 break;
1518 default:
1519 status = STATUS_INVALID_PARAMETER;
1520 break;
1522 return status;
1525 NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue,
1526 NTSTATUS CompletionStatus, ULONG Information, BOOL async )
1528 NTSTATUS status;
1530 SERVER_START_REQ( add_fd_completion )
1532 req->handle = wine_server_obj_handle( hFile );
1533 req->cvalue = CompletionValue;
1534 req->status = CompletionStatus;
1535 req->information = Information;
1536 req->async = async;
1537 status = wine_server_call( req );
1539 SERVER_END_REQ;
1540 return status;
1543 /******************************************************************
1544 * RtlRunOnceInitialize (NTDLL.@)
1546 void WINAPI RtlRunOnceInitialize( RTL_RUN_ONCE *once )
1548 once->Ptr = NULL;
1551 /******************************************************************
1552 * RtlRunOnceBeginInitialize (NTDLL.@)
1554 DWORD WINAPI RtlRunOnceBeginInitialize( RTL_RUN_ONCE *once, ULONG flags, void **context )
1556 if (flags & RTL_RUN_ONCE_CHECK_ONLY)
1558 ULONG_PTR val = (ULONG_PTR)once->Ptr;
1560 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1561 if ((val & 3) != 2) return STATUS_UNSUCCESSFUL;
1562 if (context) *context = (void *)(val & ~3);
1563 return STATUS_SUCCESS;
1566 for (;;)
1568 ULONG_PTR next, val = (ULONG_PTR)once->Ptr;
1570 switch (val & 3)
1572 case 0: /* first time */
1573 if (!interlocked_cmpxchg_ptr( &once->Ptr,
1574 (flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0 ))
1575 return STATUS_PENDING;
1576 break;
1578 case 1: /* in progress, wait */
1579 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1580 next = val & ~3;
1581 if (interlocked_cmpxchg_ptr( &once->Ptr, (void *)((ULONG_PTR)&next | 1),
1582 (void *)val ) == (void *)val)
1583 NtWaitForKeyedEvent( 0, &next, FALSE, NULL );
1584 break;
1586 case 2: /* done */
1587 if (context) *context = (void *)(val & ~3);
1588 return STATUS_SUCCESS;
1590 case 3: /* in progress, async */
1591 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
1592 return STATUS_PENDING;
1597 /******************************************************************
1598 * RtlRunOnceComplete (NTDLL.@)
1600 DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context )
1602 if ((ULONG_PTR)context & 3) return STATUS_INVALID_PARAMETER;
1604 if (flags & RTL_RUN_ONCE_INIT_FAILED)
1606 if (context) return STATUS_INVALID_PARAMETER;
1607 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1609 else context = (void *)((ULONG_PTR)context | 2);
1611 for (;;)
1613 ULONG_PTR val = (ULONG_PTR)once->Ptr;
1615 switch (val & 3)
1617 case 1: /* in progress */
1618 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break;
1619 val &= ~3;
1620 while (val)
1622 ULONG_PTR next = *(ULONG_PTR *)val;
1623 NtReleaseKeyedEvent( 0, (void *)val, FALSE, NULL );
1624 val = next;
1626 return STATUS_SUCCESS;
1628 case 3: /* in progress, async */
1629 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
1630 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break;
1631 return STATUS_SUCCESS;
1633 default:
1634 return STATUS_UNSUCCESSFUL;
1639 /******************************************************************
1640 * RtlRunOnceExecuteOnce (NTDLL.@)
1642 DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN func,
1643 void *param, void **context )
1645 DWORD ret = RtlRunOnceBeginInitialize( once, 0, context );
1647 if (ret != STATUS_PENDING) return ret;
1649 if (!func( once, param, context ))
1651 RtlRunOnceComplete( once, RTL_RUN_ONCE_INIT_FAILED, NULL );
1652 return STATUS_UNSUCCESSFUL;
1655 return RtlRunOnceComplete( once, 0, context ? *context : NULL );
1658 #ifdef __linux__
1660 /* Futex-based SRW lock implementation:
1662 * Since we can rely on the kernel to release all threads and don't need to
1663 * worry about NtReleaseKeyedEvent(), we can simplify the layout a bit. The
1664 * layout looks like this:
1666 * 31 - Exclusive lock bit, set if the resource is owned exclusively.
1667 * 30-16 - Number of exclusive waiters. Unlike the fallback implementation,
1668 * this does not include the thread owning the lock, or shared threads
1669 * waiting on the lock.
1670 * 15 - Does this lock have any shared waiters? We use this as an
1671 * optimization to avoid unnecessary FUTEX_WAKE_BITSET calls when
1672 * releasing an exclusive lock.
1673 * 14-0 - Number of shared owners. Unlike the fallback implementation, this
1674 * does not include the number of shared threads waiting on the lock.
1675 * Thus the state [1, x, >=1] will never occur.
1678 #define SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT 0x80000000
1679 #define SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK 0x7fff0000
1680 #define SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC 0x00010000
1681 #define SRWLOCK_FUTEX_SHARED_WAITERS_BIT 0x00008000
1682 #define SRWLOCK_FUTEX_SHARED_OWNERS_MASK 0x00007fff
1683 #define SRWLOCK_FUTEX_SHARED_OWNERS_INC 0x00000001
1685 /* Futex bitmasks; these are independent from the bits in the lock itself. */
1686 #define SRWLOCK_FUTEX_BITSET_EXCLUSIVE 1
1687 #define SRWLOCK_FUTEX_BITSET_SHARED 2
1689 static NTSTATUS fast_try_acquire_srw_exclusive( RTL_SRWLOCK *lock )
1691 int old, new;
1692 NTSTATUS ret;
1694 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
1698 old = *(int *)lock;
1700 if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
1701 && !(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK))
1703 /* Not locked exclusive or shared. We can try to grab it. */
1704 new = old | SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT;
1705 ret = STATUS_SUCCESS;
1707 else
1709 new = old;
1710 ret = STATUS_TIMEOUT;
1712 } while (interlocked_cmpxchg( (int *)lock, new, old ) != old);
1714 return ret;
1717 static NTSTATUS fast_acquire_srw_exclusive( RTL_SRWLOCK *lock )
1719 int old, new;
1720 BOOLEAN wait;
1722 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
1724 /* Atomically increment the exclusive waiter count. */
1727 old = *(int *)lock;
1728 new = old + SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC;
1729 assert(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK);
1730 } while (interlocked_cmpxchg( (int *)lock, new, old ) != old);
1732 for (;;)
1736 old = *(int *)lock;
1738 if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
1739 && !(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK))
1741 /* Not locked exclusive or shared. We can try to grab it. */
1742 new = old | SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT;
1743 assert(old & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK);
1744 new -= SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC;
1745 wait = FALSE;
1747 else
1749 new = old;
1750 wait = TRUE;
1752 } while (interlocked_cmpxchg( (int *)lock, new, old ) != old);
1754 if (!wait)
1755 return STATUS_SUCCESS;
1757 futex_wait_bitset( (int *)lock, new, NULL, SRWLOCK_FUTEX_BITSET_EXCLUSIVE );
1760 return STATUS_SUCCESS;
1763 static NTSTATUS fast_try_acquire_srw_shared( RTL_SRWLOCK *lock )
1765 int new, old;
1766 NTSTATUS ret;
1768 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
1772 old = *(int *)lock;
1774 if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
1775 && !(old & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
1777 /* Not locked exclusive, and no exclusive waiters. We can try to
1778 * grab it. */
1779 new = old + SRWLOCK_FUTEX_SHARED_OWNERS_INC;
1780 assert(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK);
1781 ret = STATUS_SUCCESS;
1783 else
1785 new = old;
1786 ret = STATUS_TIMEOUT;
1788 } while (interlocked_cmpxchg( (int *)lock, new, old ) != old);
1790 return ret;
1793 static NTSTATUS fast_acquire_srw_shared( RTL_SRWLOCK *lock )
1795 int old, new;
1796 BOOLEAN wait;
1798 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
1800 for (;;)
1804 old = *(int *)lock;
1806 if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
1807 && !(old & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
1809 /* Not locked exclusive, and no exclusive waiters. We can try
1810 * to grab it. */
1811 new = old + SRWLOCK_FUTEX_SHARED_OWNERS_INC;
1812 assert(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK);
1813 wait = FALSE;
1815 else
1817 new = old | SRWLOCK_FUTEX_SHARED_WAITERS_BIT;
1818 wait = TRUE;
1820 } while (interlocked_cmpxchg( (int *)lock, new, old ) != old);
1822 if (!wait)
1823 return STATUS_SUCCESS;
1825 futex_wait_bitset( (int *)lock, new, NULL, SRWLOCK_FUTEX_BITSET_SHARED );
1828 return STATUS_SUCCESS;
1831 static NTSTATUS fast_release_srw_exclusive( RTL_SRWLOCK *lock )
1833 int old, new;
1835 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
1839 old = *(int *)lock;
1841 if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT))
1843 ERR("Lock %p is not owned exclusive! (%#x)\n", lock, *(int *)lock);
1844 return STATUS_RESOURCE_NOT_OWNED;
1847 new = old & ~SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT;
1849 if (!(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
1850 new &= ~SRWLOCK_FUTEX_SHARED_WAITERS_BIT;
1851 } while (interlocked_cmpxchg( (int *)lock, new, old ) != old);
1853 if (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK)
1854 futex_wake_bitset( (int *)lock, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE );
1855 else if (old & SRWLOCK_FUTEX_SHARED_WAITERS_BIT)
1856 futex_wake_bitset( (int *)lock, INT_MAX, SRWLOCK_FUTEX_BITSET_SHARED );
1858 return STATUS_SUCCESS;
1861 static NTSTATUS fast_release_srw_shared( RTL_SRWLOCK *lock )
1863 int old, new;
1865 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
1869 old = *(int *)lock;
1871 if (old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
1873 ERR("Lock %p is owned exclusive! (%#x)\n", lock, *(int *)lock);
1874 return STATUS_RESOURCE_NOT_OWNED;
1876 else if (!(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK))
1878 ERR("Lock %p is not owned shared! (%#x)\n", lock, *(int *)lock);
1879 return STATUS_RESOURCE_NOT_OWNED;
1882 new = old - SRWLOCK_FUTEX_SHARED_OWNERS_INC;
1883 } while (interlocked_cmpxchg( (int *)lock, new, old ) != old);
1885 /* Optimization: only bother waking if there are actually exclusive waiters. */
1886 if (!(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK) && (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
1887 futex_wake_bitset( (int *)lock, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE );
1889 return STATUS_SUCCESS;
1892 #else
1894 static NTSTATUS fast_try_acquire_srw_exclusive( RTL_SRWLOCK *lock )
1896 return STATUS_NOT_IMPLEMENTED;
1899 static NTSTATUS fast_acquire_srw_exclusive( RTL_SRWLOCK *lock )
1901 return STATUS_NOT_IMPLEMENTED;
1904 static NTSTATUS fast_try_acquire_srw_shared( RTL_SRWLOCK *lock )
1906 return STATUS_NOT_IMPLEMENTED;
1909 static NTSTATUS fast_acquire_srw_shared( RTL_SRWLOCK *lock )
1911 return STATUS_NOT_IMPLEMENTED;
1914 static NTSTATUS fast_release_srw_exclusive( RTL_SRWLOCK *lock )
1916 return STATUS_NOT_IMPLEMENTED;
1919 static NTSTATUS fast_release_srw_shared( RTL_SRWLOCK *lock )
1921 return STATUS_NOT_IMPLEMENTED;
1924 #endif
1926 /* SRW locks implementation
1928 * The memory layout used by the lock is:
1930 * 32 31 16 0
1931 * ________________ ________________
1932 * | X| #exclusive | #shared |
1933 * ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
1934 * Since there is no space left for a separate counter of shared access
1935 * threads inside the locked section the #shared field is used for multiple
1936 * purposes. The following table lists all possible states the lock can be
1937 * in, notation: [X, #exclusive, #shared]:
1939 * [0, 0, N] -> locked by N shared access threads, if N=0 it's unlocked
1940 * [0, >=1, >=1] -> threads are requesting exclusive locks, but there are
1941 * still shared access threads inside. #shared should not be incremented
1942 * anymore!
1943 * [1, >=1, >=0] -> lock is owned by an exclusive thread and the #shared
1944 * counter can be used again to count the number of threads waiting in the
1945 * queue for shared access.
1947 * the following states are invalid and will never occur:
1948 * [0, >=1, 0], [1, 0, >=0]
1950 * The main problem arising from the fact that we have no separate counter
1951 * of shared access threads inside the locked section is that in the state
1952 * [0, >=1, >=1] above we cannot add additional waiting threads to the
1953 * shared access queue - it wouldn't be possible to distinguish waiting
1954 * threads and those that are still inside. To solve this problem the lock
1955 * uses the following approach: a thread that isn't able to allocate a
1956 * shared lock just uses the exclusive queue instead. As soon as the thread
1957 * is woken up it is in the state [1, >=1, >=0]. In this state it's again
1958 * possible to use the shared access queue. The thread atomically moves
1959 * itself to the shared access queue and releases the exclusive lock, so
1960 * that the "real" exclusive access threads have a chance. As soon as they
1961 * are all ready the shared access threads are processed.
1964 #define SRWLOCK_MASK_IN_EXCLUSIVE 0x80000000
1965 #define SRWLOCK_MASK_EXCLUSIVE_QUEUE 0x7fff0000
1966 #define SRWLOCK_MASK_SHARED_QUEUE 0x0000ffff
1967 #define SRWLOCK_RES_EXCLUSIVE 0x00010000
1968 #define SRWLOCK_RES_SHARED 0x00000001
1970 #ifdef WORDS_BIGENDIAN
1971 #define srwlock_key_exclusive(lock) (&lock->Ptr)
1972 #define srwlock_key_shared(lock) ((void *)((char *)&lock->Ptr + 2))
1973 #else
1974 #define srwlock_key_exclusive(lock) ((void *)((char *)&lock->Ptr + 2))
1975 #define srwlock_key_shared(lock) (&lock->Ptr)
1976 #endif
1978 static inline void srwlock_check_invalid( unsigned int val )
1980 /* Throw exception if it's impossible to acquire/release this lock. */
1981 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) == SRWLOCK_MASK_EXCLUSIVE_QUEUE ||
1982 (val & SRWLOCK_MASK_SHARED_QUEUE) == SRWLOCK_MASK_SHARED_QUEUE)
1983 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED);
1986 static inline unsigned int srwlock_lock_exclusive( unsigned int *dest, int incr )
1988 unsigned int val, tmp;
1989 /* Atomically modifies the value of *dest by adding incr. If the shared
1990 * queue is empty and there are threads waiting for exclusive access, then
1991 * sets the mark SRWLOCK_MASK_IN_EXCLUSIVE to signal other threads that
1992 * they are allowed again to use the shared queue counter. */
1993 for (val = *dest;; val = tmp)
1995 tmp = val + incr;
1996 srwlock_check_invalid( tmp );
1997 if ((tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(tmp & SRWLOCK_MASK_SHARED_QUEUE))
1998 tmp |= SRWLOCK_MASK_IN_EXCLUSIVE;
1999 if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val)
2000 break;
2002 return val;
2005 static inline unsigned int srwlock_unlock_exclusive( unsigned int *dest, int incr )
2007 unsigned int val, tmp;
2008 /* Atomically modifies the value of *dest by adding incr. If the queue of
2009 * threads waiting for exclusive access is empty, then remove the
2010 * SRWLOCK_MASK_IN_EXCLUSIVE flag (only the shared queue counter will
2011 * remain). */
2012 for (val = *dest;; val = tmp)
2014 tmp = val + incr;
2015 srwlock_check_invalid( tmp );
2016 if (!(tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE))
2017 tmp &= SRWLOCK_MASK_SHARED_QUEUE;
2018 if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val)
2019 break;
2021 return val;
2024 static inline void srwlock_leave_exclusive( RTL_SRWLOCK *lock, unsigned int val )
2026 /* Used when a thread leaves an exclusive section. If there are other
2027 * exclusive access threads they are processed first, followed by
2028 * the shared waiters. */
2029 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
2030 NtReleaseKeyedEvent( 0, srwlock_key_exclusive(lock), FALSE, NULL );
2031 else
2033 val &= SRWLOCK_MASK_SHARED_QUEUE; /* remove SRWLOCK_MASK_IN_EXCLUSIVE */
2034 while (val--)
2035 NtReleaseKeyedEvent( 0, srwlock_key_shared(lock), FALSE, NULL );
2039 static inline void srwlock_leave_shared( RTL_SRWLOCK *lock, unsigned int val )
2041 /* Wake up one exclusive thread as soon as the last shared access thread
2042 * has left. */
2043 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_SHARED_QUEUE))
2044 NtReleaseKeyedEvent( 0, srwlock_key_exclusive(lock), FALSE, NULL );
2047 /***********************************************************************
2048 * RtlInitializeSRWLock (NTDLL.@)
2050 * NOTES
2051 * Please note that SRWLocks do not keep track of the owner of a lock.
2052 * It doesn't make any difference which thread for example unlocks an
2053 * SRWLock (see corresponding tests). This implementation uses two
2054 * keyed events (one for the exclusive waiters and one for the shared
2055 * waiters) and is limited to 2^15-1 waiting threads.
2057 void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock )
2059 lock->Ptr = NULL;
2062 /***********************************************************************
2063 * RtlAcquireSRWLockExclusive (NTDLL.@)
2065 * NOTES
2066 * Unlike RtlAcquireResourceExclusive this function doesn't allow
2067 * nested calls from the same thread. "Upgrading" a shared access lock
2068 * to an exclusive access lock also doesn't seem to be supported.
2070 void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
2072 if (fast_acquire_srw_exclusive( lock ) != STATUS_NOT_IMPLEMENTED)
2073 return;
2075 if (srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, SRWLOCK_RES_EXCLUSIVE ))
2076 NtWaitForKeyedEvent( 0, srwlock_key_exclusive(lock), FALSE, NULL );
2079 /***********************************************************************
2080 * RtlAcquireSRWLockShared (NTDLL.@)
2082 * NOTES
2083 * Do not call this function recursively - it will only succeed when
2084 * there are no threads waiting for an exclusive lock!
2086 void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
2088 unsigned int val, tmp;
2090 if (fast_acquire_srw_shared( lock ) != STATUS_NOT_IMPLEMENTED)
2091 return;
2093 /* Acquires a shared lock. If it's currently not possible to add elements to
2094 * the shared queue, then request exclusive access instead. */
2095 for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
2097 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
2098 tmp = val + SRWLOCK_RES_EXCLUSIVE;
2099 else
2100 tmp = val + SRWLOCK_RES_SHARED;
2101 if ((tmp = interlocked_cmpxchg( (int *)&lock->Ptr, tmp, val )) == val)
2102 break;
2105 /* Drop exclusive access again and instead requeue for shared access. */
2106 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
2108 NtWaitForKeyedEvent( 0, srwlock_key_exclusive(lock), FALSE, NULL );
2109 val = srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr, (SRWLOCK_RES_SHARED
2110 - SRWLOCK_RES_EXCLUSIVE) ) - SRWLOCK_RES_EXCLUSIVE;
2111 srwlock_leave_exclusive( lock, val );
2114 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
2115 NtWaitForKeyedEvent( 0, srwlock_key_shared(lock), FALSE, NULL );
2118 /***********************************************************************
2119 * RtlReleaseSRWLockExclusive (NTDLL.@)
2121 void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
2123 if (fast_release_srw_exclusive( lock ) != STATUS_NOT_IMPLEMENTED)
2124 return;
2126 srwlock_leave_exclusive( lock, srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr,
2127 - SRWLOCK_RES_EXCLUSIVE ) - SRWLOCK_RES_EXCLUSIVE );
2130 /***********************************************************************
2131 * RtlReleaseSRWLockShared (NTDLL.@)
2133 void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
2135 if (fast_release_srw_shared( lock ) != STATUS_NOT_IMPLEMENTED)
2136 return;
2138 srwlock_leave_shared( lock, srwlock_lock_exclusive( (unsigned int *)&lock->Ptr,
2139 - SRWLOCK_RES_SHARED ) - SRWLOCK_RES_SHARED );
2142 /***********************************************************************
2143 * RtlTryAcquireSRWLockExclusive (NTDLL.@)
2145 * NOTES
2146 * Similar to AcquireSRWLockExclusive recusive calls are not allowed
2147 * and will fail with return value FALSE.
2149 BOOLEAN WINAPI RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
2151 NTSTATUS ret;
2153 if ((ret = fast_try_acquire_srw_exclusive( lock )) != STATUS_NOT_IMPLEMENTED)
2154 return (ret == STATUS_SUCCESS);
2156 return interlocked_cmpxchg( (int *)&lock->Ptr, SRWLOCK_MASK_IN_EXCLUSIVE |
2157 SRWLOCK_RES_EXCLUSIVE, 0 ) == 0;
2160 /***********************************************************************
2161 * RtlTryAcquireSRWLockShared (NTDLL.@)
2163 BOOLEAN WINAPI RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock )
2165 unsigned int val, tmp;
2166 NTSTATUS ret;
2168 if ((ret = fast_try_acquire_srw_shared( lock )) != STATUS_NOT_IMPLEMENTED)
2169 return (ret == STATUS_SUCCESS);
2171 for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
2173 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
2174 return FALSE;
2175 if ((tmp = interlocked_cmpxchg( (int *)&lock->Ptr, val + SRWLOCK_RES_SHARED, val )) == val)
2176 break;
2178 return TRUE;
2181 #ifdef __linux__
2182 static NTSTATUS fast_wait_cv( RTL_CONDITION_VARIABLE *variable, int val, const LARGE_INTEGER *timeout )
2184 struct timespec timespec;
2185 int ret;
2187 if (!use_futexes())
2188 return STATUS_NOT_IMPLEMENTED;
2190 if (timeout && timeout->QuadPart != TIMEOUT_INFINITE)
2192 timespec_from_timeout( &timespec, timeout );
2193 ret = futex_wait( (int *)&variable->Ptr, val, &timespec );
2195 else
2196 ret = futex_wait( (int *)&variable->Ptr, val, NULL );
2198 if (ret == -1 && errno == ETIMEDOUT)
2199 return STATUS_TIMEOUT;
2200 return STATUS_WAIT_0;
2203 static NTSTATUS fast_wake_cv( RTL_CONDITION_VARIABLE *variable, int count )
2205 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2207 futex_wake( (int *)&variable->Ptr, count );
2208 return STATUS_SUCCESS;
2210 #else
2211 static NTSTATUS fast_wait_cv( RTL_CONDITION_VARIABLE *variable, int val, const LARGE_INTEGER *timeout )
2213 return STATUS_NOT_IMPLEMENTED;
2216 static NTSTATUS fast_wake_cv( RTL_CONDITION_VARIABLE *variable, int count )
2218 return STATUS_NOT_IMPLEMENTED;
2220 #endif
2222 /***********************************************************************
2223 * RtlInitializeConditionVariable (NTDLL.@)
2225 * Initializes the condition variable with NULL.
2227 * PARAMS
2228 * variable [O] condition variable
2230 * RETURNS
2231 * Nothing.
2233 void WINAPI RtlInitializeConditionVariable( RTL_CONDITION_VARIABLE *variable )
2235 variable->Ptr = NULL;
2238 /***********************************************************************
2239 * RtlWakeConditionVariable (NTDLL.@)
2241 * Wakes up one thread waiting on the condition variable.
2243 * PARAMS
2244 * variable [I/O] condition variable to wake up.
2246 * RETURNS
2247 * Nothing.
2249 * NOTES
2250 * The calling thread does not have to own any lock in order to call
2251 * this function.
2253 void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable )
2255 interlocked_xchg_add( (int *)&variable->Ptr, 1 );
2256 if (fast_wake_cv( variable, 1 ) == STATUS_NOT_IMPLEMENTED)
2257 RtlWakeAddressSingle( variable );
2260 /***********************************************************************
2261 * RtlWakeAllConditionVariable (NTDLL.@)
2263 * See WakeConditionVariable, wakes up all waiting threads.
2265 void WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *variable )
2267 interlocked_xchg_add( (int *)&variable->Ptr, 1 );
2268 if (fast_wake_cv( variable, INT_MAX ) == STATUS_NOT_IMPLEMENTED)
2269 RtlWakeAddressAll( variable );
2272 /***********************************************************************
2273 * RtlSleepConditionVariableCS (NTDLL.@)
2275 * Atomically releases the critical section and suspends the thread,
2276 * waiting for a Wake(All)ConditionVariable event. Afterwards it enters
2277 * the critical section again and returns.
2279 * PARAMS
2280 * variable [I/O] condition variable
2281 * crit [I/O] critical section to leave temporarily
2282 * timeout [I] timeout
2284 * RETURNS
2285 * see NtWaitForKeyedEvent for all possible return values.
2287 NTSTATUS WINAPI RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, RTL_CRITICAL_SECTION *crit,
2288 const LARGE_INTEGER *timeout )
2290 NTSTATUS status;
2291 int val = *(int *)&variable->Ptr;
2293 RtlLeaveCriticalSection( crit );
2295 if ((status = fast_wait_cv( variable, val, timeout )) == STATUS_NOT_IMPLEMENTED)
2296 status = RtlWaitOnAddress( &variable->Ptr, &val, sizeof(int), timeout );
2298 RtlEnterCriticalSection( crit );
2300 return status;
2303 /***********************************************************************
2304 * RtlSleepConditionVariableSRW (NTDLL.@)
2306 * Atomically releases the SRWLock and suspends the thread,
2307 * waiting for a Wake(All)ConditionVariable event. Afterwards it enters
2308 * the SRWLock again with the same access rights and returns.
2310 * PARAMS
2311 * variable [I/O] condition variable
2312 * lock [I/O] SRWLock to leave temporarily
2313 * timeout [I] timeout
2314 * flags [I] type of the current lock (exclusive / shared)
2316 * RETURNS
2317 * see NtWaitForKeyedEvent for all possible return values.
2319 * NOTES
2320 * the behaviour is undefined if the thread doesn't own the lock.
2322 NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, RTL_SRWLOCK *lock,
2323 const LARGE_INTEGER *timeout, ULONG flags )
2325 NTSTATUS status;
2326 int val = *(int *)&variable->Ptr;
2328 if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
2329 RtlReleaseSRWLockShared( lock );
2330 else
2331 RtlReleaseSRWLockExclusive( lock );
2333 if ((status = fast_wait_cv( variable, val, timeout )) == STATUS_NOT_IMPLEMENTED)
2334 status = RtlWaitOnAddress( &variable->Ptr, &val, sizeof(int), timeout );
2336 if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
2337 RtlAcquireSRWLockShared( lock );
2338 else
2339 RtlAcquireSRWLockExclusive( lock );
2340 return status;
2343 static RTL_CRITICAL_SECTION addr_section;
2344 static RTL_CRITICAL_SECTION_DEBUG addr_section_debug =
2346 0, 0, &addr_section,
2347 { &addr_section_debug.ProcessLocksList, &addr_section_debug.ProcessLocksList },
2348 0, 0, { (DWORD_PTR)(__FILE__ ": addr_section") }
2350 static RTL_CRITICAL_SECTION addr_section = { &addr_section_debug, -1, 0, 0, 0, 0 };
2352 static BOOL compare_addr( const void *addr, const void *cmp, SIZE_T size )
2354 switch (size)
2356 case 1:
2357 return (*(const UCHAR *)addr == *(const UCHAR *)cmp);
2358 case 2:
2359 return (*(const USHORT *)addr == *(const USHORT *)cmp);
2360 case 4:
2361 return (*(const ULONG *)addr == *(const ULONG *)cmp);
2362 case 8:
2363 return (*(const ULONG64 *)addr == *(const ULONG64 *)cmp);
2366 return FALSE;
2369 #ifdef __linux__
2370 /* We can't map addresses to futex directly, because an application can wait on
2371 * 8 bytes, and we can't pass all 8 as the compare value to futex(). Instead we
2372 * map all addresses to a small fixed table of futexes. This may result in
2373 * spurious wakes, but the application is already expected to handle those. */
2375 static int addr_futex_table[256];
2377 static inline int *hash_addr( const void *addr )
2379 ULONG_PTR val = (ULONG_PTR)addr;
2381 return &addr_futex_table[(val >> 2) & 255];
2384 static inline NTSTATUS fast_wait_addr( const void *addr, const void *cmp, SIZE_T size,
2385 const LARGE_INTEGER *timeout )
2387 int *futex;
2388 int val;
2389 struct timespec timespec;
2390 int ret;
2392 if (!use_futexes())
2393 return STATUS_NOT_IMPLEMENTED;
2395 futex = hash_addr( addr );
2397 /* We must read the previous value of the futex before checking the value
2398 * of the address being waited on. That way, if we receive a wake between
2399 * now and waiting on the futex, we know that val will have changed.
2400 * Use an atomic load so that memory accesses are ordered between this read
2401 * and the increment below. */
2402 val = interlocked_cmpxchg( futex, 0, 0 );
2403 if (!compare_addr( addr, cmp, size ))
2404 return STATUS_SUCCESS;
2406 if (timeout)
2408 timespec_from_timeout( &timespec, timeout );
2409 ret = futex_wait( futex, val, &timespec );
2411 else
2412 ret = futex_wait( futex, val, NULL );
2414 if (ret == -1 && errno == ETIMEDOUT)
2415 return STATUS_TIMEOUT;
2416 return STATUS_SUCCESS;
2419 static inline NTSTATUS fast_wake_addr( const void *addr )
2421 int *futex;
2423 if (!use_futexes())
2424 return STATUS_NOT_IMPLEMENTED;
2426 futex = hash_addr( addr );
2428 interlocked_xchg_add( futex, 1 );
2430 futex_wake( futex, INT_MAX );
2431 return STATUS_SUCCESS;
2433 #else
2434 static inline NTSTATUS fast_wait_addr( const void *addr, const void *cmp, SIZE_T size,
2435 const LARGE_INTEGER *timeout )
2437 return STATUS_NOT_IMPLEMENTED;
2440 static inline NTSTATUS fast_wake_addr( const void *addr )
2442 return STATUS_NOT_IMPLEMENTED;
2444 #endif
2446 /***********************************************************************
2447 * RtlWaitOnAddress (NTDLL.@)
2449 NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size,
2450 const LARGE_INTEGER *timeout )
2452 select_op_t select_op;
2453 NTSTATUS ret;
2454 int cookie;
2455 BOOL user_apc = FALSE;
2456 obj_handle_t apc_handle = 0;
2457 apc_call_t call;
2458 apc_result_t result;
2459 timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE;
2461 if (size != 1 && size != 2 && size != 4 && size != 8)
2462 return STATUS_INVALID_PARAMETER;
2464 if ((ret = fast_wait_addr( addr, cmp, size, timeout )) != STATUS_NOT_IMPLEMENTED)
2465 return ret;
2467 select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT;
2468 select_op.keyed_event.handle = wine_server_obj_handle( keyed_event );
2469 select_op.keyed_event.key = wine_server_client_ptr( addr );
2471 memset( &result, 0, sizeof(result) );
2473 for (;;)
2475 RtlEnterCriticalSection( &addr_section );
2476 if (!compare_addr( addr, cmp, size ))
2478 RtlLeaveCriticalSection( &addr_section );
2479 return STATUS_SUCCESS;
2482 SERVER_START_REQ( select )
2484 req->flags = SELECT_INTERRUPTIBLE;
2485 req->cookie = wine_server_client_ptr( &cookie );
2486 req->prev_apc = apc_handle;
2487 req->timeout = abs_timeout;
2488 wine_server_add_data( req, &result, sizeof(result) );
2489 wine_server_add_data( req, &select_op, sizeof(select_op.keyed_event) );
2490 ret = wine_server_call( req );
2491 abs_timeout = reply->timeout;
2492 apc_handle = reply->apc_handle;
2493 call = reply->call;
2495 SERVER_END_REQ;
2497 RtlLeaveCriticalSection( &addr_section );
2499 if (ret == STATUS_PENDING) ret = wait_select_reply( &cookie );
2500 if (ret != STATUS_USER_APC) break;
2501 if (invoke_apc( &call, &result ))
2503 /* if we ran a user apc we have to check once more if additional apcs are queued,
2504 * but we don't want to wait */
2505 abs_timeout = 0;
2506 user_apc = TRUE;
2507 size = 0;
2511 if (ret == STATUS_TIMEOUT && user_apc) ret = STATUS_USER_APC;
2513 return ret;
2516 /***********************************************************************
2517 * RtlWakeAddressAll (NTDLL.@)
2519 void WINAPI RtlWakeAddressAll( const void *addr )
2521 if (fast_wake_addr( addr ) != STATUS_NOT_IMPLEMENTED)
2522 return;
2524 RtlEnterCriticalSection( &addr_section );
2525 while (NtReleaseKeyedEvent( 0, addr, 0, &zero_timeout ) == STATUS_SUCCESS) {}
2526 RtlLeaveCriticalSection( &addr_section );
2529 /***********************************************************************
2530 * RtlWakeAddressSingle (NTDLL.@)
2532 void WINAPI RtlWakeAddressSingle( const void *addr )
2534 if (fast_wake_addr( addr ) != STATUS_NOT_IMPLEMENTED)
2535 return;
2537 RtlEnterCriticalSection( &addr_section );
2538 NtReleaseKeyedEvent( 0, addr, 0, &zero_timeout );
2539 RtlLeaveCriticalSection( &addr_section );