ntdll: Add a wrapper to call the unhandled exception filter.
[wine.git] / dlls / ntdll / sync.c
blob4ae8e36ce04d8b8d5ddfbb3d0e0c8e3516b182f0
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 len = (len + 3) & ~3; /* DWORD-align the entire structure */
119 *ret = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, len );
120 if (!*ret) return STATUS_NO_MEMORY;
122 (*ret)->rootdir = wine_server_obj_handle( attr->RootDirectory );
123 (*ret)->attributes = attr->Attributes;
125 if (attr->SecurityDescriptor)
127 struct security_descriptor *descr = (struct security_descriptor *)(*ret + 1);
128 unsigned char *ptr = (unsigned char *)(descr + 1);
130 descr->control = ((SECURITY_DESCRIPTOR *)sd)->Control & ~SE_SELF_RELATIVE;
131 if (owner) descr->owner_len = RtlLengthSid( owner );
132 if (group) descr->group_len = RtlLengthSid( group );
133 if (sacl_present && sacl) descr->sacl_len = sacl->AclSize;
134 if (dacl_present && dacl) descr->dacl_len = dacl->AclSize;
136 memcpy( ptr, owner, descr->owner_len );
137 ptr += descr->owner_len;
138 memcpy( ptr, group, descr->group_len );
139 ptr += descr->group_len;
140 memcpy( ptr, sacl, descr->sacl_len );
141 ptr += descr->sacl_len;
142 memcpy( ptr, dacl, descr->dacl_len );
143 (*ret)->sd_len = (sizeof(*descr) + descr->owner_len + descr->group_len + descr->sacl_len +
144 descr->dacl_len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
147 if (attr->ObjectName)
149 unsigned char *ptr = (unsigned char *)(*ret + 1) + (*ret)->sd_len;
150 (*ret)->name_len = attr->ObjectName->Length;
151 memcpy( ptr, attr->ObjectName->Buffer, (*ret)->name_len );
154 *ret_len = len;
155 return STATUS_SUCCESS;
158 NTSTATUS validate_open_object_attributes( const OBJECT_ATTRIBUTES *attr )
160 if (!attr || attr->Length != sizeof(*attr)) return STATUS_INVALID_PARAMETER;
162 if (attr->ObjectName)
164 if (attr->ObjectName->Length & (sizeof(WCHAR) - 1)) return STATUS_OBJECT_NAME_INVALID;
166 else if (attr->RootDirectory) return STATUS_OBJECT_NAME_INVALID;
168 return STATUS_SUCCESS;
172 * Semaphores
175 /******************************************************************************
176 * NtCreateSemaphore (NTDLL.@)
178 NTSTATUS WINAPI NtCreateSemaphore( OUT PHANDLE SemaphoreHandle,
179 IN ACCESS_MASK access,
180 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
181 IN LONG InitialCount,
182 IN LONG MaximumCount )
184 NTSTATUS ret;
185 data_size_t len;
186 struct object_attributes *objattr;
188 if (MaximumCount <= 0 || InitialCount < 0 || InitialCount > MaximumCount)
189 return STATUS_INVALID_PARAMETER;
191 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
193 SERVER_START_REQ( create_semaphore )
195 req->access = access;
196 req->initial = InitialCount;
197 req->max = MaximumCount;
198 wine_server_add_data( req, objattr, len );
199 ret = wine_server_call( req );
200 *SemaphoreHandle = wine_server_ptr_handle( reply->handle );
202 SERVER_END_REQ;
204 RtlFreeHeap( GetProcessHeap(), 0, objattr );
205 return ret;
208 /******************************************************************************
209 * NtOpenSemaphore (NTDLL.@)
211 NTSTATUS WINAPI NtOpenSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
213 NTSTATUS ret;
215 if ((ret = validate_open_object_attributes( attr ))) return ret;
217 SERVER_START_REQ( open_semaphore )
219 req->access = access;
220 req->attributes = attr->Attributes;
221 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
222 if (attr->ObjectName)
223 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
224 ret = wine_server_call( req );
225 *handle = wine_server_ptr_handle( reply->handle );
227 SERVER_END_REQ;
228 return ret;
231 /******************************************************************************
232 * NtQuerySemaphore (NTDLL.@)
234 NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS class,
235 void *info, ULONG len, ULONG *ret_len )
237 NTSTATUS ret;
238 SEMAPHORE_BASIC_INFORMATION *out = info;
240 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, len, ret_len);
242 if (class != SemaphoreBasicInformation)
244 FIXME("(%p,%d,%u) Unknown class\n", handle, class, len);
245 return STATUS_INVALID_INFO_CLASS;
248 if (len != sizeof(SEMAPHORE_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
250 SERVER_START_REQ( query_semaphore )
252 req->handle = wine_server_obj_handle( handle );
253 if (!(ret = wine_server_call( req )))
255 out->CurrentCount = reply->current;
256 out->MaximumCount = reply->max;
257 if (ret_len) *ret_len = sizeof(SEMAPHORE_BASIC_INFORMATION);
260 SERVER_END_REQ;
262 return ret;
265 /******************************************************************************
266 * NtReleaseSemaphore (NTDLL.@)
268 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, PULONG previous )
270 NTSTATUS ret;
271 SERVER_START_REQ( release_semaphore )
273 req->handle = wine_server_obj_handle( handle );
274 req->count = count;
275 if (!(ret = wine_server_call( req )))
277 if (previous) *previous = reply->prev_count;
280 SERVER_END_REQ;
281 return ret;
285 * Events
288 /**************************************************************************
289 * NtCreateEvent (NTDLL.@)
290 * ZwCreateEvent (NTDLL.@)
292 NTSTATUS WINAPI NtCreateEvent( PHANDLE EventHandle, ACCESS_MASK DesiredAccess,
293 const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN InitialState)
295 NTSTATUS ret;
296 data_size_t len;
297 struct object_attributes *objattr;
299 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
301 SERVER_START_REQ( create_event )
303 req->access = DesiredAccess;
304 req->manual_reset = (type == NotificationEvent);
305 req->initial_state = InitialState;
306 wine_server_add_data( req, objattr, len );
307 ret = wine_server_call( req );
308 *EventHandle = wine_server_ptr_handle( reply->handle );
310 SERVER_END_REQ;
312 RtlFreeHeap( GetProcessHeap(), 0, objattr );
313 return ret;
316 /******************************************************************************
317 * NtOpenEvent (NTDLL.@)
318 * ZwOpenEvent (NTDLL.@)
320 NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
322 NTSTATUS ret;
324 if ((ret = validate_open_object_attributes( attr ))) return ret;
326 SERVER_START_REQ( open_event )
328 req->access = access;
329 req->attributes = attr->Attributes;
330 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
331 if (attr->ObjectName)
332 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
333 ret = wine_server_call( req );
334 *handle = wine_server_ptr_handle( reply->handle );
336 SERVER_END_REQ;
337 return ret;
341 /******************************************************************************
342 * NtSetEvent (NTDLL.@)
343 * ZwSetEvent (NTDLL.@)
345 NTSTATUS WINAPI NtSetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
347 NTSTATUS ret;
349 /* FIXME: set NumberOfThreadsReleased */
351 SERVER_START_REQ( event_op )
353 req->handle = wine_server_obj_handle( handle );
354 req->op = SET_EVENT;
355 ret = wine_server_call( req );
357 SERVER_END_REQ;
358 return ret;
361 /******************************************************************************
362 * NtResetEvent (NTDLL.@)
364 NTSTATUS WINAPI NtResetEvent( HANDLE handle, PULONG NumberOfThreadsReleased )
366 NTSTATUS ret;
368 /* resetting an event can't release any thread... */
369 if (NumberOfThreadsReleased) *NumberOfThreadsReleased = 0;
371 SERVER_START_REQ( event_op )
373 req->handle = wine_server_obj_handle( handle );
374 req->op = RESET_EVENT;
375 ret = wine_server_call( req );
377 SERVER_END_REQ;
378 return ret;
381 /******************************************************************************
382 * NtClearEvent (NTDLL.@)
384 * FIXME
385 * same as NtResetEvent ???
387 NTSTATUS WINAPI NtClearEvent ( HANDLE handle )
389 return NtResetEvent( handle, NULL );
392 /******************************************************************************
393 * NtPulseEvent (NTDLL.@)
395 * FIXME
396 * PulseCount
398 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, PULONG PulseCount )
400 NTSTATUS ret;
402 if (PulseCount)
403 FIXME("(%p,%d)\n", handle, *PulseCount);
405 SERVER_START_REQ( event_op )
407 req->handle = wine_server_obj_handle( handle );
408 req->op = PULSE_EVENT;
409 ret = wine_server_call( req );
411 SERVER_END_REQ;
412 return ret;
415 /******************************************************************************
416 * NtQueryEvent (NTDLL.@)
418 NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class,
419 void *info, ULONG len, ULONG *ret_len )
421 NTSTATUS ret;
422 EVENT_BASIC_INFORMATION *out = info;
424 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, len, ret_len);
426 if (class != EventBasicInformation)
428 FIXME("(%p, %d, %d) Unknown class\n",
429 handle, class, len);
430 return STATUS_INVALID_INFO_CLASS;
433 if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
435 SERVER_START_REQ( query_event )
437 req->handle = wine_server_obj_handle( handle );
438 if (!(ret = wine_server_call( req )))
440 out->EventType = reply->manual_reset ? NotificationEvent : SynchronizationEvent;
441 out->EventState = reply->state;
442 if (ret_len) *ret_len = sizeof(EVENT_BASIC_INFORMATION);
445 SERVER_END_REQ;
447 return ret;
451 * Mutants (known as Mutexes in Kernel32)
454 /******************************************************************************
455 * NtCreateMutant [NTDLL.@]
456 * ZwCreateMutant [NTDLL.@]
458 NTSTATUS WINAPI NtCreateMutant(OUT HANDLE* MutantHandle,
459 IN ACCESS_MASK access,
460 IN const OBJECT_ATTRIBUTES* attr OPTIONAL,
461 IN BOOLEAN InitialOwner)
463 NTSTATUS status;
464 data_size_t len;
465 struct object_attributes *objattr;
467 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
469 SERVER_START_REQ( create_mutex )
471 req->access = access;
472 req->owned = InitialOwner;
473 wine_server_add_data( req, objattr, len );
474 status = wine_server_call( req );
475 *MutantHandle = wine_server_ptr_handle( reply->handle );
477 SERVER_END_REQ;
479 RtlFreeHeap( GetProcessHeap(), 0, objattr );
480 return status;
483 /**************************************************************************
484 * NtOpenMutant [NTDLL.@]
485 * ZwOpenMutant [NTDLL.@]
487 NTSTATUS WINAPI NtOpenMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
489 NTSTATUS status;
491 if ((status = validate_open_object_attributes( attr ))) return status;
493 SERVER_START_REQ( open_mutex )
495 req->access = access;
496 req->attributes = attr->Attributes;
497 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
498 if (attr->ObjectName)
499 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
500 status = wine_server_call( req );
501 *handle = wine_server_ptr_handle( reply->handle );
503 SERVER_END_REQ;
504 return status;
507 /**************************************************************************
508 * NtReleaseMutant [NTDLL.@]
509 * ZwReleaseMutant [NTDLL.@]
511 NTSTATUS WINAPI NtReleaseMutant( IN HANDLE handle, OUT PLONG prev_count OPTIONAL)
513 NTSTATUS status;
515 SERVER_START_REQ( release_mutex )
517 req->handle = wine_server_obj_handle( handle );
518 status = wine_server_call( req );
519 if (prev_count) *prev_count = 1 - reply->prev_count;
521 SERVER_END_REQ;
522 return status;
525 /******************************************************************
526 * NtQueryMutant [NTDLL.@]
527 * ZwQueryMutant [NTDLL.@]
529 NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class,
530 void *info, ULONG len, ULONG *ret_len )
532 NTSTATUS ret;
533 MUTANT_BASIC_INFORMATION *out = info;
535 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, len, ret_len);
537 if (class != MutantBasicInformation)
539 FIXME("(%p, %d, %d) Unknown class\n",
540 handle, class, len);
541 return STATUS_INVALID_INFO_CLASS;
544 if (len != sizeof(MUTANT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
546 SERVER_START_REQ( query_mutex )
548 req->handle = wine_server_obj_handle( handle );
549 if (!(ret = wine_server_call( req )))
551 out->CurrentCount = 1 - reply->count;
552 out->OwnedByCaller = reply->owned;
553 out->AbandonedState = reply->abandoned;
554 if (ret_len) *ret_len = sizeof(MUTANT_BASIC_INFORMATION);
557 SERVER_END_REQ;
559 return ret;
563 * Jobs
566 /******************************************************************************
567 * NtCreateJobObject [NTDLL.@]
568 * ZwCreateJobObject [NTDLL.@]
570 NTSTATUS WINAPI NtCreateJobObject( PHANDLE handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
572 NTSTATUS ret;
573 data_size_t len;
574 struct object_attributes *objattr;
576 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
578 SERVER_START_REQ( create_job )
580 req->access = access;
581 wine_server_add_data( req, objattr, len );
582 ret = wine_server_call( req );
583 *handle = wine_server_ptr_handle( reply->handle );
585 SERVER_END_REQ;
587 RtlFreeHeap( GetProcessHeap(), 0, objattr );
588 return ret;
591 /******************************************************************************
592 * NtOpenJobObject [NTDLL.@]
593 * ZwOpenJobObject [NTDLL.@]
595 NTSTATUS WINAPI NtOpenJobObject( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
597 NTSTATUS ret;
599 if ((ret = validate_open_object_attributes( attr ))) return ret;
601 SERVER_START_REQ( open_job )
603 req->access = access;
604 req->attributes = attr->Attributes;
605 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
606 if (attr->ObjectName)
607 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
608 ret = wine_server_call( req );
609 *handle = wine_server_ptr_handle( reply->handle );
611 SERVER_END_REQ;
612 return ret;
615 /******************************************************************************
616 * NtTerminateJobObject [NTDLL.@]
617 * ZwTerminateJobObject [NTDLL.@]
619 NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status )
621 NTSTATUS ret;
623 TRACE( "(%p, %d)\n", handle, status );
625 SERVER_START_REQ( terminate_job )
627 req->handle = wine_server_obj_handle( handle );
628 req->status = status;
629 ret = wine_server_call( req );
631 SERVER_END_REQ;
633 return ret;
636 /******************************************************************************
637 * NtQueryInformationJobObject [NTDLL.@]
638 * ZwQueryInformationJobObject [NTDLL.@]
640 NTSTATUS WINAPI NtQueryInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info,
641 ULONG len, PULONG ret_len )
643 FIXME( "stub: %p %u %p %u %p\n", handle, class, info, len, ret_len );
645 if (class >= MaxJobObjectInfoClass)
646 return STATUS_INVALID_PARAMETER;
648 switch (class)
650 case JobObjectBasicAccountingInformation:
652 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION *accounting;
653 if (len < sizeof(*accounting))
654 return STATUS_INFO_LENGTH_MISMATCH;
656 accounting = (JOBOBJECT_BASIC_ACCOUNTING_INFORMATION *)info;
657 memset(accounting, 0, sizeof(*accounting));
658 if (ret_len) *ret_len = sizeof(*accounting);
659 return STATUS_SUCCESS;
662 case JobObjectBasicProcessIdList:
664 JOBOBJECT_BASIC_PROCESS_ID_LIST *process;
665 if (len < sizeof(*process))
666 return STATUS_INFO_LENGTH_MISMATCH;
668 process = (JOBOBJECT_BASIC_PROCESS_ID_LIST *)info;
669 memset(process, 0, sizeof(*process));
670 if (ret_len) *ret_len = sizeof(*process);
671 return STATUS_SUCCESS;
674 case JobObjectExtendedLimitInformation:
676 JOBOBJECT_EXTENDED_LIMIT_INFORMATION *extended_limit;
677 if (len < sizeof(*extended_limit))
678 return STATUS_INFO_LENGTH_MISMATCH;
680 extended_limit = (JOBOBJECT_EXTENDED_LIMIT_INFORMATION *)info;
681 memset(extended_limit, 0, sizeof(*extended_limit));
682 if (ret_len) *ret_len = sizeof(*extended_limit);
683 return STATUS_SUCCESS;
686 case JobObjectBasicLimitInformation:
688 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit;
689 if (len < sizeof(*basic_limit))
690 return STATUS_INFO_LENGTH_MISMATCH;
692 basic_limit = (JOBOBJECT_BASIC_LIMIT_INFORMATION *)info;
693 memset(basic_limit, 0, sizeof(*basic_limit));
694 if (ret_len) *ret_len = sizeof(*basic_limit);
695 return STATUS_SUCCESS;
698 default:
699 return STATUS_NOT_IMPLEMENTED;
703 /******************************************************************************
704 * NtSetInformationJobObject [NTDLL.@]
705 * ZwSetInformationJobObject [NTDLL.@]
707 NTSTATUS WINAPI NtSetInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, PVOID info, ULONG len )
709 NTSTATUS status = STATUS_NOT_IMPLEMENTED;
710 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit;
711 ULONG info_size = sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION);
712 DWORD limit_flags = JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS;
714 TRACE( "(%p, %u, %p, %u)\n", handle, class, info, len );
716 if (class >= MaxJobObjectInfoClass)
717 return STATUS_INVALID_PARAMETER;
719 switch (class)
722 case JobObjectExtendedLimitInformation:
723 info_size = sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION);
724 limit_flags = JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS;
725 /* fallthrough */
726 case JobObjectBasicLimitInformation:
727 if (len != info_size)
728 return STATUS_INVALID_PARAMETER;
730 basic_limit = info;
731 if (basic_limit->LimitFlags & ~limit_flags)
732 return STATUS_INVALID_PARAMETER;
734 SERVER_START_REQ( set_job_limits )
736 req->handle = wine_server_obj_handle( handle );
737 req->limit_flags = basic_limit->LimitFlags;
738 status = wine_server_call( req );
740 SERVER_END_REQ;
741 break;
743 case JobObjectAssociateCompletionPortInformation:
744 if (len != sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT))
745 return STATUS_INVALID_PARAMETER;
747 SERVER_START_REQ( set_job_completion_port )
749 JOBOBJECT_ASSOCIATE_COMPLETION_PORT *port_info = info;
750 req->job = wine_server_obj_handle( handle );
751 req->port = wine_server_obj_handle( port_info->CompletionPort );
752 req->key = wine_server_client_ptr( port_info->CompletionKey );
753 status = wine_server_call(req);
755 SERVER_END_REQ;
756 break;
758 case JobObjectBasicUIRestrictions:
759 status = STATUS_SUCCESS;
760 /* fallthrough */
761 default:
762 FIXME( "stub: %p %u %p %u\n", handle, class, info, len );
765 return status;
768 /******************************************************************************
769 * NtIsProcessInJob [NTDLL.@]
770 * ZwIsProcessInJob [NTDLL.@]
772 NTSTATUS WINAPI NtIsProcessInJob( HANDLE process, HANDLE job )
774 NTSTATUS status;
776 TRACE( "(%p %p)\n", job, process );
778 SERVER_START_REQ( process_in_job )
780 req->job = wine_server_obj_handle( job );
781 req->process = wine_server_obj_handle( process );
782 status = wine_server_call( req );
784 SERVER_END_REQ;
786 return status;
789 /******************************************************************************
790 * NtAssignProcessToJobObject [NTDLL.@]
791 * ZwAssignProcessToJobObject [NTDLL.@]
793 NTSTATUS WINAPI NtAssignProcessToJobObject( HANDLE job, HANDLE process )
795 NTSTATUS status;
797 TRACE( "(%p %p)\n", job, process );
799 SERVER_START_REQ( assign_job )
801 req->job = wine_server_obj_handle( job );
802 req->process = wine_server_obj_handle( process );
803 status = wine_server_call( req );
805 SERVER_END_REQ;
807 return status;
811 * Timers
814 /**************************************************************************
815 * NtCreateTimer [NTDLL.@]
816 * ZwCreateTimer [NTDLL.@]
818 NTSTATUS WINAPI NtCreateTimer(OUT HANDLE *handle,
819 IN ACCESS_MASK access,
820 IN const OBJECT_ATTRIBUTES *attr OPTIONAL,
821 IN TIMER_TYPE timer_type)
823 NTSTATUS status;
824 data_size_t len;
825 struct object_attributes *objattr;
827 if (timer_type != NotificationTimer && timer_type != SynchronizationTimer)
828 return STATUS_INVALID_PARAMETER;
830 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
832 SERVER_START_REQ( create_timer )
834 req->access = access;
835 req->manual = (timer_type == NotificationTimer);
836 wine_server_add_data( req, objattr, len );
837 status = wine_server_call( req );
838 *handle = wine_server_ptr_handle( reply->handle );
840 SERVER_END_REQ;
842 RtlFreeHeap( GetProcessHeap(), 0, objattr );
843 return status;
847 /**************************************************************************
848 * NtOpenTimer [NTDLL.@]
849 * ZwOpenTimer [NTDLL.@]
851 NTSTATUS WINAPI NtOpenTimer( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
853 NTSTATUS status;
855 if ((status = validate_open_object_attributes( attr ))) return status;
857 SERVER_START_REQ( open_timer )
859 req->access = access;
860 req->attributes = attr->Attributes;
861 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
862 if (attr->ObjectName)
863 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
864 status = wine_server_call( req );
865 *handle = wine_server_ptr_handle( reply->handle );
867 SERVER_END_REQ;
868 return status;
871 /**************************************************************************
872 * NtSetTimer [NTDLL.@]
873 * ZwSetTimer [NTDLL.@]
875 NTSTATUS WINAPI NtSetTimer(IN HANDLE handle,
876 IN const LARGE_INTEGER* when,
877 IN PTIMER_APC_ROUTINE callback,
878 IN PVOID callback_arg,
879 IN BOOLEAN resume,
880 IN ULONG period OPTIONAL,
881 OUT PBOOLEAN state OPTIONAL)
883 NTSTATUS status = STATUS_SUCCESS;
885 TRACE("(%p,%p,%p,%p,%08x,0x%08x,%p)\n",
886 handle, when, callback, callback_arg, resume, period, state);
888 SERVER_START_REQ( set_timer )
890 req->handle = wine_server_obj_handle( handle );
891 req->period = period;
892 req->expire = when->QuadPart;
893 req->callback = wine_server_client_ptr( callback );
894 req->arg = wine_server_client_ptr( callback_arg );
895 status = wine_server_call( req );
896 if (state) *state = reply->signaled;
898 SERVER_END_REQ;
900 /* set error but can still succeed */
901 if (resume && status == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
902 return status;
905 /**************************************************************************
906 * NtCancelTimer [NTDLL.@]
907 * ZwCancelTimer [NTDLL.@]
909 NTSTATUS WINAPI NtCancelTimer(IN HANDLE handle, OUT BOOLEAN* state)
911 NTSTATUS status;
913 SERVER_START_REQ( cancel_timer )
915 req->handle = wine_server_obj_handle( handle );
916 status = wine_server_call( req );
917 if (state) *state = reply->signaled;
919 SERVER_END_REQ;
920 return status;
923 /******************************************************************************
924 * NtQueryTimer (NTDLL.@)
926 * Retrieves information about a timer.
928 * PARAMS
929 * TimerHandle [I] The timer to retrieve information about.
930 * TimerInformationClass [I] The type of information to retrieve.
931 * TimerInformation [O] Pointer to buffer to store information in.
932 * Length [I] The length of the buffer pointed to by TimerInformation.
933 * ReturnLength [O] Optional. The size of buffer actually used.
935 * RETURNS
936 * Success: STATUS_SUCCESS
937 * Failure: STATUS_INFO_LENGTH_MISMATCH, if Length doesn't match the required data
938 * size for the class specified.
939 * STATUS_INVALID_INFO_CLASS, if an invalid TimerInformationClass was specified.
940 * STATUS_ACCESS_DENIED, if TimerHandle does not have TIMER_QUERY_STATE access
941 * to the timer.
943 NTSTATUS WINAPI NtQueryTimer(
944 HANDLE TimerHandle,
945 TIMER_INFORMATION_CLASS TimerInformationClass,
946 PVOID TimerInformation,
947 ULONG Length,
948 PULONG ReturnLength)
950 TIMER_BASIC_INFORMATION * basic_info = TimerInformation;
951 NTSTATUS status;
952 LARGE_INTEGER now;
954 TRACE("(%p,%d,%p,0x%08x,%p)\n", TimerHandle, TimerInformationClass,
955 TimerInformation, Length, ReturnLength);
957 switch (TimerInformationClass)
959 case TimerBasicInformation:
960 if (Length < sizeof(TIMER_BASIC_INFORMATION))
961 return STATUS_INFO_LENGTH_MISMATCH;
963 SERVER_START_REQ(get_timer_info)
965 req->handle = wine_server_obj_handle( TimerHandle );
966 status = wine_server_call(req);
968 /* convert server time to absolute NTDLL time */
969 basic_info->RemainingTime.QuadPart = reply->when;
970 basic_info->TimerState = reply->signaled;
972 SERVER_END_REQ;
974 /* convert from absolute into relative time */
975 NtQuerySystemTime(&now);
976 if (now.QuadPart > basic_info->RemainingTime.QuadPart)
977 basic_info->RemainingTime.QuadPart = 0;
978 else
979 basic_info->RemainingTime.QuadPart -= now.QuadPart;
981 if (ReturnLength) *ReturnLength = sizeof(TIMER_BASIC_INFORMATION);
983 return status;
986 FIXME("Unhandled class %d\n", TimerInformationClass);
987 return STATUS_INVALID_INFO_CLASS;
991 /******************************************************************************
992 * NtQueryTimerResolution [NTDLL.@]
994 NTSTATUS WINAPI NtQueryTimerResolution(OUT ULONG* min_resolution,
995 OUT ULONG* max_resolution,
996 OUT ULONG* current_resolution)
998 FIXME("(%p,%p,%p), stub!\n",
999 min_resolution, max_resolution, current_resolution);
1001 return STATUS_NOT_IMPLEMENTED;
1004 /******************************************************************************
1005 * NtSetTimerResolution [NTDLL.@]
1007 NTSTATUS WINAPI NtSetTimerResolution(IN ULONG resolution,
1008 IN BOOLEAN set_resolution,
1009 OUT ULONG* current_resolution )
1011 FIXME("(%u,%u,%p), stub!\n",
1012 resolution, set_resolution, current_resolution);
1014 return STATUS_NOT_IMPLEMENTED;
1019 /* wait operations */
1021 static NTSTATUS wait_objects( DWORD count, const HANDLE *handles,
1022 BOOLEAN wait_any, BOOLEAN alertable,
1023 const LARGE_INTEGER *timeout )
1025 select_op_t select_op;
1026 UINT i, flags = SELECT_INTERRUPTIBLE;
1028 if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
1030 if (alertable) flags |= SELECT_ALERTABLE;
1031 select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL;
1032 for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] );
1033 return server_select( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout );
1037 /******************************************************************
1038 * NtWaitForMultipleObjects (NTDLL.@)
1040 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles,
1041 BOOLEAN wait_any, BOOLEAN alertable,
1042 const LARGE_INTEGER *timeout )
1044 return wait_objects( count, handles, wait_any, alertable, timeout );
1048 /******************************************************************
1049 * NtWaitForSingleObject (NTDLL.@)
1051 NTSTATUS WINAPI NtWaitForSingleObject(HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
1053 return wait_objects( 1, &handle, FALSE, alertable, timeout );
1057 /******************************************************************
1058 * NtSignalAndWaitForSingleObject (NTDLL.@)
1060 NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE hSignalObject, HANDLE hWaitObject,
1061 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1063 select_op_t select_op;
1064 UINT flags = SELECT_INTERRUPTIBLE;
1066 if (!hSignalObject) return STATUS_INVALID_HANDLE;
1068 if (alertable) flags |= SELECT_ALERTABLE;
1069 select_op.signal_and_wait.op = SELECT_SIGNAL_AND_WAIT;
1070 select_op.signal_and_wait.wait = wine_server_obj_handle( hWaitObject );
1071 select_op.signal_and_wait.signal = wine_server_obj_handle( hSignalObject );
1072 return server_select( &select_op, sizeof(select_op.signal_and_wait), flags, timeout );
1076 /******************************************************************
1077 * NtYieldExecution (NTDLL.@)
1079 NTSTATUS WINAPI NtYieldExecution(void)
1081 #ifdef HAVE_SCHED_YIELD
1082 sched_yield();
1083 return STATUS_SUCCESS;
1084 #else
1085 return STATUS_NO_YIELD_PERFORMED;
1086 #endif
1090 /******************************************************************
1091 * NtDelayExecution (NTDLL.@)
1093 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
1095 /* if alertable, we need to query the server */
1096 if (alertable)
1097 return server_select( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout );
1099 if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */
1101 for (;;) select( 0, NULL, NULL, NULL, NULL );
1103 else
1105 LARGE_INTEGER now;
1106 timeout_t when, diff;
1108 if ((when = timeout->QuadPart) < 0)
1110 NtQuerySystemTime( &now );
1111 when = now.QuadPart - when;
1114 /* Note that we yield after establishing the desired timeout */
1115 NtYieldExecution();
1116 if (!when) return STATUS_SUCCESS;
1118 for (;;)
1120 struct timeval tv;
1121 NtQuerySystemTime( &now );
1122 diff = (when - now.QuadPart + 9) / 10;
1123 if (diff <= 0) break;
1124 tv.tv_sec = diff / 1000000;
1125 tv.tv_usec = diff % 1000000;
1126 if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
1129 return STATUS_SUCCESS;
1133 /******************************************************************************
1134 * NtCreateKeyedEvent (NTDLL.@)
1136 NTSTATUS WINAPI NtCreateKeyedEvent( HANDLE *handle, ACCESS_MASK access,
1137 const OBJECT_ATTRIBUTES *attr, ULONG flags )
1139 NTSTATUS ret;
1140 data_size_t len;
1141 struct object_attributes *objattr;
1143 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1145 SERVER_START_REQ( create_keyed_event )
1147 req->access = access;
1148 wine_server_add_data( req, objattr, len );
1149 ret = wine_server_call( req );
1150 *handle = wine_server_ptr_handle( reply->handle );
1152 SERVER_END_REQ;
1154 RtlFreeHeap( GetProcessHeap(), 0, objattr );
1155 return ret;
1158 /******************************************************************************
1159 * NtOpenKeyedEvent (NTDLL.@)
1161 NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1163 NTSTATUS ret;
1165 if ((ret = validate_open_object_attributes( attr ))) return ret;
1167 SERVER_START_REQ( open_keyed_event )
1169 req->access = access;
1170 req->attributes = attr->Attributes;
1171 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1172 if (attr->ObjectName)
1173 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1174 ret = wine_server_call( req );
1175 *handle = wine_server_ptr_handle( reply->handle );
1177 SERVER_END_REQ;
1178 return ret;
1181 /******************************************************************************
1182 * NtWaitForKeyedEvent (NTDLL.@)
1184 NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
1185 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1187 select_op_t select_op;
1188 UINT flags = SELECT_INTERRUPTIBLE;
1190 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1191 if (alertable) flags |= SELECT_ALERTABLE;
1192 select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT;
1193 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1194 select_op.keyed_event.key = wine_server_client_ptr( key );
1195 return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1198 /******************************************************************************
1199 * NtReleaseKeyedEvent (NTDLL.@)
1201 NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key,
1202 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1204 select_op_t select_op;
1205 UINT flags = SELECT_INTERRUPTIBLE;
1207 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1208 if (alertable) flags |= SELECT_ALERTABLE;
1209 select_op.keyed_event.op = SELECT_KEYED_EVENT_RELEASE;
1210 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1211 select_op.keyed_event.key = wine_server_client_ptr( key );
1212 return server_select( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1215 /******************************************************************
1216 * NtCreateIoCompletion (NTDLL.@)
1217 * ZwCreateIoCompletion (NTDLL.@)
1219 * Creates I/O completion object.
1221 * PARAMS
1222 * CompletionPort [O] created completion object handle will be placed there
1223 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1224 * ObjectAttributes [I] completion object attributes
1225 * NumberOfConcurrentThreads [I] desired number of concurrent active worker threads
1228 NTSTATUS WINAPI NtCreateIoCompletion( PHANDLE CompletionPort, ACCESS_MASK DesiredAccess,
1229 POBJECT_ATTRIBUTES attr, ULONG NumberOfConcurrentThreads )
1231 NTSTATUS status;
1232 data_size_t len;
1233 struct object_attributes *objattr;
1235 TRACE("(%p, %x, %p, %d)\n", CompletionPort, DesiredAccess, attr, NumberOfConcurrentThreads);
1237 if (!CompletionPort)
1238 return STATUS_INVALID_PARAMETER;
1240 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
1242 SERVER_START_REQ( create_completion )
1244 req->access = DesiredAccess;
1245 req->concurrent = NumberOfConcurrentThreads;
1246 wine_server_add_data( req, objattr, len );
1247 if (!(status = wine_server_call( req )))
1248 *CompletionPort = wine_server_ptr_handle( reply->handle );
1250 SERVER_END_REQ;
1252 RtlFreeHeap( GetProcessHeap(), 0, objattr );
1253 return status;
1256 /******************************************************************
1257 * NtSetIoCompletion (NTDLL.@)
1258 * ZwSetIoCompletion (NTDLL.@)
1260 * Inserts completion message into queue
1262 * PARAMS
1263 * CompletionPort [I] HANDLE to completion object
1264 * CompletionKey [I] completion key
1265 * CompletionValue [I] completion value (usually pointer to OVERLAPPED)
1266 * Status [I] operation status
1267 * NumberOfBytesTransferred [I] number of bytes transferred
1269 NTSTATUS WINAPI NtSetIoCompletion( HANDLE CompletionPort, ULONG_PTR CompletionKey,
1270 ULONG_PTR CompletionValue, NTSTATUS Status,
1271 SIZE_T NumberOfBytesTransferred )
1273 NTSTATUS status;
1275 TRACE("(%p, %lx, %lx, %x, %lx)\n", CompletionPort, CompletionKey,
1276 CompletionValue, Status, NumberOfBytesTransferred);
1278 SERVER_START_REQ( add_completion )
1280 req->handle = wine_server_obj_handle( CompletionPort );
1281 req->ckey = CompletionKey;
1282 req->cvalue = CompletionValue;
1283 req->status = Status;
1284 req->information = NumberOfBytesTransferred;
1285 status = wine_server_call( req );
1287 SERVER_END_REQ;
1288 return status;
1291 /******************************************************************
1292 * NtRemoveIoCompletion (NTDLL.@)
1293 * ZwRemoveIoCompletion (NTDLL.@)
1295 * (Wait for and) retrieve first completion message from completion object's queue
1297 * PARAMS
1298 * CompletionPort [I] HANDLE to I/O completion object
1299 * CompletionKey [O] completion key
1300 * CompletionValue [O] Completion value given in NtSetIoCompletion or in async operation
1301 * iosb [O] IO_STATUS_BLOCK of completed asynchronous operation
1302 * WaitTime [I] optional wait time in NTDLL format
1305 NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE CompletionPort, PULONG_PTR CompletionKey,
1306 PULONG_PTR CompletionValue, PIO_STATUS_BLOCK iosb,
1307 PLARGE_INTEGER WaitTime )
1309 NTSTATUS status;
1311 TRACE("(%p, %p, %p, %p, %p)\n", CompletionPort, CompletionKey,
1312 CompletionValue, iosb, WaitTime);
1314 for(;;)
1316 SERVER_START_REQ( remove_completion )
1318 req->handle = wine_server_obj_handle( CompletionPort );
1319 if (!(status = wine_server_call( req )))
1321 *CompletionKey = reply->ckey;
1322 *CompletionValue = reply->cvalue;
1323 iosb->Information = reply->information;
1324 iosb->u.Status = reply->status;
1327 SERVER_END_REQ;
1328 if (status != STATUS_PENDING) break;
1330 status = NtWaitForSingleObject( CompletionPort, FALSE, WaitTime );
1331 if (status != WAIT_OBJECT_0) break;
1333 return status;
1336 /******************************************************************
1337 * NtRemoveIoCompletionEx (NTDLL.@)
1338 * ZwRemoveIoCompletionEx (NTDLL.@)
1340 NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE port, FILE_IO_COMPLETION_INFORMATION *info, ULONG count,
1341 ULONG *written, LARGE_INTEGER *timeout, BOOLEAN alertable )
1343 NTSTATUS ret;
1344 ULONG i = 0;
1346 TRACE("%p %p %u %p %p %u\n", port, info, count, written, timeout, alertable);
1348 for (;;)
1350 for (;;)
1352 SERVER_START_REQ( remove_completion )
1354 req->handle = wine_server_obj_handle( port );
1355 if (!(ret = wine_server_call( req )))
1357 info[i].CompletionKey = reply->ckey;
1358 info[i].CompletionValue = reply->cvalue;
1359 info[i].IoStatusBlock.Information = reply->information;
1360 info[i].IoStatusBlock.u.Status = reply->status;
1363 SERVER_END_REQ;
1365 if (ret != STATUS_SUCCESS) break;
1367 if (i++ >= count) break;
1370 if (i && ret == STATUS_PENDING)
1372 ret = STATUS_SUCCESS;
1373 break;
1376 ret = NtWaitForSingleObject( port, alertable, timeout );
1377 if (ret != WAIT_OBJECT_0) break;
1380 *written = i ? i : 1;
1381 return ret;
1384 /******************************************************************
1385 * NtOpenIoCompletion (NTDLL.@)
1386 * ZwOpenIoCompletion (NTDLL.@)
1388 * Opens I/O completion object
1390 * PARAMS
1391 * CompletionPort [O] completion object handle will be placed there
1392 * DesiredAccess [I] desired access to a handle (combination of IO_COMPLETION_*)
1393 * ObjectAttributes [I] completion object name
1396 NTSTATUS WINAPI NtOpenIoCompletion( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1398 NTSTATUS status;
1400 if (!handle) return STATUS_INVALID_PARAMETER;
1401 if ((status = validate_open_object_attributes( attr ))) return status;
1403 SERVER_START_REQ( open_completion )
1405 req->access = access;
1406 req->attributes = attr->Attributes;
1407 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1408 if (attr->ObjectName)
1409 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1410 status = wine_server_call( req );
1411 *handle = wine_server_ptr_handle( reply->handle );
1413 SERVER_END_REQ;
1414 return status;
1417 /******************************************************************
1418 * NtQueryIoCompletion (NTDLL.@)
1419 * ZwQueryIoCompletion (NTDLL.@)
1421 * Requests information about given I/O completion object
1423 * PARAMS
1424 * CompletionPort [I] HANDLE to completion port to request
1425 * InformationClass [I] information class
1426 * CompletionInformation [O] user-provided buffer for data
1427 * BufferLength [I] buffer length
1428 * RequiredLength [O] required buffer length
1431 NTSTATUS WINAPI NtQueryIoCompletion( HANDLE CompletionPort, IO_COMPLETION_INFORMATION_CLASS InformationClass,
1432 PVOID CompletionInformation, ULONG BufferLength, PULONG RequiredLength )
1434 NTSTATUS status;
1436 TRACE("(%p, %d, %p, 0x%x, %p)\n", CompletionPort, InformationClass, CompletionInformation,
1437 BufferLength, RequiredLength);
1439 if (!CompletionInformation) return STATUS_INVALID_PARAMETER;
1440 switch( InformationClass )
1442 case IoCompletionBasicInformation:
1444 ULONG *info = CompletionInformation;
1446 if (RequiredLength) *RequiredLength = sizeof(*info);
1447 if (BufferLength != sizeof(*info))
1448 status = STATUS_INFO_LENGTH_MISMATCH;
1449 else
1451 SERVER_START_REQ( query_completion )
1453 req->handle = wine_server_obj_handle( CompletionPort );
1454 if (!(status = wine_server_call( req )))
1455 *info = reply->depth;
1457 SERVER_END_REQ;
1460 break;
1461 default:
1462 status = STATUS_INVALID_PARAMETER;
1463 break;
1465 return status;
1468 NTSTATUS NTDLL_AddCompletion( HANDLE hFile, ULONG_PTR CompletionValue,
1469 NTSTATUS CompletionStatus, ULONG Information )
1471 NTSTATUS status;
1473 SERVER_START_REQ( add_fd_completion )
1475 req->handle = wine_server_obj_handle( hFile );
1476 req->cvalue = CompletionValue;
1477 req->status = CompletionStatus;
1478 req->information = Information;
1479 status = wine_server_call( req );
1481 SERVER_END_REQ;
1482 return status;
1485 /******************************************************************
1486 * RtlRunOnceInitialize (NTDLL.@)
1488 void WINAPI RtlRunOnceInitialize( RTL_RUN_ONCE *once )
1490 once->Ptr = NULL;
1493 /******************************************************************
1494 * RtlRunOnceBeginInitialize (NTDLL.@)
1496 DWORD WINAPI RtlRunOnceBeginInitialize( RTL_RUN_ONCE *once, ULONG flags, void **context )
1498 if (flags & RTL_RUN_ONCE_CHECK_ONLY)
1500 ULONG_PTR val = (ULONG_PTR)once->Ptr;
1502 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1503 if ((val & 3) != 2) return STATUS_UNSUCCESSFUL;
1504 if (context) *context = (void *)(val & ~3);
1505 return STATUS_SUCCESS;
1508 for (;;)
1510 ULONG_PTR next, val = (ULONG_PTR)once->Ptr;
1512 switch (val & 3)
1514 case 0: /* first time */
1515 if (!interlocked_cmpxchg_ptr( &once->Ptr,
1516 (flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0 ))
1517 return STATUS_PENDING;
1518 break;
1520 case 1: /* in progress, wait */
1521 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1522 next = val & ~3;
1523 if (interlocked_cmpxchg_ptr( &once->Ptr, (void *)((ULONG_PTR)&next | 1),
1524 (void *)val ) == (void *)val)
1525 NtWaitForKeyedEvent( keyed_event, &next, FALSE, NULL );
1526 break;
1528 case 2: /* done */
1529 if (context) *context = (void *)(val & ~3);
1530 return STATUS_SUCCESS;
1532 case 3: /* in progress, async */
1533 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
1534 return STATUS_PENDING;
1539 /******************************************************************
1540 * RtlRunOnceComplete (NTDLL.@)
1542 DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context )
1544 if ((ULONG_PTR)context & 3) return STATUS_INVALID_PARAMETER;
1546 if (flags & RTL_RUN_ONCE_INIT_FAILED)
1548 if (context) return STATUS_INVALID_PARAMETER;
1549 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
1551 else context = (void *)((ULONG_PTR)context | 2);
1553 for (;;)
1555 ULONG_PTR val = (ULONG_PTR)once->Ptr;
1557 switch (val & 3)
1559 case 1: /* in progress */
1560 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break;
1561 val &= ~3;
1562 while (val)
1564 ULONG_PTR next = *(ULONG_PTR *)val;
1565 NtReleaseKeyedEvent( keyed_event, (void *)val, FALSE, NULL );
1566 val = next;
1568 return STATUS_SUCCESS;
1570 case 3: /* in progress, async */
1571 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
1572 if (interlocked_cmpxchg_ptr( &once->Ptr, context, (void *)val ) != (void *)val) break;
1573 return STATUS_SUCCESS;
1575 default:
1576 return STATUS_UNSUCCESSFUL;
1581 /******************************************************************
1582 * RtlRunOnceExecuteOnce (NTDLL.@)
1584 DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN func,
1585 void *param, void **context )
1587 DWORD ret = RtlRunOnceBeginInitialize( once, 0, context );
1589 if (ret != STATUS_PENDING) return ret;
1591 if (!func( once, param, context ))
1593 RtlRunOnceComplete( once, RTL_RUN_ONCE_INIT_FAILED, NULL );
1594 return STATUS_UNSUCCESSFUL;
1597 return RtlRunOnceComplete( once, 0, context ? *context : NULL );
1601 /* SRW locks implementation
1603 * The memory layout used by the lock is:
1605 * 32 31 16 0
1606 * ________________ ________________
1607 * | X| #exclusive | #shared |
1608 * ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
1609 * Since there is no space left for a separate counter of shared access
1610 * threads inside the locked section the #shared field is used for multiple
1611 * purposes. The following table lists all possible states the lock can be
1612 * in, notation: [X, #exclusive, #shared]:
1614 * [0, 0, N] -> locked by N shared access threads, if N=0 it's unlocked
1615 * [0, >=1, >=1] -> threads are requesting exclusive locks, but there are
1616 * still shared access threads inside. #shared should not be incremented
1617 * anymore!
1618 * [1, >=1, >=0] -> lock is owned by an exclusive thread and the #shared
1619 * counter can be used again to count the number of threads waiting in the
1620 * queue for shared access.
1622 * the following states are invalid and will never occur:
1623 * [0, >=1, 0], [1, 0, >=0]
1625 * The main problem arising from the fact that we have no separate counter
1626 * of shared access threads inside the locked section is that in the state
1627 * [0, >=1, >=1] above we cannot add additional waiting threads to the
1628 * shared access queue - it wouldn't be possible to distinguish waiting
1629 * threads and those that are still inside. To solve this problem the lock
1630 * uses the following approach: a thread that isn't able to allocate a
1631 * shared lock just uses the exclusive queue instead. As soon as the thread
1632 * is woken up it is in the state [1, >=1, >=0]. In this state it's again
1633 * possible to use the shared access queue. The thread atomically moves
1634 * itself to the shared access queue and releases the exclusive lock, so
1635 * that the "real" exclusive access threads have a chance. As soon as they
1636 * are all ready the shared access threads are processed.
1639 #define SRWLOCK_MASK_IN_EXCLUSIVE 0x80000000
1640 #define SRWLOCK_MASK_EXCLUSIVE_QUEUE 0x7fff0000
1641 #define SRWLOCK_MASK_SHARED_QUEUE 0x0000ffff
1642 #define SRWLOCK_RES_EXCLUSIVE 0x00010000
1643 #define SRWLOCK_RES_SHARED 0x00000001
1645 #ifdef WORDS_BIGENDIAN
1646 #define srwlock_key_exclusive(lock) (&lock->Ptr)
1647 #define srwlock_key_shared(lock) ((void *)((char *)&lock->Ptr + 2))
1648 #else
1649 #define srwlock_key_exclusive(lock) ((void *)((char *)&lock->Ptr + 2))
1650 #define srwlock_key_shared(lock) (&lock->Ptr)
1651 #endif
1653 static inline void srwlock_check_invalid( unsigned int val )
1655 /* Throw exception if it's impossible to acquire/release this lock. */
1656 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) == SRWLOCK_MASK_EXCLUSIVE_QUEUE ||
1657 (val & SRWLOCK_MASK_SHARED_QUEUE) == SRWLOCK_MASK_SHARED_QUEUE)
1658 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED);
1661 static inline unsigned int srwlock_lock_exclusive( unsigned int *dest, int incr )
1663 unsigned int val, tmp;
1664 /* Atomically modifies the value of *dest by adding incr. If the shared
1665 * queue is empty and there are threads waiting for exclusive access, then
1666 * sets the mark SRWLOCK_MASK_IN_EXCLUSIVE to signal other threads that
1667 * they are allowed again to use the shared queue counter. */
1668 for (val = *dest;; val = tmp)
1670 tmp = val + incr;
1671 srwlock_check_invalid( tmp );
1672 if ((tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(tmp & SRWLOCK_MASK_SHARED_QUEUE))
1673 tmp |= SRWLOCK_MASK_IN_EXCLUSIVE;
1674 if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val)
1675 break;
1677 return val;
1680 static inline unsigned int srwlock_unlock_exclusive( unsigned int *dest, int incr )
1682 unsigned int val, tmp;
1683 /* Atomically modifies the value of *dest by adding incr. If the queue of
1684 * threads waiting for exclusive access is empty, then remove the
1685 * SRWLOCK_MASK_IN_EXCLUSIVE flag (only the shared queue counter will
1686 * remain). */
1687 for (val = *dest;; val = tmp)
1689 tmp = val + incr;
1690 srwlock_check_invalid( tmp );
1691 if (!(tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE))
1692 tmp &= SRWLOCK_MASK_SHARED_QUEUE;
1693 if ((tmp = interlocked_cmpxchg( (int *)dest, tmp, val )) == val)
1694 break;
1696 return val;
1699 static inline void srwlock_leave_exclusive( RTL_SRWLOCK *lock, unsigned int val )
1701 /* Used when a thread leaves an exclusive section. If there are other
1702 * exclusive access threads they are processed first, followed by
1703 * the shared waiters. */
1704 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
1705 NtReleaseKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1706 else
1708 val &= SRWLOCK_MASK_SHARED_QUEUE; /* remove SRWLOCK_MASK_IN_EXCLUSIVE */
1709 while (val--)
1710 NtReleaseKeyedEvent( keyed_event, srwlock_key_shared(lock), FALSE, NULL );
1714 static inline void srwlock_leave_shared( RTL_SRWLOCK *lock, unsigned int val )
1716 /* Wake up one exclusive thread as soon as the last shared access thread
1717 * has left. */
1718 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_SHARED_QUEUE))
1719 NtReleaseKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1722 /***********************************************************************
1723 * RtlInitializeSRWLock (NTDLL.@)
1725 * NOTES
1726 * Please note that SRWLocks do not keep track of the owner of a lock.
1727 * It doesn't make any difference which thread for example unlocks an
1728 * SRWLock (see corresponding tests). This implementation uses two
1729 * keyed events (one for the exclusive waiters and one for the shared
1730 * waiters) and is limited to 2^15-1 waiting threads.
1732 void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock )
1734 lock->Ptr = NULL;
1737 /***********************************************************************
1738 * RtlAcquireSRWLockExclusive (NTDLL.@)
1740 * NOTES
1741 * Unlike RtlAcquireResourceExclusive this function doesn't allow
1742 * nested calls from the same thread. "Upgrading" a shared access lock
1743 * to an exclusive access lock also doesn't seem to be supported.
1745 void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
1747 if (srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, SRWLOCK_RES_EXCLUSIVE ))
1748 NtWaitForKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1751 /***********************************************************************
1752 * RtlAcquireSRWLockShared (NTDLL.@)
1754 * NOTES
1755 * Do not call this function recursively - it will only succeed when
1756 * there are no threads waiting for an exclusive lock!
1758 void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
1760 unsigned int val, tmp;
1761 /* Acquires a shared lock. If it's currently not possible to add elements to
1762 * the shared queue, then request exclusive access instead. */
1763 for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
1765 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
1766 tmp = val + SRWLOCK_RES_EXCLUSIVE;
1767 else
1768 tmp = val + SRWLOCK_RES_SHARED;
1769 if ((tmp = interlocked_cmpxchg( (int *)&lock->Ptr, tmp, val )) == val)
1770 break;
1773 /* Drop exclusive access again and instead requeue for shared access. */
1774 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
1776 NtWaitForKeyedEvent( keyed_event, srwlock_key_exclusive(lock), FALSE, NULL );
1777 val = srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr, (SRWLOCK_RES_SHARED
1778 - SRWLOCK_RES_EXCLUSIVE) ) - SRWLOCK_RES_EXCLUSIVE;
1779 srwlock_leave_exclusive( lock, val );
1782 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
1783 NtWaitForKeyedEvent( keyed_event, srwlock_key_shared(lock), FALSE, NULL );
1786 /***********************************************************************
1787 * RtlReleaseSRWLockExclusive (NTDLL.@)
1789 void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
1791 srwlock_leave_exclusive( lock, srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr,
1792 - SRWLOCK_RES_EXCLUSIVE ) - SRWLOCK_RES_EXCLUSIVE );
1795 /***********************************************************************
1796 * RtlReleaseSRWLockShared (NTDLL.@)
1798 void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
1800 srwlock_leave_shared( lock, srwlock_lock_exclusive( (unsigned int *)&lock->Ptr,
1801 - SRWLOCK_RES_SHARED ) - SRWLOCK_RES_SHARED );
1804 /***********************************************************************
1805 * RtlTryAcquireSRWLockExclusive (NTDLL.@)
1807 * NOTES
1808 * Similar to AcquireSRWLockExclusive recusive calls are not allowed
1809 * and will fail with return value FALSE.
1811 BOOLEAN WINAPI RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
1813 return interlocked_cmpxchg( (int *)&lock->Ptr, SRWLOCK_MASK_IN_EXCLUSIVE |
1814 SRWLOCK_RES_EXCLUSIVE, 0 ) == 0;
1817 /***********************************************************************
1818 * RtlTryAcquireSRWLockShared (NTDLL.@)
1820 BOOLEAN WINAPI RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock )
1822 unsigned int val, tmp;
1823 for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
1825 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
1826 return FALSE;
1827 if ((tmp = interlocked_cmpxchg( (int *)&lock->Ptr, val + SRWLOCK_RES_SHARED, val )) == val)
1828 break;
1830 return TRUE;
1833 /***********************************************************************
1834 * RtlInitializeConditionVariable (NTDLL.@)
1836 * Initializes the condition variable with NULL.
1838 * PARAMS
1839 * variable [O] condition variable
1841 * RETURNS
1842 * Nothing.
1844 void WINAPI RtlInitializeConditionVariable( RTL_CONDITION_VARIABLE *variable )
1846 variable->Ptr = NULL;
1849 /***********************************************************************
1850 * RtlWakeConditionVariable (NTDLL.@)
1852 * Wakes up one thread waiting on the condition variable.
1854 * PARAMS
1855 * variable [I/O] condition variable to wake up.
1857 * RETURNS
1858 * Nothing.
1860 * NOTES
1861 * The calling thread does not have to own any lock in order to call
1862 * this function.
1864 void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable )
1866 if (interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
1867 NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1870 /***********************************************************************
1871 * RtlWakeAllConditionVariable (NTDLL.@)
1873 * See WakeConditionVariable, wakes up all waiting threads.
1875 void WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *variable )
1877 int val = interlocked_xchg( (int *)&variable->Ptr, 0 );
1878 while (val-- > 0)
1879 NtReleaseKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1882 /***********************************************************************
1883 * RtlSleepConditionVariableCS (NTDLL.@)
1885 * Atomically releases the critical section and suspends the thread,
1886 * waiting for a Wake(All)ConditionVariable event. Afterwards it enters
1887 * the critical section again and returns.
1889 * PARAMS
1890 * variable [I/O] condition variable
1891 * crit [I/O] critical section to leave temporarily
1892 * timeout [I] timeout
1894 * RETURNS
1895 * see NtWaitForKeyedEvent for all possible return values.
1897 NTSTATUS WINAPI RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, RTL_CRITICAL_SECTION *crit,
1898 const LARGE_INTEGER *timeout )
1900 NTSTATUS status;
1901 interlocked_xchg_add( (int *)&variable->Ptr, 1 );
1902 RtlLeaveCriticalSection( crit );
1904 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, timeout );
1905 if (status != STATUS_SUCCESS)
1907 if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
1908 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1911 RtlEnterCriticalSection( crit );
1912 return status;
1915 /***********************************************************************
1916 * RtlSleepConditionVariableSRW (NTDLL.@)
1918 * Atomically releases the SRWLock and suspends the thread,
1919 * waiting for a Wake(All)ConditionVariable event. Afterwards it enters
1920 * the SRWLock again with the same access rights and returns.
1922 * PARAMS
1923 * variable [I/O] condition variable
1924 * lock [I/O] SRWLock to leave temporarily
1925 * timeout [I] timeout
1926 * flags [I] type of the current lock (exclusive / shared)
1928 * RETURNS
1929 * see NtWaitForKeyedEvent for all possible return values.
1931 * NOTES
1932 * the behaviour is undefined if the thread doesn't own the lock.
1934 NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, RTL_SRWLOCK *lock,
1935 const LARGE_INTEGER *timeout, ULONG flags )
1937 NTSTATUS status;
1938 interlocked_xchg_add( (int *)&variable->Ptr, 1 );
1940 if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
1941 RtlReleaseSRWLockShared( lock );
1942 else
1943 RtlReleaseSRWLockExclusive( lock );
1945 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, timeout );
1946 if (status != STATUS_SUCCESS)
1948 if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr ))
1949 status = NtWaitForKeyedEvent( keyed_event, &variable->Ptr, FALSE, NULL );
1952 if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
1953 RtlAcquireSRWLockShared( lock );
1954 else
1955 RtlAcquireSRWLockExclusive( lock );
1956 return status;