mshtml/tests: Added more ownerDocument property tests.
[wine.git] / dlls / ntdll / sync.c
blob8e406ceaebeec8ca3d9e398deaf3cad4acd403d5
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 = NULL, group = NULL;
81 ACL *dacl, *sacl;
82 BOOLEAN 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, &defaulted ))) return status;
98 if ((status = RtlGetGroupSecurityDescriptor( sd, &group, &defaulted ))) 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) len += RtlLengthSid( owner );
102 if (group) 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) descr->owner_len = RtlLengthSid( owner );
130 if (group) 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 JobObjectBasicAccountingInformation:
650 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION *accounting;
651 if (len < sizeof(*accounting))
652 return STATUS_INFO_LENGTH_MISMATCH;
654 accounting = (JOBOBJECT_BASIC_ACCOUNTING_INFORMATION *)info;
655 memset(accounting, 0, sizeof(*accounting));
656 if (ret_len) *ret_len = sizeof(*accounting);
657 return STATUS_SUCCESS;
660 case JobObjectBasicProcessIdList:
662 JOBOBJECT_BASIC_PROCESS_ID_LIST *process;
663 if (len < sizeof(*process))
664 return STATUS_INFO_LENGTH_MISMATCH;
666 process = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)info;
667 memset(process, 0, sizeof(*process));
668 if (ret_len) *ret_len = sizeof(*process);
669 return STATUS_SUCCESS;
672 case JobObjectExtendedLimitInformation:
674 JOBOBJECT_EXTENDED_LIMIT_INFORMATION *extended_limit;
675 if (len < sizeof(*extended_limit))
676 return STATUS_INFO_LENGTH_MISMATCH;
678 extended_limit = (JOBOBJECT_EXTENDED_LIMIT_INFORMATION *)info;
679 memset(extended_limit, 0, sizeof(*extended_limit));
680 if (ret_len) *ret_len = sizeof(*extended_limit);
681 return STATUS_SUCCESS;
684 case JobObjectBasicLimitInformation:
686 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit;
687 if (len < sizeof(*basic_limit))
688 return STATUS_INFO_LENGTH_MISMATCH;
690 basic_limit = (JOBOBJECT_BASIC_LIMIT_INFORMATION *)info;
691 memset(basic_limit, 0, sizeof(*basic_limit));
692 if (ret_len) *ret_len = sizeof(*basic_limit);
693 return STATUS_SUCCESS;
696 default:
697 return STATUS_NOT_IMPLEMENTED;
701 /******************************************************************************
702 * NtSetInformationJobObject [NTDLL.@]
703 * ZwSetInformationJobObject [NTDLL.@]
705 NTSTATUS WINAPI NtSetInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info, ULONG len )
707 NTSTATUS status = STATUS_NOT_IMPLEMENTED;
708 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit;
709 ULONG info_size = sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION);
710 DWORD limit_flags = JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS;
712 TRACE( "(%p, %u, %p, %u)\n", handle, class, info, len );
714 if (class >= MaxJobObjectInfoClass)
715 return STATUS_INVALID_PARAMETER;
717 switch (class)
720 case JobObjectExtendedLimitInformation:
721 info_size = sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION);
722 limit_flags = JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS;
723 /* fallthrough */
724 case JobObjectBasicLimitInformation:
725 if (len != info_size)
726 return STATUS_INVALID_PARAMETER;
728 basic_limit = info;
729 if (basic_limit->LimitFlags & ~limit_flags)
730 return STATUS_INVALID_PARAMETER;
732 SERVER_START_REQ( set_job_limits )
734 req->handle = wine_server_obj_handle( handle );
735 req->limit_flags = basic_limit->LimitFlags;
736 status = wine_server_call( req );
738 SERVER_END_REQ;
739 break;
741 case JobObjectAssociateCompletionPortInformation:
742 if (len != sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT))
743 return STATUS_INVALID_PARAMETER;
745 SERVER_START_REQ( set_job_completion_port )
747 JOBOBJECT_ASSOCIATE_COMPLETION_PORT *port_info = info;
748 req->job = wine_server_obj_handle( handle );
749 req->port = wine_server_obj_handle( port_info->CompletionPort );
750 req->key = wine_server_client_ptr( port_info->CompletionKey );
751 status = wine_server_call(req);
753 SERVER_END_REQ;
754 break;
756 case JobObjectBasicUIRestrictions:
757 status = STATUS_SUCCESS;
758 /* fallthrough */
759 default:
760 FIXME( "stub: %p %u %p %u\n", handle, class, info, len );
763 return status;
766 /******************************************************************************
767 * NtIsProcessInJob [NTDLL.@]
768 * ZwIsProcessInJob [NTDLL.@]
770 NTSTATUS WINAPI NtIsProcessInJob( HANDLE process, HANDLE job )
772 NTSTATUS status;
774 TRACE( "(%p %p)\n", job, process );
776 SERVER_START_REQ( process_in_job )
778 req->job = wine_server_obj_handle( job );
779 req->process = wine_server_obj_handle( process );
780 status = wine_server_call( req );
782 SERVER_END_REQ;
784 return status;
787 /******************************************************************************
788 * NtAssignProcessToJobObject [NTDLL.@]
789 * ZwAssignProcessToJobObject [NTDLL.@]
791 NTSTATUS WINAPI NtAssignProcessToJobObject( HANDLE job, HANDLE process )
793 NTSTATUS status;
795 TRACE( "(%p %p)\n", job, process );
797 SERVER_START_REQ( assign_job )
799 req->job = wine_server_obj_handle( job );
800 req->process = wine_server_obj_handle( process );
801 status = wine_server_call( req );
803 SERVER_END_REQ;
805 return status;
809 * Timers
812 /**************************************************************************
813 * NtCreateTimer [NTDLL.@]
814 * ZwCreateTimer [NTDLL.@]
816 NTSTATUS WINAPI NtCreateTimer(OUT HANDLE *handle,
817 IN ACCESS_MASK access,
818 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
819 IN TIMER_TYPE timer_type)
821 NTSTATUS status;
822 data_size_t len;
823 struct object_attributes *objattr;
825 if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
826 return STATUS_INVALID_PARAMETER;
828 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
830 SERVER_START_REQ( create_timer )
832 req->access = access;
833 req->manual = (timer_type == NotificationTimer);
834 wine_server_add_data( req, objattr, len );
835 status = wine_server_call( req );
836 *handle = wine_server_ptr_handle( reply->handle );
838 SERVER_END_REQ;
840 RtlFreeHeap( GetProcessHeap(), 0, objattr );
841 return status;
845 /**************************************************************************
846 * NtOpenTimer [NTDLL.@]
847 * ZwOpenTimer [NTDLL.@]
849 NTSTATUS WINAPI NtOpenTimer( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
851 NTSTATUS status;
853 if ((status = validate_open_object_attributes( attr ))) return status;
855 SERVER_START_REQ( open_timer )
857 req->access = access;
858 req->attributes = attr->Attributes;
859 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
860 if (attr->ObjectName)
861 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
862 status = wine_server_call( req );
863 *handle = wine_server_ptr_handle( reply->handle );
865 SERVER_END_REQ;
866 return status;
869 /**************************************************************************
870 * NtSetTimer [NTDLL.@]
871 * ZwSetTimer [NTDLL.@]
873 NTSTATUS WINAPI NtSetTimer(IN HANDLE handle,
874 IN const LARGE_INTEGER* when,
875 IN PTIMER_APC_ROUTINE callback,
876 IN PVOID callback_arg,
877 IN BOOLEAN resume,
878 IN ULONG period OPTIONAL,
879 OUT PBOOLEAN state OPTIONAL)
881 NTSTATUS status = STATUS_SUCCESS;
883 TRACE("(%p,%p,%p,%p,%08x,0x%08x,%p)\n",
884 handle, when, callback, callback_arg, resume, period, state);
886 SERVER_START_REQ( set_timer )
888 req->handle = wine_server_obj_handle( handle );
889 req->period = period;
890 req->expire = when->QuadPart;
891 req->callback = wine_server_client_ptr( callback );
892 req->arg = wine_server_client_ptr( callback_arg );
893 status = wine_server_call( req );
894 if (state) *state = reply->signaled;
896 SERVER_END_REQ;
898 /* set error but can still succeed */
899 if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
900 return status;
903 /**************************************************************************
904 * NtCancelTimer [NTDLL.@]
905 * ZwCancelTimer [NTDLL.@]
907 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
909 NTSTATUS status;
911 SERVER_START_REQ( cancel_timer )
913 req->handle = wine_server_obj_handle( handle );
914 status = wine_server_call( req );
915 if (state) *state = reply->signaled;
917 SERVER_END_REQ;
918 return status;
921 /******************************************************************************
922 * NtQueryTimer (NTDLL.@)
924 * Retrieves information about a timer.
926 * PARAMS
927 * TimerHandle [I] The timer to retrieve information about.
928 * TimerInformationClass [I] The type of information to retrieve.
929 * TimerInformation [O] Pointer to buffer to store information in.
930 * Length [I] The length of the buffer pointed to by TimerInformation.
931 * ReturnLength [O] Optional. The size of buffer actually used.
933 * RETURNS
934 * Success: STATUS_SUCCESS
935 * Failure: STATUS_INFO_LENGTH_MISMATCH, if Length doesn't match the required data
936 * size for the class specified.
937 * STATUS_INVALID_INFO_CLASS, if an invalid TimerInformationClass was specified.
938 * STATUS_ACCESS_DENIED, if TimerHandle does not have TIMER_QUERY_STATE access
939 * to the timer.
941 NTSTATUS WINAPI NtQueryTimer(
942 HANDLE TimerHandle,
943 TIMER_INFORMATION_CLASS TimerInformationClass,
944 PVOID TimerInformation,
945 ULONG Length,
946 PULONG ReturnLength)
948 TIMER_BASIC_INFORMATION * basic_info = TimerInformation;
949 NTSTATUS status;
950 LARGE_INTEGER now;
952 TRACE("(%p,%d,%p,0x%08x,%p)\n", TimerHandle, TimerInformationClass,
953 TimerInformation, Length, ReturnLength);
955 switch (TimerInformationClass)
957 case TimerBasicInformation:
958 if (Length < sizeof(TIMER_BASIC_INFORMATION))
959 return STATUS_INFO_LENGTH_MISMATCH;
961 SERVER_START_REQ(get_timer_info)
963 req->handle = wine_server_obj_handle( TimerHandle );
964 status = wine_server_call(req);
966 /* convert server time to absolute NTDLL time */
967 basic_info->RemainingTime.QuadPart = reply->when;
968 basic_info->TimerState = reply->signaled;
970 SERVER_END_REQ;
972 /* convert from absolute into relative time */
973 NtQuerySystemTime(&now);
974 if (now.QuadPart > basic_info->RemainingTime.QuadPart)
975 basic_info->RemainingTime.QuadPart = 0;
976 else
977 basic_info->RemainingTime.QuadPart -= now.QuadPart;
979 if (ReturnLength) *ReturnLength = sizeof(TIMER_BASIC_INFORMATION);
981 return status;
984 FIXME("Unhandled class %d\n", TimerInformationClass);
985 return STATUS_INVALID_INFO_CLASS;
989 /******************************************************************************
990 * NtQueryTimerResolution [NTDLL.@]
992 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
993 OUT ULONG* max_resolution,
994 OUT ULONG* current_resolution)
996 FIXME("(%p,%p,%p), stub!\n",
997 min_resolution, max_resolution, current_resolution);
999 return STATUS_NOT_IMPLEMENTED;
1002 /******************************************************************************
1003 * NtSetTimerResolution [NTDLL.@]
1005 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
1006 IN BOOLEAN set_resolution,
1007 OUT ULONG* current_resolution )
1009 FIXME("(%u,%u,%p), stub!\n",
1010 resolution, set_resolution, current_resolution);
1012 return STATUS_NOT_IMPLEMENTED;
1017 /* wait operations */
1019 static NTSTATUS wait_objects( DWORD count, const HANDLE *handles,
1020 BOOLEAN wait_any, BOOLEAN alertable,
1021 const LARGE_INTEGER *timeout )
1023 select_op_t select_op;
1024 UINT i, flags = SELECT_INTERRUPTIBLE;
1026 if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
1028 if (alertable) flags |= SELECT_ALERTABLE;
1029 select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL;
1030 for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] );
1031 return server_select( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout );
1035 /******************************************************************
1036 * NtWaitForMultipleObjects (NTDLL.@)
1038 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
1039 BOOLEAN wait_any, BOOLEAN alertable,
1040 const LARGE_INTEGER *timeout )
1042 return wait_objects( count, handles, wait_any, alertable, timeout );
1046 /******************************************************************
1047 * NtWaitForSingleObject (NTDLL.@)
1049 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
1051 return wait_objects( 1, &handle, FALSE, alertable, timeout );
1055 /******************************************************************
1056 * NtSignalAndWaitForSingleObject (NTDLL.@)
1058 NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE hSignalObject, HANDLE hWaitObject,
1059 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1061 select_op_t select_op;
1062 UINT flags = SELECT_INTERRUPTIBLE;
1064 if (!hSignalObject) return STATUS_INVALID_HANDLE;
1066 if (alertable) flags |= SELECT_ALERTABLE;
1067 select_op.signal_and_wait.op = SELECT_SIGNAL_AND_WAIT;
1068 select_op.signal_and_wait.wait = wine_server_obj_handle( hWaitObject );
1069 select_op.signal_and_wait.signal = wine_server_obj_handle( hSignalObject );
1070 return server_select( &select_op, sizeof(select_op.signal_and_wait), flags, timeout );
1074 /******************************************************************
1075 * NtYieldExecution (NTDLL.@)
1077 NTSTATUS WINAPI NtYieldExecution(void)
1079 #ifdef HAVE_SCHED_YIELD
1080 sched_yield();
1081 return STATUS_SUCCESS;
1082 #else
1083 return STATUS_NO_YIELD_PERFORMED;
1084 #endif
1088 /******************************************************************
1089 * NtDelayExecution (NTDLL.@)
1091 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
1093 /* if alertable, we need to query the server */
1094 if (alertable)
1095 return server_select( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout );
1097 if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */
1099 for (;;) select( 0, NULL, NULL, NULL, NULL );
1101 else
1103 LARGE_INTEGER now;
1104 timeout_t when, diff;
1106 if ((when = timeout->QuadPart) < 0)
1108 NtQuerySystemTime( &now );
1109 when = now.QuadPart - when;
1112 /* Note that we yield after establishing the desired timeout */
1113 NtYieldExecution();
1114 if (!when) return STATUS_SUCCESS;
1116 for (;;)
1118 struct timeval tv;
1119 NtQuerySystemTime( &now );
1120 diff = (when - now.QuadPart + 9) / 10;
1121 if (diff <= 0) break;
1122 tv.tv_sec = diff / 1000000;
1123 tv.tv_usec = diff % 1000000;
1124 if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
1127 return STATUS_SUCCESS;
1131 /******************************************************************************
1132 * NtCreateKeyedEvent (NTDLL.@)
1134 NTSTATUS WINAPI NtCreateKeyedEvent( HANDLE *handle, ACCESS_MASK access,
1135 const OBJECT_ATTRIBUTES *attr, ULONG flags )
1137 NTSTATUS ret;
1138 data_size_t len;
1139 struct object_attributes *objattr;
1141 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1143 SERVER_START_REQ( create_keyed_event )
1145 req->access = access;
1146 wine_server_add_data( req, objattr, len );
1147 ret = wine_server_call( req );
1148 *handle = wine_server_ptr_handle( reply->handle );
1150 SERVER_END_REQ;
1152 RtlFreeHeap( GetProcessHeap(), 0, objattr );
1153 return ret;
1156 /******************************************************************************
1157 * NtOpenKeyedEvent (NTDLL.@)
1159 NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1161 NTSTATUS ret;
1163 if ((ret = validate_open_object_attributes( attr ))) return ret;
1165 SERVER_START_REQ( open_keyed_event )
1167 req->access = access;
1168 req->attributes = attr->Attributes;
1169 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1170 if (attr->ObjectName)
1171 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1172 ret = wine_server_call( req );
1173 *handle = wine_server_ptr_handle( reply->handle );
1175 SERVER_END_REQ;
1176 return ret;
1179 /******************************************************************************
1180 * NtWaitForKeyedEvent (NTDLL.@)
1182 NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
1183 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1185 select_op_t select_op;
1186 UINT flags = SELECT_INTERRUPTIBLE;
1188 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1189 if (alertable) flags |= SELECT_ALERTABLE;
1190 select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT;
1191 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1192 select_op.keyed_event.key = wine_server_client_ptr( key );
1193 return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1196 /******************************************************************************
1197 * NtReleaseKeyedEvent (NTDLL.@)
1199 NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key,
1200 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1202 select_op_t select_op;
1203 UINT flags = SELECT_INTERRUPTIBLE;
1205 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1206 if (alertable) flags |= SELECT_ALERTABLE;
1207 select_op.keyed_event.op = SELECT_KEYED_EVENT_RELEASE;
1208 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1209 select_op.keyed_event.key = wine_server_client_ptr( key );
1210 return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1213 /******************************************************************
1214 * NtCreateIoCompletion (NTDLL.@)
1215 * ZwCreateIoCompletion (NTDLL.@)
1217 * Creates I/O completion object.
1219 * PARAMS
1220 * CompletionPort [O] created completion object handle will be placed there
1221 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1222 * ObjectAttributes [I] completion object attributes
1223 * NumberOfConcurrentThreads [I] desired number of concurrent active worker threads
1226 NTSTATUS WINAPI NtCreateIoCompletion( PHANDLE CompletionPort, ACCESS_MASK DesiredAccess,
1227 POBJECT_ATTRIBUTES attr, ULONG NumberOfConcurrentThreads )
1229 NTSTATUS status;
1230 data_size_t len;
1231 struct object_attributes *objattr;
1233 TRACE("(%p, %x, %p, %d)\n", CompletionPort, DesiredAccess, attr, NumberOfConcurrentThreads);
1235 if (!CompletionPort)
1236 return STATUS_INVALID_PARAMETER;
1238 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
1240 SERVER_START_REQ( create_completion )
1242 req->access = DesiredAccess;
1243 req->concurrent = NumberOfConcurrentThreads;
1244 wine_server_add_data( req, objattr, len );
1245 if (!(status = wine_server_call( req )))
1246 *CompletionPort = wine_server_ptr_handle( reply->handle );
1248 SERVER_END_REQ;
1250 RtlFreeHeap( GetProcessHeap(), 0, objattr );
1251 return status;
1254 /******************************************************************
1255 * NtSetIoCompletion (NTDLL.@)
1256 * ZwSetIoCompletion (NTDLL.@)
1258 * Inserts completion message into queue
1260 * PARAMS
1261 * CompletionPort [I] HANDLE to completion object
1262 * CompletionKey [I] completion key
1263 * CompletionValue [I] completion value (usually pointer to OVERLAPPED)
1264 * Status [I] operation status
1265 * NumberOfBytesTransferred [I] number of bytes transferred
1267 NTSTATUS WINAPI NtSetIoCompletion( HANDLE CompletionPort, ULONG_PTR CompletionKey,
1268 ULONG_PTR CompletionValue, NTSTATUS Status,
1269 SIZE_T NumberOfBytesTransferred )
1271 NTSTATUS status;
1273 TRACE("(%p, %lx, %lx, %x, %lx)\n", CompletionPort, CompletionKey,
1274 CompletionValue, Status, NumberOfBytesTransferred);
1276 SERVER_START_REQ( add_completion )
1278 req->handle = wine_server_obj_handle( CompletionPort );
1279 req->ckey = CompletionKey;
1280 req->cvalue = CompletionValue;
1281 req->status = Status;
1282 req->information = NumberOfBytesTransferred;
1283 status = wine_server_call( req );
1285 SERVER_END_REQ;
1286 return status;
1289 /******************************************************************
1290 * NtRemoveIoCompletion (NTDLL.@)
1291 * ZwRemoveIoCompletion (NTDLL.@)
1293 * (Wait for and) retrieve first completion message from completion object's queue
1295 * PARAMS
1296 * CompletionPort [I] HANDLE to I/O completion object
1297 * CompletionKey [O] completion key
1298 * CompletionValue [O] Completion value given in NtSetIoCompletion or in async operation
1299 * iosb [O] IO_STATUS_BLOCK of completed asynchronous operation
1300 * WaitTime [I] optional wait time in NTDLL format
1303 NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE CompletionPort, PULONG_PTR CompletionKey,
1304 PULONG_PTR CompletionValue, PIO_STATUS_BLOCK iosb,
1305 PLARGE_INTEGER WaitTime )
1307 NTSTATUS status;
1309 TRACE("(%p, %p, %p, %p, %p)\n", CompletionPort, CompletionKey,
1310 CompletionValue, iosb, WaitTime);
1312 for(;;)
1314 SERVER_START_REQ( remove_completion )
1316 req->handle = wine_server_obj_handle( CompletionPort );
1317 if (!(status = wine_server_call( req )))
1319 *CompletionKey = reply->ckey;
1320 *CompletionValue = reply->cvalue;
1321 iosb->Information = reply->information;
1322 iosb->u.Status = reply->status;
1325 SERVER_END_REQ;
1326 if (status != STATUS_PENDING) break;
1328 status = NtWaitForSingleObject( CompletionPort, FALSE, WaitTime );
1329 if (status != WAIT_OBJECT_0) break;
1331 return status;
1334 /******************************************************************
1335 * NtOpenIoCompletion (NTDLL.@)
1336 * ZwOpenIoCompletion (NTDLL.@)
1338 * Opens I/O completion object
1340 * PARAMS
1341 * CompletionPort [O] completion object handle will be placed there
1342 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1343 * ObjectAttributes [I] completion object name
1346 NTSTATUS WINAPI NtOpenIoCompletion( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1348 NTSTATUS status;
1350 if (!handle) return STATUS_INVALID_PARAMETER;
1351 if ((status = validate_open_object_attributes( attr ))) return status;
1353 SERVER_START_REQ( open_completion )
1355 req->access = access;
1356 req->attributes = attr->Attributes;
1357 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1358 if (attr->ObjectName)
1359 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1360 status = wine_server_call( req );
1361 *handle = wine_server_ptr_handle( reply->handle );
1363 SERVER_END_REQ;
1364 return status;
1367 /******************************************************************
1368 * NtQueryIoCompletion (NTDLL.@)
1369 * ZwQueryIoCompletion (NTDLL.@)
1371 * Requests information about given I/O completion object
1373 * PARAMS
1374 * CompletionPort [I] HANDLE to completion port to request
1375 * InformationClass [I] information class
1376 * CompletionInformation [O] user-provided buffer for data
1377 * BufferLength [I] buffer length
1378 * RequiredLength [O] required buffer length
1381 NTSTATUS WINAPI NtQueryIoCompletion( HANDLE CompletionPort, IO_COMPLETION_INFORMATION_CLASS InformationClass,
1382 PVOID CompletionInformation, ULONG BufferLength, PULONG RequiredLength )
1384 NTSTATUS status;
1386 TRACE("(%p, %d, %p, 0x%x, %p)\n", CompletionPort, InformationClass, CompletionInformation,
1387 BufferLength, RequiredLength);
1389 if (!CompletionInformation) return STATUS_INVALID_PARAMETER;
1390 switch( InformationClass )
1392 case IoCompletionBasicInformation:
1394 ULONG *info = CompletionInformation;
1396 if (RequiredLength) *RequiredLength = sizeof(*info);
1397 if (BufferLength != sizeof(*info))
1398 status = STATUS_INFO_LENGTH_MISMATCH;
1399 else
1401 SERVER_START_REQ( query_completion )
1403 req->handle = wine_server_obj_handle( CompletionPort );
1404 if (!(status = wine_server_call( req )))
1405 *info = reply->depth;
1407 SERVER_END_REQ;
1410 break;
1411 default:
1412 status = STATUS_INVALID_PARAMETER;
1413 break;
1415 return status;
1418 NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue,
1419 NTSTATUS CompletionStatus, ULONG Information )
1421 NTSTATUS status;
1423 SERVER_START_REQ( add_fd_completion )
1425 req->handle = wine_server_obj_handle( hFile );
1426 req->cvalue = CompletionValue;
1427 req->status = CompletionStatus;
1428 req->information = Information;
1429 status = wine_server_call( req );
1431 SERVER_END_REQ;
1432 return status;
1435 /******************************************************************
1436 * RtlRunOnceInitialize (NTDLL.@)
1438 void WINAPI RtlRunOnceInitialize( RTL_RUN_ONCE *once )
1440 once->Ptr = NULL;
1443 /******************************************************************
1444 * RtlRunOnceBeginInitialize (NTDLL.@)
1446 DWORD WINAPI RtlRunOnceBeginInitialize( RTL_RUN_ONCE *once, ULONG flags, void **context )
1448 if (flags & RTL_RUN_ONCE_CHECK_ONLY)
1450 ULONG_PTR val = (ULONG_PTR)once->Ptr;
1452 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1453 if ((val & 3) != 2) return STATUS_UNSUCCESSFUL;
1454 if (context) *context = (void *)(val & ~3);
1455 return STATUS_SUCCESS;
1458 for (;;)
1460 ULONG_PTR next, val = (ULONG_PTR)once->Ptr;
1462 switch (val & 3)
1464 case 0: /* first time */
1465 if (!interlocked_cmpxchg_ptr( &once->Ptr,
1466 (flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0 ))
1467 return STATUS_PENDING;
1468 break;
1470 case 1: /* in progress, wait */
1471 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1472 next = val & ~3;
1473 if (interlocked_cmpxchg_ptr( &once->Ptr, (void *)((ULONG_PTR)&next | 1),
1474 (void *)val ) == (void *)val)
1475 NtWaitForKeyedEvent( keyed_event, &next, FALSE, NULL );
1476 break;
1478 case 2: /* done */
1479 if (context) *context = (void *)(val & ~3);
1480 return STATUS_SUCCESS;
1482 case 3: /* in progress, async */
1483 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
1484 return STATUS_PENDING;
1489 /******************************************************************
1490 * RtlRunOnceComplete (NTDLL.@)
1492 DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context )
1494 if ((ULONG_PTR)context & 3) return STATUS_INVALID_PARAMETER;
1496 if (flags & RTL_RUN_ONCE_INIT_FAILED)
1498 if (context) return STATUS_INVALID_PARAMETER;
1499 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1501 else context = (void *)((ULONG_PTR)context | 2);
1503 for (;;)
1505 ULONG_PTR val = (ULONG_PTR)once->Ptr;
1507 switch (val & 3)
1509 case 1: /* in progress */
1510 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break;
1511 val &= ~3;
1512 while (val)
1514 ULONG_PTR next = *(ULONG_PTR *)val;
1515 NtReleaseKeyedEvent( keyed_event, (void *)val, FALSE, NULL );
1516 val = next;
1518 return STATUS_SUCCESS;
1520 case 3: /* in progress, async */
1521 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
1522 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break;
1523 return STATUS_SUCCESS;
1525 default:
1526 return STATUS_UNSUCCESSFUL;
1531 /******************************************************************
1532 * RtlRunOnceExecuteOnce (NTDLL.@)
1534 DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN func,
1535 void *param, void **context )
1537 DWORD ret = RtlRunOnceBeginInitialize( once, 0, context );
1539 if (ret != STATUS_PENDING) return ret;
1541 if (!func( once, param, context ))
1543 RtlRunOnceComplete( once, RTL_RUN_ONCE_INIT_FAILED, NULL );
1544 return STATUS_UNSUCCESSFUL;
1547 return RtlRunOnceComplete( once, 0, context ? *context : NULL );
1551 /* SRW locks implementation
1553 * The memory layout used by the lock is:
1555 * 32 31 16 0
1556 * ________________ ________________
1557 * | X| #exclusive | #shared |
1558 * ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
1559 * Since there is no space left for a separate counter of shared access
1560 * threads inside the locked section the #shared field is used for multiple
1561 * purposes. The following table lists all possible states the lock can be
1562 * in, notation: [X, #exclusive, #shared]:
1564 * [0, 0, N] -> locked by N shared access threads, if N=0 it's unlocked
1565 * [0, >=1, >=1] -> threads are requesting exclusive locks, but there are
1566 * still shared access threads inside. #shared should not be incremented
1567 * anymore!
1568 * [1, >=1, >=0] -> lock is owned by an exclusive thread and the #shared
1569 * counter can be used again to count the number of threads waiting in the
1570 * queue for shared access.
1572 * the following states are invalid and will never occur:
1573 * [0, >=1, 0], [1, 0, >=0]
1575 * The main problem arising from the fact that we have no separate counter
1576 * of shared access threads inside the locked section is that in the state
1577 * [0, >=1, >=1] above we cannot add additional waiting threads to the
1578 * shared access queue - it wouldn't be possible to distinguish waiting
1579 * threads and those that are still inside. To solve this problem the lock
1580 * uses the following approach: a thread that isn't able to allocate a
1581 * shared lock just uses the exclusive queue instead. As soon as the thread
1582 * is woken up it is in the state [1, >=1, >=0]. In this state it's again
1583 * possible to use the shared access queue. The thread atomically moves
1584 * itself to the shared access queue and releases the exclusive lock, so
1585 * that the "real" exclusive access threads have a chance. As soon as they
1586 * are all ready the shared access threads are processed.
1589 #define SRWLOCK_MASK_IN_EXCLUSIVE 0x80000000
1590 #define SRWLOCK_MASK_EXCLUSIVE_QUEUE 0x7fff0000
1591 #define SRWLOCK_MASK_SHARED_QUEUE 0x0000ffff
1592 #define SRWLOCK_RES_EXCLUSIVE 0x00010000
1593 #define SRWLOCK_RES_SHARED 0x00000001
1595 #ifdef WORDS_BIGENDIAN
1596 #define srwlock_key_exclusive(lock) (&lock->Ptr)
1597 #define srwlock_key_shared(lock) ((void *)((char *)&lock->Ptr + 2))
1598 #else
1599 #define srwlock_key_exclusive(lock) ((void *)((char *)&lock->Ptr + 2))
1600 #define srwlock_key_shared(lock) (&lock->Ptr)
1601 #endif
1603 static inline void srwlock_check_invalid( unsigned int val )
1605 /* Throw exception if it's impossible to acquire/release this lock. */
1606 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) == SRWLOCK_MASK_EXCLUSIVE_QUEUE ||
1607 (val & SRWLOCK_MASK_SHARED_QUEUE) == SRWLOCK_MASK_SHARED_QUEUE)
1608 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED);
1611 static inline unsigned int srwlock_lock_exclusive( unsigned int *dest, int incr )
1613 unsigned int val, tmp;
1614 /* Atomically modifies the value of *dest by adding incr. If the shared
1615 * queue is empty and there are threads waiting for exclusive access, then
1616 * sets the mark SRWLOCK_MASK_IN_EXCLUSIVE to signal other threads that
1617 * they are allowed again to use the shared queue counter. */
1618 for (val = *dest;; val = tmp)
1620 tmp = val + incr;
1621 srwlock_check_invalid( tmp );
1622 if ((tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(tmp & SRWLOCK_MASK_SHARED_QUEUE))
1623 tmp |= SRWLOCK_MASK_IN_EXCLUSIVE;
1624 if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val)
1625 break;
1627 return val;
1630 static inline unsigned int srwlock_unlock_exclusive( unsigned int *dest, int incr )
1632 unsigned int val, tmp;
1633 /* Atomically modifies the value of *dest by adding incr. If the queue of
1634 * threads waiting for exclusive access is empty, then remove the
1635 * SRWLOCK_MASK_IN_EXCLUSIVE flag (only the shared queue counter will
1636 * remain). */
1637 for (val = *dest;; val = tmp)
1639 tmp = val + incr;
1640 srwlock_check_invalid( tmp );
1641 if (!(tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE))
1642 tmp &= SRWLOCK_MASK_SHARED_QUEUE;
1643 if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val)
1644 break;
1646 return val;
1649 static inline void srwlock_leave_exclusive( RTL_SRWLOCK *lock, unsigned int val )
1651 /* Used when a thread leaves an exclusive section. If there are other
1652 * exclusive access threads they are processed first, followed by
1653 * the shared waiters. */
1654 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
1655 NtReleaseKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1656 else
1658 val &= SRWLOCK_MASK_SHARED_QUEUE; /* remove SRWLOCK_MASK_IN_EXCLUSIVE */
1659 while (val--)
1660 NtReleaseKeyedEvent( keyed_event, srwlock_key_shared(lock), FALSE, NULL );
1664 static inline void srwlock_leave_shared( RTL_SRWLOCK *lock, unsigned int val )
1666 /* Wake up one exclusive thread as soon as the last shared access thread
1667 * has left. */
1668 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_SHARED_QUEUE))
1669 NtReleaseKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1672 /***********************************************************************
1673 * RtlInitializeSRWLock (NTDLL.@)
1675 * NOTES
1676 * Please note that SRWLocks do not keep track of the owner of a lock.
1677 * It doesn't make any difference which thread for example unlocks an
1678 * SRWLock (see corresponding tests). This implementation uses two
1679 * keyed events (one for the exclusive waiters and one for the shared
1680 * waiters) and is limited to 2^15-1 waiting threads.
1682 void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock )
1684 lock->Ptr = NULL;
1687 /***********************************************************************
1688 * RtlAcquireSRWLockExclusive (NTDLL.@)
1690 * NOTES
1691 * Unlike RtlAcquireResourceExclusive this function doesn't allow
1692 * nested calls from the same thread. "Upgrading" a shared access lock
1693 * to an exclusive access lock also doesn't seem to be supported.
1695 void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
1697 if (srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, SRWLOCK_RES_EXCLUSIVE ))
1698 NtWaitForKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1701 /***********************************************************************
1702 * RtlAcquireSRWLockShared (NTDLL.@)
1704 * NOTES
1705 * Do not call this function recursively - it will only succeed when
1706 * there are no threads waiting for an exclusive lock!
1708 void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
1710 unsigned int val, tmp;
1711 /* Acquires a shared lock. If it's currently not possible to add elements to
1712 * the shared queue, then request exclusive access instead. */
1713 for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
1715 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
1716 tmp = val + SRWLOCK_RES_EXCLUSIVE;
1717 else
1718 tmp = val + SRWLOCK_RES_SHARED;
1719 if ((tmp = interlocked_cmpxchg( (int *)&lock->Ptr, tmp, val )) == val)
1720 break;
1723 /* Drop exclusive access again and instead requeue for shared access. */
1724 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
1726 NtWaitForKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1727 val = srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr, (SRWLOCK_RES_SHARED
1728 - SRWLOCK_RES_EXCLUSIVE) ) - SRWLOCK_RES_EXCLUSIVE;
1729 srwlock_leave_exclusive( lock, val );
1732 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
1733 NtWaitForKeyedEvent( keyed_event, srwlock_key_shared(lock), FALSE, NULL );
1736 /***********************************************************************
1737 * RtlReleaseSRWLockExclusive (NTDLL.@)
1739 void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
1741 srwlock_leave_exclusive( lock, srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr,
1742 - SRWLOCK_RES_EXCLUSIVE ) - SRWLOCK_RES_EXCLUSIVE );
1745 /***********************************************************************
1746 * RtlReleaseSRWLockShared (NTDLL.@)
1748 void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
1750 srwlock_leave_shared( lock, srwlock_lock_exclusive( (unsigned int *)&lock->Ptr,
1751 - SRWLOCK_RES_SHARED ) - SRWLOCK_RES_SHARED );
1754 /***********************************************************************
1755 * RtlTryAcquireSRWLockExclusive (NTDLL.@)
1757 * NOTES
1758 * Similar to AcquireSRWLockExclusive recusive calls are not allowed
1759 * and will fail with return value FALSE.
1761 BOOLEAN WINAPI RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
1763 return interlocked_cmpxchg( (int *)&lock->Ptr, SRWLOCK_MASK_IN_EXCLUSIVE |
1764 SRWLOCK_RES_EXCLUSIVE, 0 ) == 0;
1767 /***********************************************************************
1768 * RtlTryAcquireSRWLockShared (NTDLL.@)
1770 BOOLEAN WINAPI RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock )
1772 unsigned int val, tmp;
1773 for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
1775 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
1776 return FALSE;
1777 if ((tmp = interlocked_cmpxchg( (int *)&lock->Ptr, val + SRWLOCK_RES_SHARED, val )) == val)
1778 break;
1780 return TRUE;
1783 /***********************************************************************
1784 * RtlInitializeConditionVariable (NTDLL.@)
1786 * Initializes the condition variable with NULL.
1788 * PARAMS
1789 * variable [O] condition variable
1791 * RETURNS
1792 * Nothing.
1794 void WINAPI RtlInitializeConditionVariable( RTL_CONDITION_VARIABLE *variable )
1796 variable->Ptr = NULL;
1799 /***********************************************************************
1800 * RtlWakeConditionVariable (NTDLL.@)
1802 * Wakes up one thread waiting on the condition variable.
1804 * PARAMS
1805 * variable [I/O] condition variable to wake up.
1807 * RETURNS
1808 * Nothing.
1810 * NOTES
1811 * The calling thread does not have to own any lock in order to call
1812 * this function.
1814 void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable )
1816 if (interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
1817 NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1820 /***********************************************************************
1821 * RtlWakeAllConditionVariable (NTDLL.@)
1823 * See WakeConditionVariable, wakes up all waiting threads.
1825 void WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *variable )
1827 int val = interlocked_xchg( (int *)&variable->Ptr, 0 );
1828 while (val-- > 0)
1829 NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1832 /***********************************************************************
1833 * RtlSleepConditionVariableCS (NTDLL.@)
1835 * Atomically releases the critical section and suspends the thread,
1836 * waiting for a Wake(All)ConditionVariable event. Afterwards it enters
1837 * the critical section again and returns.
1839 * PARAMS
1840 * variable [I/O] condition variable
1841 * crit [I/O] critical section to leave temporarily
1842 * timeout [I] timeout
1844 * RETURNS
1845 * see NtWaitForKeyedEvent for all possible return values.
1847 NTSTATUS WINAPI RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, RTL_CRITICAL_SECTION *crit,
1848 const LARGE_INTEGER *timeout )
1850 NTSTATUS status;
1851 interlocked_xchg_add( (int *)&variable->Ptr, 1 );
1852 RtlLeaveCriticalSection( crit );
1854 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, timeout );
1855 if (status != STATUS_SUCCESS)
1857 if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
1858 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1861 RtlEnterCriticalSection( crit );
1862 return status;
1865 /***********************************************************************
1866 * RtlSleepConditionVariableSRW (NTDLL.@)
1868 * Atomically releases the SRWLock and suspends the thread,
1869 * waiting for a Wake(All)ConditionVariable event. Afterwards it enters
1870 * the SRWLock again with the same access rights and returns.
1872 * PARAMS
1873 * variable [I/O] condition variable
1874 * lock [I/O] SRWLock to leave temporarily
1875 * timeout [I] timeout
1876 * flags [I] type of the current lock (exclusive / shared)
1878 * RETURNS
1879 * see NtWaitForKeyedEvent for all possible return values.
1881 * NOTES
1882 * the behaviour is undefined if the thread doesn't own the lock.
1884 NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, RTL_SRWLOCK *lock,
1885 const LARGE_INTEGER *timeout, ULONG flags )
1887 NTSTATUS status;
1888 interlocked_xchg_add( (int *)&variable->Ptr, 1 );
1890 if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
1891 RtlReleaseSRWLockShared( lock );
1892 else
1893 RtlReleaseSRWLockExclusive( lock );
1895 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, timeout );
1896 if (status != STATUS_SUCCESS)
1898 if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
1899 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1902 if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
1903 RtlAcquireSRWLockShared( lock );
1904 else
1905 RtlAcquireSRWLockExclusive( lock );
1906 return status;