crypt32/tests: Add a trailing '\n' to ok() calls.
[wine.git] / dlls / ntdll / sync.c
blobc1797601de9ba4dec144449a332913227382ff16
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 alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_attributes **ret,
77 data_size_t *ret_len )
79 unsigned int len = sizeof(**ret);
80 PSID owner, group;
81 ACL *dacl, *sacl;
82 BOOLEAN owner_present, group_present, dacl_present, sacl_present, defaulted;
83 PSECURITY_DESCRIPTOR sd;
84 NTSTATUS status;
86 *ret = NULL;
87 *ret_len = 0;
89 if (!attr) return STATUS_SUCCESS;
91 if (attr->Length != sizeof(*attr)) return STATUS_INVALID_PARAMETER;
93 if ((sd = attr->SecurityDescriptor))
95 len += sizeof(struct security_descriptor);
97 if ((status = RtlGetOwnerSecurityDescriptor( sd, &owner, &owner_present ))) return status;
98 if ((status = RtlGetGroupSecurityDescriptor( sd, &group, &group_present ))) return status;
99 if ((status = RtlGetSaclSecurityDescriptor( sd, &sacl_present, &sacl, &defaulted ))) return status;
100 if ((status = RtlGetDaclSecurityDescriptor( sd, &dacl_present, &dacl, &defaulted ))) return status;
101 if (owner_present) len += RtlLengthSid( owner );
102 if (group_present) len += RtlLengthSid( group );
103 if (sacl_present && sacl) len += sacl->AclSize;
104 if (dacl_present && dacl) len += dacl->AclSize;
106 /* fix alignment for the Unicode name that follows the structure */
107 len = (len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
110 if (attr->ObjectName)
112 if (attr->ObjectName->Length & (sizeof(WCHAR) - 1)) return STATUS_OBJECT_NAME_INVALID;
113 len += attr->ObjectName->Length;
115 else if (attr->RootDirectory) return STATUS_OBJECT_NAME_INVALID;
117 *ret = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, len );
118 if (!*ret) return STATUS_NO_MEMORY;
120 (*ret)->rootdir = wine_server_obj_handle( attr->RootDirectory );
121 (*ret)->attributes = attr->Attributes;
123 if (attr->SecurityDescriptor)
125 struct security_descriptor *descr = (struct security_descriptor *)(*ret + 1);
126 unsigned char *ptr = (unsigned char *)(descr + 1);
128 descr->control = ((SECURITY_DESCRIPTOR *)sd)->Control & ~SE_SELF_RELATIVE;
129 if (owner_present) descr->owner_len = RtlLengthSid( owner );
130 if (group_present) descr->group_len = RtlLengthSid( group );
131 if (sacl_present && sacl) descr->sacl_len = sacl->AclSize;
132 if (dacl_present && dacl) descr->dacl_len = dacl->AclSize;
134 memcpy( ptr, owner, descr->owner_len );
135 ptr += descr->owner_len;
136 memcpy( ptr, group, descr->group_len );
137 ptr += descr->group_len;
138 memcpy( ptr, sacl, descr->sacl_len );
139 ptr += descr->sacl_len;
140 memcpy( ptr, dacl, descr->dacl_len );
141 (*ret)->sd_len = (sizeof(*descr) + descr->owner_len + descr->group_len + descr->sacl_len +
142 descr->dacl_len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
145 if (attr->ObjectName)
147 unsigned char *ptr = (unsigned char *)(*ret + 1) + (*ret)->sd_len;
148 (*ret)->name_len = attr->ObjectName->Length;
149 memcpy( ptr, attr->ObjectName->Buffer, (*ret)->name_len );
152 *ret_len = len;
153 return STATUS_SUCCESS;
156 NTSTATUS validate_open_object_attributes( const OBJECT_ATTRIBUTES *attr )
158 if (!attr || attr->Length != sizeof(*attr)) return STATUS_INVALID_PARAMETER;
160 if (attr->ObjectName)
162 if (attr->ObjectName->Length & (sizeof(WCHAR) - 1)) return STATUS_OBJECT_NAME_INVALID;
164 else if (attr->RootDirectory) return STATUS_OBJECT_NAME_INVALID;
166 return STATUS_SUCCESS;
170 * Semaphores
173 /******************************************************************************
174 * NtCreateSemaphore (NTDLL.@)
176 NTSTATUS WINAPI NtCreateSemaphore( OUT PHANDLE SemaphoreHandle,
177 IN ACCESS_MASK access,
178 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
179 IN LONG InitialCount,
180 IN LONG MaximumCount )
182 NTSTATUS ret;
183 data_size_t len;
184 struct object_attributes *objattr;
186 if (MaximumCount <= 0 || InitialCount < 0 || InitialCount > MaximumCount)
187 return STATUS_INVALID_PARAMETER;
189 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
191 SERVER_START_REQ( create_semaphore )
193 req->access = access;
194 req->initial = InitialCount;
195 req->max = MaximumCount;
196 wine_server_add_data( req, objattr, len );
197 ret = wine_server_call( req );
198 *SemaphoreHandle = wine_server_ptr_handle( reply->handle );
200 SERVER_END_REQ;
202 RtlFreeHeap( GetProcessHeap(), 0, objattr );
203 return ret;
206 /******************************************************************************
207 * NtOpenSemaphore (NTDLL.@)
209 NTSTATUS WINAPI NtOpenSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
211 NTSTATUS ret;
213 if ((ret = validate_open_object_attributes( attr ))) return ret;
215 SERVER_START_REQ( open_semaphore )
217 req->access = access;
218 req->attributes = attr->Attributes;
219 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
220 if (attr->ObjectName)
221 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
222 ret = wine_server_call( req );
223 *handle = wine_server_ptr_handle( reply->handle );
225 SERVER_END_REQ;
226 return ret;
229 /******************************************************************************
230 * NtQuerySemaphore (NTDLL.@)
232 NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS class,
233 void *info, ULONG len, ULONG *ret_len )
235 NTSTATUS ret;
236 SEMAPHORE_BASIC_INFORMATION *out = info;
238 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, len, ret_len);
240 if (class != SemaphoreBasicInformation)
242 FIXME("(%p,%d,%u) Unknown class\n", handle, class, len);
243 return STATUS_INVALID_INFO_CLASS;
246 if (len != sizeof(SEMAPHORE_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
248 SERVER_START_REQ( query_semaphore )
250 req->handle = wine_server_obj_handle( handle );
251 if (!(ret = wine_server_call( req )))
253 out->CurrentCount = reply->current;
254 out->MaximumCount = reply->max;
255 if (ret_len) *ret_len = sizeof(SEMAPHORE_BASIC_INFORMATION);
258 SERVER_END_REQ;
260 return ret;
263 /******************************************************************************
264 * NtReleaseSemaphore (NTDLL.@)
266 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
268 NTSTATUS ret;
269 SERVER_START_REQ( release_semaphore )
271 req->handle = wine_server_obj_handle( handle );
272 req->count = count;
273 if (!(ret = wine_server_call( req )))
275 if (previous) *previous = reply->prev_count;
278 SERVER_END_REQ;
279 return ret;
283 * Events
286 /**************************************************************************
287 * NtCreateEvent (NTDLL.@)
288 * ZwCreateEvent (NTDLL.@)
290 NTSTATUS WINAPI NtCreateEvent( PHANDLE EventHandle, ACCESS_MASK DesiredAccess,
291 const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN InitialState)
293 NTSTATUS ret;
294 data_size_t len;
295 struct object_attributes *objattr;
297 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
299 SERVER_START_REQ( create_event )
301 req->access = DesiredAccess;
302 req->manual_reset = (type == NotificationEvent);
303 req->initial_state = InitialState;
304 wine_server_add_data( req, objattr, len );
305 ret = wine_server_call( req );
306 *EventHandle = wine_server_ptr_handle( reply->handle );
308 SERVER_END_REQ;
310 RtlFreeHeap( GetProcessHeap(), 0, objattr );
311 return ret;
314 /******************************************************************************
315 * NtOpenEvent (NTDLL.@)
316 * ZwOpenEvent (NTDLL.@)
318 NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
320 NTSTATUS ret;
322 if ((ret = validate_open_object_attributes( attr ))) return ret;
324 SERVER_START_REQ( open_event )
326 req->access = access;
327 req->attributes = attr->Attributes;
328 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
329 if (attr->ObjectName)
330 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
331 ret = wine_server_call( req );
332 *handle = wine_server_ptr_handle( reply->handle );
334 SERVER_END_REQ;
335 return ret;
339 /******************************************************************************
340 * NtSetEvent (NTDLL.@)
341 * ZwSetEvent (NTDLL.@)
343 NTSTATUS WINAPI NtSetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
345 NTSTATUS ret;
347 /* FIXME: set NumberOfThreadsReleased */
349 SERVER_START_REQ( event_op )
351 req->handle = wine_server_obj_handle( handle );
352 req->op = SET_EVENT;
353 ret = wine_server_call( req );
355 SERVER_END_REQ;
356 return ret;
359 /******************************************************************************
360 * NtResetEvent (NTDLL.@)
362 NTSTATUS WINAPI NtResetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
364 NTSTATUS ret;
366 /* resetting an event can't release any thread... */
367 if (NumberOfThreadsReleased) *NumberOfThreadsReleased = 0;
369 SERVER_START_REQ( event_op )
371 req->handle = wine_server_obj_handle( handle );
372 req->op = RESET_EVENT;
373 ret = wine_server_call( req );
375 SERVER_END_REQ;
376 return ret;
379 /******************************************************************************
380 * NtClearEvent (NTDLL.@)
382 * FIXME
383 * same as NtResetEvent ???
385 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
387 return NtResetEvent( handle, NULL );
390 /******************************************************************************
391 * NtPulseEvent (NTDLL.@)
393 * FIXME
394 * PulseCount
396 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, PULONG PulseCount )
398 NTSTATUS ret;
400 if (PulseCount)
401 FIXME("(%p,%d)\n", handle, *PulseCount);
403 SERVER_START_REQ( event_op )
405 req->handle = wine_server_obj_handle( handle );
406 req->op = PULSE_EVENT;
407 ret = wine_server_call( req );
409 SERVER_END_REQ;
410 return ret;
413 /******************************************************************************
414 * NtQueryEvent (NTDLL.@)
416 NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class,
417 void *info, ULONG len, ULONG *ret_len )
419 NTSTATUS ret;
420 EVENT_BASIC_INFORMATION *out = info;
422 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, len, ret_len);
424 if (class != EventBasicInformation)
426 FIXME("(%p, %d, %d) Unknown class\n",
427 handle, class, len);
428 return STATUS_INVALID_INFO_CLASS;
431 if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
433 SERVER_START_REQ( query_event )
435 req->handle = wine_server_obj_handle( handle );
436 if (!(ret = wine_server_call( req )))
438 out->EventType = reply->manual_reset ? NotificationEvent : SynchronizationEvent;
439 out->EventState = reply->state;
440 if (ret_len) *ret_len = sizeof(EVENT_BASIC_INFORMATION);
443 SERVER_END_REQ;
445 return ret;
449 * Mutants (known as Mutexes in Kernel32)
452 /******************************************************************************
453 * NtCreateMutant [NTDLL.@]
454 * ZwCreateMutant [NTDLL.@]
456 NTSTATUS WINAPI NtCreateMutant(OUT HANDLE* MutantHandle,
457 IN ACCESS_MASK access,
458 IN const OBJECT_ATTRIBUTES* attr OPTIONAL,
459 IN BOOLEAN InitialOwner)
461 NTSTATUS status;
462 data_size_t len;
463 struct object_attributes *objattr;
465 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
467 SERVER_START_REQ( create_mutex )
469 req->access = access;
470 req->owned = InitialOwner;
471 wine_server_add_data( req, objattr, len );
472 status = wine_server_call( req );
473 *MutantHandle = wine_server_ptr_handle( reply->handle );
475 SERVER_END_REQ;
477 RtlFreeHeap( GetProcessHeap(), 0, objattr );
478 return status;
481 /**************************************************************************
482 * NtOpenMutant [NTDLL.@]
483 * ZwOpenMutant [NTDLL.@]
485 NTSTATUS WINAPI NtOpenMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
487 NTSTATUS status;
489 if ((status = validate_open_object_attributes( attr ))) return status;
491 SERVER_START_REQ( open_mutex )
493 req->access = access;
494 req->attributes = attr->Attributes;
495 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
496 if (attr->ObjectName)
497 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
498 status = wine_server_call( req );
499 *handle = wine_server_ptr_handle( reply->handle );
501 SERVER_END_REQ;
502 return status;
505 /**************************************************************************
506 * NtReleaseMutant [NTDLL.@]
507 * ZwReleaseMutant [NTDLL.@]
509 NTSTATUS WINAPI NtReleaseMutant( IN HANDLE handle, OUT PLONG prev_count OPTIONAL)
511 NTSTATUS status;
513 SERVER_START_REQ( release_mutex )
515 req->handle = wine_server_obj_handle( handle );
516 status = wine_server_call( req );
517 if (prev_count) *prev_count = 1 - reply->prev_count;
519 SERVER_END_REQ;
520 return status;
523 /******************************************************************
524 * NtQueryMutant [NTDLL.@]
525 * ZwQueryMutant [NTDLL.@]
527 NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class,
528 void *info, ULONG len, ULONG *ret_len )
530 NTSTATUS ret;
531 MUTANT_BASIC_INFORMATION *out = info;
533 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, len, ret_len);
535 if (class != MutantBasicInformation)
537 FIXME("(%p, %d, %d) Unknown class\n",
538 handle, class, len);
539 return STATUS_INVALID_INFO_CLASS;
542 if (len != sizeof(MUTANT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
544 SERVER_START_REQ( query_mutex )
546 req->handle = wine_server_obj_handle( handle );
547 if (!(ret = wine_server_call( req )))
549 out->CurrentCount = 1 - reply->count;
550 out->OwnedByCaller = reply->owned;
551 out->AbandonedState = reply->abandoned;
552 if (ret_len) *ret_len = sizeof(MUTANT_BASIC_INFORMATION);
555 SERVER_END_REQ;
557 return ret;
561 * Jobs
564 /******************************************************************************
565 * NtCreateJobObject [NTDLL.@]
566 * ZwCreateJobObject [NTDLL.@]
568 NTSTATUS WINAPI NtCreateJobObject( PHANDLE handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
570 NTSTATUS ret;
571 data_size_t len;
572 struct object_attributes *objattr;
574 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
576 SERVER_START_REQ( create_job )
578 req->access = access;
579 wine_server_add_data( req, objattr, len );
580 ret = wine_server_call( req );
581 *handle = wine_server_ptr_handle( reply->handle );
583 SERVER_END_REQ;
585 RtlFreeHeap( GetProcessHeap(), 0, objattr );
586 return ret;
589 /******************************************************************************
590 * NtOpenJobObject [NTDLL.@]
591 * ZwOpenJobObject [NTDLL.@]
593 NTSTATUS WINAPI NtOpenJobObject( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
595 NTSTATUS ret;
597 if ((ret = validate_open_object_attributes( attr ))) return ret;
599 SERVER_START_REQ( open_job )
601 req->access = access;
602 req->attributes = attr->Attributes;
603 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
604 if (attr->ObjectName)
605 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
606 ret = wine_server_call( req );
607 *handle = wine_server_ptr_handle( reply->handle );
609 SERVER_END_REQ;
610 return ret;
613 /******************************************************************************
614 * NtTerminateJobObject [NTDLL.@]
615 * ZwTerminateJobObject [NTDLL.@]
617 NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status )
619 NTSTATUS ret;
621 TRACE( "(%p, %d)\n", handle, status );
623 SERVER_START_REQ( terminate_job )
625 req->handle = wine_server_obj_handle( handle );
626 req->status = status;
627 ret = wine_server_call( req );
629 SERVER_END_REQ;
631 return ret;
634 /******************************************************************************
635 * NtQueryInformationJobObject [NTDLL.@]
636 * ZwQueryInformationJobObject [NTDLL.@]
638 NTSTATUS WINAPI NtQueryInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info,
639 ULONG len, PULONG ret_len )
641 FIXME( "stub: %p %u %p %u %p\n", handle, class, info, len, ret_len );
643 if (class >= MaxJobObjectInfoClass)
644 return STATUS_INVALID_PARAMETER;
646 switch (class)
648 case JobObjectExtendedLimitInformation:
650 JOBOBJECT_EXTENDED_LIMIT_INFORMATION *extended_limit;
651 if (len < sizeof(*extended_limit))
652 return STATUS_INFO_LENGTH_MISMATCH;
654 extended_limit = (JOBOBJECT_EXTENDED_LIMIT_INFORMATION *)info;
655 memset(extended_limit, 0, sizeof(*extended_limit));
656 if (ret_len) *ret_len = sizeof(*extended_limit);
657 return STATUS_SUCCESS;
660 case JobObjectBasicLimitInformation:
662 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit;
663 if (len < sizeof(*basic_limit))
664 return STATUS_INFO_LENGTH_MISMATCH;
666 basic_limit = (JOBOBJECT_BASIC_LIMIT_INFORMATION *)info;
667 memset(basic_limit, 0, sizeof(*basic_limit));
668 if (ret_len) *ret_len = sizeof(*basic_limit);
669 return STATUS_SUCCESS;
672 default:
673 return STATUS_NOT_IMPLEMENTED;
677 /******************************************************************************
678 * NtSetInformationJobObject [NTDLL.@]
679 * ZwSetInformationJobObject [NTDLL.@]
681 NTSTATUS WINAPI NtSetInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info, ULONG len )
683 NTSTATUS status = STATUS_NOT_IMPLEMENTED;
684 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit;
685 ULONG info_size = sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION);
686 DWORD limit_flags = JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS;
688 TRACE( "(%p, %u, %p, %u)\n", handle, class, info, len );
690 if (class >= MaxJobObjectInfoClass)
691 return STATUS_INVALID_PARAMETER;
693 switch (class)
696 case JobObjectExtendedLimitInformation:
697 info_size = sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION);
698 limit_flags = JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS;
699 /* fallthrough */
700 case JobObjectBasicLimitInformation:
701 if (len != info_size)
702 return STATUS_INVALID_PARAMETER;
704 basic_limit = info;
705 if (basic_limit->LimitFlags & ~limit_flags)
706 return STATUS_INVALID_PARAMETER;
708 SERVER_START_REQ( set_job_limits )
710 req->handle = wine_server_obj_handle( handle );
711 req->limit_flags = basic_limit->LimitFlags;
712 status = wine_server_call( req );
714 SERVER_END_REQ;
715 break;
717 case JobObjectAssociateCompletionPortInformation:
718 if (len != sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT))
719 return STATUS_INVALID_PARAMETER;
721 SERVER_START_REQ( set_job_completion_port )
723 JOBOBJECT_ASSOCIATE_COMPLETION_PORT *port_info = info;
724 req->job = wine_server_obj_handle( handle );
725 req->port = wine_server_obj_handle( port_info->CompletionPort );
726 req->key = wine_server_client_ptr( port_info->CompletionKey );
727 status = wine_server_call(req);
729 SERVER_END_REQ;
730 break;
732 case JobObjectBasicUIRestrictions:
733 status = STATUS_SUCCESS;
734 /* fallthrough */
735 default:
736 FIXME( "stub: %p %u %p %u\n", handle, class, info, len );
739 return status;
742 /******************************************************************************
743 * NtIsProcessInJob [NTDLL.@]
744 * ZwIsProcessInJob [NTDLL.@]
746 NTSTATUS WINAPI NtIsProcessInJob( HANDLE process, HANDLE job )
748 NTSTATUS status;
750 TRACE( "(%p %p)\n", job, process );
752 SERVER_START_REQ( process_in_job )
754 req->job = wine_server_obj_handle( job );
755 req->process = wine_server_obj_handle( process );
756 status = wine_server_call( req );
758 SERVER_END_REQ;
760 return status;
763 /******************************************************************************
764 * NtAssignProcessToJobObject [NTDLL.@]
765 * ZwAssignProcessToJobObject [NTDLL.@]
767 NTSTATUS WINAPI NtAssignProcessToJobObject( HANDLE job, HANDLE process )
769 NTSTATUS status;
771 TRACE( "(%p %p)\n", job, process );
773 SERVER_START_REQ( assign_job )
775 req->job = wine_server_obj_handle( job );
776 req->process = wine_server_obj_handle( process );
777 status = wine_server_call( req );
779 SERVER_END_REQ;
781 return status;
785 * Timers
788 /**************************************************************************
789 * NtCreateTimer [NTDLL.@]
790 * ZwCreateTimer [NTDLL.@]
792 NTSTATUS WINAPI NtCreateTimer(OUT HANDLE *handle,
793 IN ACCESS_MASK access,
794 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
795 IN TIMER_TYPE timer_type)
797 NTSTATUS status;
798 data_size_t len;
799 struct object_attributes *objattr;
801 if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
802 return STATUS_INVALID_PARAMETER;
804 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
806 SERVER_START_REQ( create_timer )
808 req->access = access;
809 req->manual = (timer_type == NotificationTimer);
810 wine_server_add_data( req, objattr, len );
811 status = wine_server_call( req );
812 *handle = wine_server_ptr_handle( reply->handle );
814 SERVER_END_REQ;
816 RtlFreeHeap( GetProcessHeap(), 0, objattr );
817 return status;
821 /**************************************************************************
822 * NtOpenTimer [NTDLL.@]
823 * ZwOpenTimer [NTDLL.@]
825 NTSTATUS WINAPI NtOpenTimer( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
827 NTSTATUS status;
829 if ((status = validate_open_object_attributes( attr ))) return status;
831 SERVER_START_REQ( open_timer )
833 req->access = access;
834 req->attributes = attr->Attributes;
835 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
836 if (attr->ObjectName)
837 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
838 status = wine_server_call( req );
839 *handle = wine_server_ptr_handle( reply->handle );
841 SERVER_END_REQ;
842 return status;
845 /**************************************************************************
846 * NtSetTimer [NTDLL.@]
847 * ZwSetTimer [NTDLL.@]
849 NTSTATUS WINAPI NtSetTimer(IN HANDLE handle,
850 IN const LARGE_INTEGER* when,
851 IN PTIMER_APC_ROUTINE callback,
852 IN PVOID callback_arg,
853 IN BOOLEAN resume,
854 IN ULONG period OPTIONAL,
855 OUT PBOOLEAN state OPTIONAL)
857 NTSTATUS status = STATUS_SUCCESS;
859 TRACE("(%p,%p,%p,%p,%08x,0x%08x,%p)\n",
860 handle, when, callback, callback_arg, resume, period, state);
862 SERVER_START_REQ( set_timer )
864 req->handle = wine_server_obj_handle( handle );
865 req->period = period;
866 req->expire = when->QuadPart;
867 req->callback = wine_server_client_ptr( callback );
868 req->arg = wine_server_client_ptr( callback_arg );
869 status = wine_server_call( req );
870 if (state) *state = reply->signaled;
872 SERVER_END_REQ;
874 /* set error but can still succeed */
875 if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
876 return status;
879 /**************************************************************************
880 * NtCancelTimer [NTDLL.@]
881 * ZwCancelTimer [NTDLL.@]
883 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
885 NTSTATUS status;
887 SERVER_START_REQ( cancel_timer )
889 req->handle = wine_server_obj_handle( handle );
890 status = wine_server_call( req );
891 if (state) *state = reply->signaled;
893 SERVER_END_REQ;
894 return status;
897 /******************************************************************************
898 * NtQueryTimer (NTDLL.@)
900 * Retrieves information about a timer.
902 * PARAMS
903 * TimerHandle [I] The timer to retrieve information about.
904 * TimerInformationClass [I] The type of information to retrieve.
905 * TimerInformation [O] Pointer to buffer to store information in.
906 * Length [I] The length of the buffer pointed to by TimerInformation.
907 * ReturnLength [O] Optional. The size of buffer actually used.
909 * RETURNS
910 * Success: STATUS_SUCCESS
911 * Failure: STATUS_INFO_LENGTH_MISMATCH, if Length doesn't match the required data
912 * size for the class specified.
913 * STATUS_INVALID_INFO_CLASS, if an invalid TimerInformationClass was specified.
914 * STATUS_ACCESS_DENIED, if TimerHandle does not have TIMER_QUERY_STATE access
915 * to the timer.
917 NTSTATUS WINAPI NtQueryTimer(
918 HANDLE TimerHandle,
919 TIMER_INFORMATION_CLASS TimerInformationClass,
920 PVOID TimerInformation,
921 ULONG Length,
922 PULONG ReturnLength)
924 TIMER_BASIC_INFORMATION * basic_info = TimerInformation;
925 NTSTATUS status;
926 LARGE_INTEGER now;
928 TRACE("(%p,%d,%p,0x%08x,%p)\n", TimerHandle, TimerInformationClass,
929 TimerInformation, Length, ReturnLength);
931 switch (TimerInformationClass)
933 case TimerBasicInformation:
934 if (Length < sizeof(TIMER_BASIC_INFORMATION))
935 return STATUS_INFO_LENGTH_MISMATCH;
937 SERVER_START_REQ(get_timer_info)
939 req->handle = wine_server_obj_handle( TimerHandle );
940 status = wine_server_call(req);
942 /* convert server time to absolute NTDLL time */
943 basic_info->RemainingTime.QuadPart = reply->when;
944 basic_info->TimerState = reply->signaled;
946 SERVER_END_REQ;
948 /* convert from absolute into relative time */
949 NtQuerySystemTime(&now);
950 if (now.QuadPart > basic_info->RemainingTime.QuadPart)
951 basic_info->RemainingTime.QuadPart = 0;
952 else
953 basic_info->RemainingTime.QuadPart -= now.QuadPart;
955 if (ReturnLength) *ReturnLength = sizeof(TIMER_BASIC_INFORMATION);
957 return status;
960 FIXME("Unhandled class %d\n", TimerInformationClass);
961 return STATUS_INVALID_INFO_CLASS;
965 /******************************************************************************
966 * NtQueryTimerResolution [NTDLL.@]
968 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
969 OUT ULONG* max_resolution,
970 OUT ULONG* current_resolution)
972 FIXME("(%p,%p,%p), stub!\n",
973 min_resolution, max_resolution, current_resolution);
975 return STATUS_NOT_IMPLEMENTED;
978 /******************************************************************************
979 * NtSetTimerResolution [NTDLL.@]
981 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
982 IN BOOLEAN set_resolution,
983 OUT ULONG* current_resolution )
985 FIXME("(%u,%u,%p), stub!\n",
986 resolution, set_resolution, current_resolution);
988 return STATUS_NOT_IMPLEMENTED;
993 /* wait operations */
995 static NTSTATUS wait_objects( DWORD count, const HANDLE *handles,
996 BOOLEAN wait_any, BOOLEAN alertable,
997 const LARGE_INTEGER *timeout )
999 select_op_t select_op;
1000 UINT i, flags = SELECT_INTERRUPTIBLE;
1002 if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
1004 if (alertable) flags |= SELECT_ALERTABLE;
1005 select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL;
1006 for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] );
1007 return server_select( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout );
1011 /******************************************************************
1012 * NtWaitForMultipleObjects (NTDLL.@)
1014 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
1015 BOOLEAN wait_any, BOOLEAN alertable,
1016 const LARGE_INTEGER *timeout )
1018 return wait_objects( count, handles, wait_any, alertable, timeout );
1022 /******************************************************************
1023 * NtWaitForSingleObject (NTDLL.@)
1025 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
1027 return wait_objects( 1, &handle, FALSE, alertable, timeout );
1031 /******************************************************************
1032 * NtSignalAndWaitForSingleObject (NTDLL.@)
1034 NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE hSignalObject, HANDLE hWaitObject,
1035 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1037 select_op_t select_op;
1038 UINT flags = SELECT_INTERRUPTIBLE;
1040 if (!hSignalObject) return STATUS_INVALID_HANDLE;
1042 if (alertable) flags |= SELECT_ALERTABLE;
1043 select_op.signal_and_wait.op = SELECT_SIGNAL_AND_WAIT;
1044 select_op.signal_and_wait.wait = wine_server_obj_handle( hWaitObject );
1045 select_op.signal_and_wait.signal = wine_server_obj_handle( hSignalObject );
1046 return server_select( &select_op, sizeof(select_op.signal_and_wait), flags, timeout );
1050 /******************************************************************
1051 * NtYieldExecution (NTDLL.@)
1053 NTSTATUS WINAPI NtYieldExecution(void)
1055 #ifdef HAVE_SCHED_YIELD
1056 sched_yield();
1057 return STATUS_SUCCESS;
1058 #else
1059 return STATUS_NO_YIELD_PERFORMED;
1060 #endif
1064 /******************************************************************
1065 * NtDelayExecution (NTDLL.@)
1067 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
1069 /* if alertable, we need to query the server */
1070 if (alertable)
1071 return server_select( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout );
1073 if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */
1075 for (;;) select( 0, NULL, NULL, NULL, NULL );
1077 else
1079 LARGE_INTEGER now;
1080 timeout_t when, diff;
1082 if ((when = timeout->QuadPart) < 0)
1084 NtQuerySystemTime( &now );
1085 when = now.QuadPart - when;
1088 /* Note that we yield after establishing the desired timeout */
1089 NtYieldExecution();
1090 if (!when) return STATUS_SUCCESS;
1092 for (;;)
1094 struct timeval tv;
1095 NtQuerySystemTime( &now );
1096 diff = (when - now.QuadPart + 9) / 10;
1097 if (diff <= 0) break;
1098 tv.tv_sec = diff / 1000000;
1099 tv.tv_usec = diff % 1000000;
1100 if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
1103 return STATUS_SUCCESS;
1107 /******************************************************************************
1108 * NtCreateKeyedEvent (NTDLL.@)
1110 NTSTATUS WINAPI NtCreateKeyedEvent( HANDLE *handle, ACCESS_MASK access,
1111 const OBJECT_ATTRIBUTES *attr, ULONG flags )
1113 NTSTATUS ret;
1114 data_size_t len;
1115 struct object_attributes *objattr;
1117 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1119 SERVER_START_REQ( create_keyed_event )
1121 req->access = access;
1122 wine_server_add_data( req, objattr, len );
1123 ret = wine_server_call( req );
1124 *handle = wine_server_ptr_handle( reply->handle );
1126 SERVER_END_REQ;
1128 RtlFreeHeap( GetProcessHeap(), 0, objattr );
1129 return ret;
1132 /******************************************************************************
1133 * NtOpenKeyedEvent (NTDLL.@)
1135 NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1137 NTSTATUS ret;
1139 if ((ret = validate_open_object_attributes( attr ))) return ret;
1141 SERVER_START_REQ( open_keyed_event )
1143 req->access = access;
1144 req->attributes = attr->Attributes;
1145 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1146 if (attr->ObjectName)
1147 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1148 ret = wine_server_call( req );
1149 *handle = wine_server_ptr_handle( reply->handle );
1151 SERVER_END_REQ;
1152 return ret;
1155 /******************************************************************************
1156 * NtWaitForKeyedEvent (NTDLL.@)
1158 NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
1159 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1161 select_op_t select_op;
1162 UINT flags = SELECT_INTERRUPTIBLE;
1164 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1165 if (alertable) flags |= SELECT_ALERTABLE;
1166 select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT;
1167 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1168 select_op.keyed_event.key = wine_server_client_ptr( key );
1169 return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1172 /******************************************************************************
1173 * NtReleaseKeyedEvent (NTDLL.@)
1175 NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key,
1176 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1178 select_op_t select_op;
1179 UINT flags = SELECT_INTERRUPTIBLE;
1181 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1182 if (alertable) flags |= SELECT_ALERTABLE;
1183 select_op.keyed_event.op = SELECT_KEYED_EVENT_RELEASE;
1184 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1185 select_op.keyed_event.key = wine_server_client_ptr( key );
1186 return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1189 /******************************************************************
1190 * NtCreateIoCompletion (NTDLL.@)
1191 * ZwCreateIoCompletion (NTDLL.@)
1193 * Creates I/O completion object.
1195 * PARAMS
1196 * CompletionPort [O] created completion object handle will be placed there
1197 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1198 * ObjectAttributes [I] completion object attributes
1199 * NumberOfConcurrentThreads [I] desired number of concurrent active worker threads
1202 NTSTATUS WINAPI NtCreateIoCompletion( PHANDLE CompletionPort, ACCESS_MASK DesiredAccess,
1203 POBJECT_ATTRIBUTES attr, ULONG NumberOfConcurrentThreads )
1205 NTSTATUS status;
1206 data_size_t len;
1207 struct object_attributes *objattr;
1209 TRACE("(%p, %x, %p, %d)\n", CompletionPort, DesiredAccess, attr, NumberOfConcurrentThreads);
1211 if (!CompletionPort)
1212 return STATUS_INVALID_PARAMETER;
1214 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
1216 SERVER_START_REQ( create_completion )
1218 req->access = DesiredAccess;
1219 req->concurrent = NumberOfConcurrentThreads;
1220 wine_server_add_data( req, objattr, len );
1221 if (!(status = wine_server_call( req )))
1222 *CompletionPort = wine_server_ptr_handle( reply->handle );
1224 SERVER_END_REQ;
1226 RtlFreeHeap( GetProcessHeap(), 0, objattr );
1227 return status;
1230 /******************************************************************
1231 * NtSetIoCompletion (NTDLL.@)
1232 * ZwSetIoCompletion (NTDLL.@)
1234 * Inserts completion message into queue
1236 * PARAMS
1237 * CompletionPort [I] HANDLE to completion object
1238 * CompletionKey [I] completion key
1239 * CompletionValue [I] completion value (usually pointer to OVERLAPPED)
1240 * Status [I] operation status
1241 * NumberOfBytesTransferred [I] number of bytes transferred
1243 NTSTATUS WINAPI NtSetIoCompletion( HANDLE CompletionPort, ULONG_PTR CompletionKey,
1244 ULONG_PTR CompletionValue, NTSTATUS Status,
1245 SIZE_T NumberOfBytesTransferred )
1247 NTSTATUS status;
1249 TRACE("(%p, %lx, %lx, %x, %lx)\n", CompletionPort, CompletionKey,
1250 CompletionValue, Status, NumberOfBytesTransferred);
1252 SERVER_START_REQ( add_completion )
1254 req->handle = wine_server_obj_handle( CompletionPort );
1255 req->ckey = CompletionKey;
1256 req->cvalue = CompletionValue;
1257 req->status = Status;
1258 req->information = NumberOfBytesTransferred;
1259 status = wine_server_call( req );
1261 SERVER_END_REQ;
1262 return status;
1265 /******************************************************************
1266 * NtRemoveIoCompletion (NTDLL.@)
1267 * ZwRemoveIoCompletion (NTDLL.@)
1269 * (Wait for and) retrieve first completion message from completion object's queue
1271 * PARAMS
1272 * CompletionPort [I] HANDLE to I/O completion object
1273 * CompletionKey [O] completion key
1274 * CompletionValue [O] Completion value given in NtSetIoCompletion or in async operation
1275 * iosb [O] IO_STATUS_BLOCK of completed asynchronous operation
1276 * WaitTime [I] optional wait time in NTDLL format
1279 NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE CompletionPort, PULONG_PTR CompletionKey,
1280 PULONG_PTR CompletionValue, PIO_STATUS_BLOCK iosb,
1281 PLARGE_INTEGER WaitTime )
1283 NTSTATUS status;
1285 TRACE("(%p, %p, %p, %p, %p)\n", CompletionPort, CompletionKey,
1286 CompletionValue, iosb, WaitTime);
1288 for(;;)
1290 SERVER_START_REQ( remove_completion )
1292 req->handle = wine_server_obj_handle( CompletionPort );
1293 if (!(status = wine_server_call( req )))
1295 *CompletionKey = reply->ckey;
1296 *CompletionValue = reply->cvalue;
1297 iosb->Information = reply->information;
1298 iosb->u.Status = reply->status;
1301 SERVER_END_REQ;
1302 if (status != STATUS_PENDING) break;
1304 status = NtWaitForSingleObject( CompletionPort, FALSE, WaitTime );
1305 if (status != WAIT_OBJECT_0) break;
1307 return status;
1310 /******************************************************************
1311 * NtOpenIoCompletion (NTDLL.@)
1312 * ZwOpenIoCompletion (NTDLL.@)
1314 * Opens I/O completion object
1316 * PARAMS
1317 * CompletionPort [O] completion object handle will be placed there
1318 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1319 * ObjectAttributes [I] completion object name
1322 NTSTATUS WINAPI NtOpenIoCompletion( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1324 NTSTATUS status;
1326 if (!handle) return STATUS_INVALID_PARAMETER;
1327 if ((status = validate_open_object_attributes( attr ))) return status;
1329 SERVER_START_REQ( open_completion )
1331 req->access = access;
1332 req->attributes = attr->Attributes;
1333 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1334 if (attr->ObjectName)
1335 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1336 status = wine_server_call( req );
1337 *handle = wine_server_ptr_handle( reply->handle );
1339 SERVER_END_REQ;
1340 return status;
1343 /******************************************************************
1344 * NtQueryIoCompletion (NTDLL.@)
1345 * ZwQueryIoCompletion (NTDLL.@)
1347 * Requests information about given I/O completion object
1349 * PARAMS
1350 * CompletionPort [I] HANDLE to completion port to request
1351 * InformationClass [I] information class
1352 * CompletionInformation [O] user-provided buffer for data
1353 * BufferLength [I] buffer length
1354 * RequiredLength [O] required buffer length
1357 NTSTATUS WINAPI NtQueryIoCompletion( HANDLE CompletionPort, IO_COMPLETION_INFORMATION_CLASS InformationClass,
1358 PVOID CompletionInformation, ULONG BufferLength, PULONG RequiredLength )
1360 NTSTATUS status;
1362 TRACE("(%p, %d, %p, 0x%x, %p)\n", CompletionPort, InformationClass, CompletionInformation,
1363 BufferLength, RequiredLength);
1365 if (!CompletionInformation) return STATUS_INVALID_PARAMETER;
1366 switch( InformationClass )
1368 case IoCompletionBasicInformation:
1370 ULONG *info = CompletionInformation;
1372 if (RequiredLength) *RequiredLength = sizeof(*info);
1373 if (BufferLength != sizeof(*info))
1374 status = STATUS_INFO_LENGTH_MISMATCH;
1375 else
1377 SERVER_START_REQ( query_completion )
1379 req->handle = wine_server_obj_handle( CompletionPort );
1380 if (!(status = wine_server_call( req )))
1381 *info = reply->depth;
1383 SERVER_END_REQ;
1386 break;
1387 default:
1388 status = STATUS_INVALID_PARAMETER;
1389 break;
1391 return status;
1394 NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue,
1395 NTSTATUS CompletionStatus, ULONG Information )
1397 NTSTATUS status;
1399 SERVER_START_REQ( add_fd_completion )
1401 req->handle = wine_server_obj_handle( hFile );
1402 req->cvalue = CompletionValue;
1403 req->status = CompletionStatus;
1404 req->information = Information;
1405 status = wine_server_call( req );
1407 SERVER_END_REQ;
1408 return status;
1411 /******************************************************************
1412 * RtlRunOnceInitialize (NTDLL.@)
1414 void WINAPI RtlRunOnceInitialize( RTL_RUN_ONCE *once )
1416 once->Ptr = NULL;
1419 /******************************************************************
1420 * RtlRunOnceBeginInitialize (NTDLL.@)
1422 DWORD WINAPI RtlRunOnceBeginInitialize( RTL_RUN_ONCE *once, ULONG flags, void **context )
1424 if (flags & RTL_RUN_ONCE_CHECK_ONLY)
1426 ULONG_PTR val = (ULONG_PTR)once->Ptr;
1428 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1429 if ((val & 3) != 2) return STATUS_UNSUCCESSFUL;
1430 if (context) *context = (void *)(val & ~3);
1431 return STATUS_SUCCESS;
1434 for (;;)
1436 ULONG_PTR next, val = (ULONG_PTR)once->Ptr;
1438 switch (val & 3)
1440 case 0: /* first time */
1441 if (!interlocked_cmpxchg_ptr( &once->Ptr,
1442 (flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0 ))
1443 return STATUS_PENDING;
1444 break;
1446 case 1: /* in progress, wait */
1447 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1448 next = val & ~3;
1449 if (interlocked_cmpxchg_ptr( &once->Ptr, (void *)((ULONG_PTR)&next | 1),
1450 (void *)val ) == (void *)val)
1451 NtWaitForKeyedEvent( keyed_event, &next, FALSE, NULL );
1452 break;
1454 case 2: /* done */
1455 if (context) *context = (void *)(val & ~3);
1456 return STATUS_SUCCESS;
1458 case 3: /* in progress, async */
1459 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
1460 return STATUS_PENDING;
1465 /******************************************************************
1466 * RtlRunOnceComplete (NTDLL.@)
1468 DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context )
1470 if ((ULONG_PTR)context & 3) return STATUS_INVALID_PARAMETER;
1472 if (flags & RTL_RUN_ONCE_INIT_FAILED)
1474 if (context) return STATUS_INVALID_PARAMETER;
1475 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1477 else context = (void *)((ULONG_PTR)context | 2);
1479 for (;;)
1481 ULONG_PTR val = (ULONG_PTR)once->Ptr;
1483 switch (val & 3)
1485 case 1: /* in progress */
1486 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break;
1487 val &= ~3;
1488 while (val)
1490 ULONG_PTR next = *(ULONG_PTR *)val;
1491 NtReleaseKeyedEvent( keyed_event, (void *)val, FALSE, NULL );
1492 val = next;
1494 return STATUS_SUCCESS;
1496 case 3: /* in progress, async */
1497 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
1498 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break;
1499 return STATUS_SUCCESS;
1501 default:
1502 return STATUS_UNSUCCESSFUL;
1507 /******************************************************************
1508 * RtlRunOnceExecuteOnce (NTDLL.@)
1510 DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN func,
1511 void *param, void **context )
1513 DWORD ret = RtlRunOnceBeginInitialize( once, 0, context );
1515 if (ret != STATUS_PENDING) return ret;
1517 if (!func( once, param, context ))
1519 RtlRunOnceComplete( once, RTL_RUN_ONCE_INIT_FAILED, NULL );
1520 return STATUS_UNSUCCESSFUL;
1523 return RtlRunOnceComplete( once, 0, context ? *context : NULL );
1527 /* SRW locks implementation
1529 * The memory layout used by the lock is:
1531 * 32 31 16 0
1532 * ________________ ________________
1533 * | X| #exclusive | #shared |
1534 * ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
1535 * Since there is no space left for a separate counter of shared access
1536 * threads inside the locked section the #shared field is used for multiple
1537 * purposes. The following table lists all possible states the lock can be
1538 * in, notation: [X, #exclusive, #shared]:
1540 * [0, 0, N] -> locked by N shared access threads, if N=0 it's unlocked
1541 * [0, >=1, >=1] -> threads are requesting exclusive locks, but there are
1542 * still shared access threads inside. #shared should not be incremented
1543 * anymore!
1544 * [1, >=1, >=0] -> lock is owned by an exclusive thread and the #shared
1545 * counter can be used again to count the number of threads waiting in the
1546 * queue for shared access.
1548 * the following states are invalid and will never occur:
1549 * [0, >=1, 0], [1, 0, >=0]
1551 * The main problem arising from the fact that we have no separate counter
1552 * of shared access threads inside the locked section is that in the state
1553 * [0, >=1, >=1] above we cannot add additional waiting threads to the
1554 * shared access queue - it wouldn't be possible to distinguish waiting
1555 * threads and those that are still inside. To solve this problem the lock
1556 * uses the following approach: a thread that isn't able to allocate a
1557 * shared lock just uses the exclusive queue instead. As soon as the thread
1558 * is woken up it is in the state [1, >=1, >=0]. In this state it's again
1559 * possible to use the shared access queue. The thread atomically moves
1560 * itself to the shared access queue and releases the exclusive lock, so
1561 * that the "real" exclusive access threads have a chance. As soon as they
1562 * are all ready the shared access threads are processed.
1565 #define SRWLOCK_MASK_IN_EXCLUSIVE 0x80000000
1566 #define SRWLOCK_MASK_EXCLUSIVE_QUEUE 0x7fff0000
1567 #define SRWLOCK_MASK_SHARED_QUEUE 0x0000ffff
1568 #define SRWLOCK_RES_EXCLUSIVE 0x00010000
1569 #define SRWLOCK_RES_SHARED 0x00000001
1571 #ifdef WORDS_BIGENDIAN
1572 #define srwlock_key_exclusive(lock) (&lock->Ptr)
1573 #define srwlock_key_shared(lock) ((void *)((char *)&lock->Ptr + 2))
1574 #else
1575 #define srwlock_key_exclusive(lock) ((void *)((char *)&lock->Ptr + 2))
1576 #define srwlock_key_shared(lock) (&lock->Ptr)
1577 #endif
1579 static inline void srwlock_check_invalid( unsigned int val )
1581 /* Throw exception if it's impossible to acquire/release this lock. */
1582 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) == SRWLOCK_MASK_EXCLUSIVE_QUEUE ||
1583 (val & SRWLOCK_MASK_SHARED_QUEUE) == SRWLOCK_MASK_SHARED_QUEUE)
1584 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED);
1587 static inline unsigned int srwlock_lock_exclusive( unsigned int *dest, int incr )
1589 unsigned int val, tmp;
1590 /* Atomically modifies the value of *dest by adding incr. If the shared
1591 * queue is empty and there are threads waiting for exclusive access, then
1592 * sets the mark SRWLOCK_MASK_IN_EXCLUSIVE to signal other threads that
1593 * they are allowed again to use the shared queue counter. */
1594 for (val = *dest;; val = tmp)
1596 tmp = val + incr;
1597 srwlock_check_invalid( tmp );
1598 if ((tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(tmp & SRWLOCK_MASK_SHARED_QUEUE))
1599 tmp |= SRWLOCK_MASK_IN_EXCLUSIVE;
1600 if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val)
1601 break;
1603 return val;
1606 static inline unsigned int srwlock_unlock_exclusive( unsigned int *dest, int incr )
1608 unsigned int val, tmp;
1609 /* Atomically modifies the value of *dest by adding incr. If the queue of
1610 * threads waiting for exclusive access is empty, then remove the
1611 * SRWLOCK_MASK_IN_EXCLUSIVE flag (only the shared queue counter will
1612 * remain). */
1613 for (val = *dest;; val = tmp)
1615 tmp = val + incr;
1616 srwlock_check_invalid( tmp );
1617 if (!(tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE))
1618 tmp &= SRWLOCK_MASK_SHARED_QUEUE;
1619 if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val)
1620 break;
1622 return val;
1625 static inline void srwlock_leave_exclusive( RTL_SRWLOCK *lock, unsigned int val )
1627 /* Used when a thread leaves an exclusive section. If there are other
1628 * exclusive access threads they are processed first, followed by
1629 * the shared waiters. */
1630 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
1631 NtReleaseKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1632 else
1634 val &= SRWLOCK_MASK_SHARED_QUEUE; /* remove SRWLOCK_MASK_IN_EXCLUSIVE */
1635 while (val--)
1636 NtReleaseKeyedEvent( keyed_event, srwlock_key_shared(lock), FALSE, NULL );
1640 static inline void srwlock_leave_shared( RTL_SRWLOCK *lock, unsigned int val )
1642 /* Wake up one exclusive thread as soon as the last shared access thread
1643 * has left. */
1644 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_SHARED_QUEUE))
1645 NtReleaseKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1648 /***********************************************************************
1649 * RtlInitializeSRWLock (NTDLL.@)
1651 * NOTES
1652 * Please note that SRWLocks do not keep track of the owner of a lock.
1653 * It doesn't make any difference which thread for example unlocks an
1654 * SRWLock (see corresponding tests). This implementation uses two
1655 * keyed events (one for the exclusive waiters and one for the shared
1656 * waiters) and is limited to 2^15-1 waiting threads.
1658 void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock )
1660 lock->Ptr = NULL;
1663 /***********************************************************************
1664 * RtlAcquireSRWLockExclusive (NTDLL.@)
1666 * NOTES
1667 * Unlike RtlAcquireResourceExclusive this function doesn't allow
1668 * nested calls from the same thread. "Upgrading" a shared access lock
1669 * to an exclusive access lock also doesn't seem to be supported.
1671 void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
1673 if (srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, SRWLOCK_RES_EXCLUSIVE ))
1674 NtWaitForKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1677 /***********************************************************************
1678 * RtlAcquireSRWLockShared (NTDLL.@)
1680 * NOTES
1681 * Do not call this function recursively - it will only succeed when
1682 * there are no threads waiting for an exclusive lock!
1684 void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
1686 unsigned int val, tmp;
1687 /* Acquires a shared lock. If it's currently not possible to add elements to
1688 * the shared queue, then request exclusive access instead. */
1689 for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
1691 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
1692 tmp = val + SRWLOCK_RES_EXCLUSIVE;
1693 else
1694 tmp = val + SRWLOCK_RES_SHARED;
1695 if ((tmp = interlocked_cmpxchg( (int *)&lock->Ptr, tmp, val )) == val)
1696 break;
1699 /* Drop exclusive access again and instead requeue for shared access. */
1700 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
1702 NtWaitForKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1703 val = srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr, (SRWLOCK_RES_SHARED
1704 - SRWLOCK_RES_EXCLUSIVE) ) - SRWLOCK_RES_EXCLUSIVE;
1705 srwlock_leave_exclusive( lock, val );
1708 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
1709 NtWaitForKeyedEvent( keyed_event, srwlock_key_shared(lock), FALSE, NULL );
1712 /***********************************************************************
1713 * RtlReleaseSRWLockExclusive (NTDLL.@)
1715 void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
1717 srwlock_leave_exclusive( lock, srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr,
1718 - SRWLOCK_RES_EXCLUSIVE ) - SRWLOCK_RES_EXCLUSIVE );
1721 /***********************************************************************
1722 * RtlReleaseSRWLockShared (NTDLL.@)
1724 void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
1726 srwlock_leave_shared( lock, srwlock_lock_exclusive( (unsigned int *)&lock->Ptr,
1727 - SRWLOCK_RES_SHARED ) - SRWLOCK_RES_SHARED );
1730 /***********************************************************************
1731 * RtlTryAcquireSRWLockExclusive (NTDLL.@)
1733 * NOTES
1734 * Similar to AcquireSRWLockExclusive recusive calls are not allowed
1735 * and will fail with return value FALSE.
1737 BOOLEAN WINAPI RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
1739 return interlocked_cmpxchg( (int *)&lock->Ptr, SRWLOCK_MASK_IN_EXCLUSIVE |
1740 SRWLOCK_RES_EXCLUSIVE, 0 ) == 0;
1743 /***********************************************************************
1744 * RtlTryAcquireSRWLockShared (NTDLL.@)
1746 BOOLEAN WINAPI RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock )
1748 unsigned int val, tmp;
1749 for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
1751 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
1752 return FALSE;
1753 if ((tmp = interlocked_cmpxchg( (int *)&lock->Ptr, val + SRWLOCK_RES_SHARED, val )) == val)
1754 break;
1756 return TRUE;
1759 /***********************************************************************
1760 * RtlInitializeConditionVariable (NTDLL.@)
1762 * Initializes the condition variable with NULL.
1764 * PARAMS
1765 * variable [O] condition variable
1767 * RETURNS
1768 * Nothing.
1770 void WINAPI RtlInitializeConditionVariable( RTL_CONDITION_VARIABLE *variable )
1772 variable->Ptr = NULL;
1775 /***********************************************************************
1776 * RtlWakeConditionVariable (NTDLL.@)
1778 * Wakes up one thread waiting on the condition variable.
1780 * PARAMS
1781 * variable [I/O] condition variable to wake up.
1783 * RETURNS
1784 * Nothing.
1786 * NOTES
1787 * The calling thread does not have to own any lock in order to call
1788 * this function.
1790 void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable )
1792 if (interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
1793 NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1796 /***********************************************************************
1797 * RtlWakeAllConditionVariable (NTDLL.@)
1799 * See WakeConditionVariable, wakes up all waiting threads.
1801 void WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *variable )
1803 int val = interlocked_xchg( (int *)&variable->Ptr, 0 );
1804 while (val-- > 0)
1805 NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1808 /***********************************************************************
1809 * RtlSleepConditionVariableCS (NTDLL.@)
1811 * Atomically releases the critical section and suspends the thread,
1812 * waiting for a Wake(All)ConditionVariable event. Afterwards it enters
1813 * the critical section again and returns.
1815 * PARAMS
1816 * variable [I/O] condition variable
1817 * crit [I/O] critical section to leave temporarily
1818 * timeout [I] timeout
1820 * RETURNS
1821 * see NtWaitForKeyedEvent for all possible return values.
1823 NTSTATUS WINAPI RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, RTL_CRITICAL_SECTION *crit,
1824 const LARGE_INTEGER *timeout )
1826 NTSTATUS status;
1827 interlocked_xchg_add( (int *)&variable->Ptr, 1 );
1828 RtlLeaveCriticalSection( crit );
1830 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, timeout );
1831 if (status != STATUS_SUCCESS)
1833 if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
1834 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1837 RtlEnterCriticalSection( crit );
1838 return status;
1841 /***********************************************************************
1842 * RtlSleepConditionVariableSRW (NTDLL.@)
1844 * Atomically releases the SRWLock and suspends the thread,
1845 * waiting for a Wake(All)ConditionVariable event. Afterwards it enters
1846 * the SRWLock again with the same access rights and returns.
1848 * PARAMS
1849 * variable [I/O] condition variable
1850 * lock [I/O] SRWLock to leave temporarily
1851 * timeout [I] timeout
1852 * flags [I] type of the current lock (exclusive / shared)
1854 * RETURNS
1855 * see NtWaitForKeyedEvent for all possible return values.
1857 * NOTES
1858 * the behaviour is undefined if the thread doesn't own the lock.
1860 NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, RTL_SRWLOCK *lock,
1861 const LARGE_INTEGER *timeout, ULONG flags )
1863 NTSTATUS status;
1864 interlocked_xchg_add( (int *)&variable->Ptr, 1 );
1866 if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
1867 RtlReleaseSRWLockShared( lock );
1868 else
1869 RtlReleaseSRWLockExclusive( lock );
1871 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, timeout );
1872 if (status != STATUS_SUCCESS)
1874 if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
1875 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1878 if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
1879 RtlAcquireSRWLockShared( lock );
1880 else
1881 RtlAcquireSRWLockExclusive( lock );
1882 return status;