win32u: Use the dummy surface for empty layered window surfaces.
[wine.git] / dlls / ntdll / unix / sync.c
blob21e66f01875f1682dfaa16c18d4c66c84362108c
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 #if 0
25 #pragma makedep unix
26 #endif
28 #include "config.h"
30 #include <assert.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <limits.h>
34 #include <signal.h>
35 #include <sys/types.h>
36 #include <sys/mman.h>
37 #ifdef HAVE_SYS_SYSCALL_H
38 #include <sys/syscall.h>
39 #endif
40 #include <sys/time.h>
41 #include <poll.h>
42 #include <unistd.h>
43 #ifdef HAVE_SCHED_H
44 # include <sched.h>
45 #endif
46 #ifdef HAVE_SYS_RESOURCE_H
47 # include <sys/resource.h>
48 #endif
49 #include <string.h>
50 #include <stdarg.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <time.h>
54 #ifdef __APPLE__
55 # include <mach/mach_time.h>
56 #endif
57 #ifdef HAVE_KQUEUE
58 # include <sys/event.h>
59 #endif
61 #include "ntstatus.h"
62 #define WIN32_NO_STATUS
63 #include "windef.h"
64 #include "winternl.h"
65 #include "ddk/wdm.h"
66 #include "wine/server.h"
67 #include "wine/debug.h"
68 #include "unix_private.h"
70 WINE_DEFAULT_DEBUG_CHANNEL(sync);
72 HANDLE keyed_event = 0;
74 static const char *debugstr_timeout( const LARGE_INTEGER *timeout )
76 if (!timeout) return "(infinite)";
77 return wine_dbgstr_longlong( timeout->QuadPart );
80 /* return a monotonic time counter, in Win32 ticks */
81 static inline ULONGLONG monotonic_counter(void)
83 struct timeval now;
84 #ifdef __APPLE__
85 static mach_timebase_info_data_t timebase;
87 if (!timebase.denom) mach_timebase_info( &timebase );
88 #ifdef HAVE_MACH_CONTINUOUS_TIME
89 if (&mach_continuous_time != NULL)
90 return mach_continuous_time() * timebase.numer / timebase.denom / 100;
91 #endif
92 return mach_absolute_time() * timebase.numer / timebase.denom / 100;
93 #elif defined(HAVE_CLOCK_GETTIME)
94 struct timespec ts;
95 #ifdef CLOCK_MONOTONIC_RAW
96 if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts ))
97 return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
98 #endif
99 if (!clock_gettime( CLOCK_MONOTONIC, &ts ))
100 return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
101 #endif
102 gettimeofday( &now, 0 );
103 return ticks_from_time_t( now.tv_sec ) + now.tv_usec * 10 - server_start_time;
106 #ifdef __linux__
108 #define USE_FUTEX
110 #include <linux/futex.h>
112 static inline int futex_wait( const LONG *addr, int val, struct timespec *timeout )
114 #if (defined(__i386__) || defined(__arm__)) && _TIME_BITS==64
115 if (timeout && sizeof(*timeout) != 8)
117 struct {
118 long tv_sec;
119 long tv_nsec;
120 } timeout32 = { timeout->tv_sec, timeout->tv_nsec };
122 return syscall( __NR_futex, addr, FUTEX_WAIT_PRIVATE, val, &timeout32, 0, 0 );
124 #endif
125 return syscall( __NR_futex, addr, FUTEX_WAIT_PRIVATE, val, timeout, 0, 0 );
128 static inline int futex_wake_one( const LONG *addr )
130 return syscall( __NR_futex, addr, FUTEX_WAKE_PRIVATE, 1, NULL, 0, 0 );
133 #elif defined(__APPLE__)
135 #define USE_FUTEX
137 #include <AvailabilityMacros.h>
139 #ifdef MAC_OS_VERSION_14_4
140 #include <os/os_sync_wait_on_address.h>
141 #endif
143 #define UL_COMPARE_AND_WAIT 1
145 extern int __ulock_wait( uint32_t operation, void *addr, uint64_t value, uint32_t timeout );
147 extern int __ulock_wake( uint32_t operation, void *addr, uint64_t wake_value );
149 static inline int futex_wait( const LONG *addr, int val, struct timespec *timeout )
151 #ifdef MAC_OS_VERSION_14_4
152 if (__builtin_available( macOS 14.4, * ))
154 /* 18446744073 seconds could overflow a uint64_t in nanoseconds */
155 if (timeout && timeout->tv_sec < 18446744073)
157 uint64_t ns_timeout = (timeout->tv_sec * 1000000000) + timeout->tv_nsec;
159 if (!ns_timeout)
161 errno = ETIMEDOUT;
162 return -1;
164 return os_sync_wait_on_address_with_timeout( (void *)addr, (uint64_t)val, 4, OS_SYNC_WAIT_ON_ADDRESS_NONE,
165 OS_CLOCK_MACH_ABSOLUTE_TIME, ns_timeout );
168 return os_sync_wait_on_address( (void *)addr, (uint64_t)val, 4, OS_SYNC_WAIT_ON_ADDRESS_NONE );
170 #endif
172 /* 4294 seconds could overflow a uint32_t in microseconds */
173 if (timeout && timeout->tv_sec < 4294)
175 uint32_t us_timeout = ((uint32_t)timeout->tv_sec * 1000000) + ((uint32_t)timeout->tv_nsec / 1000);
177 if (!us_timeout)
179 errno = ETIMEDOUT;
180 return -1;
182 return __ulock_wait( UL_COMPARE_AND_WAIT, (void *)addr, (uint64_t)val, us_timeout );
185 return __ulock_wait( UL_COMPARE_AND_WAIT, (void *)addr, (uint64_t)val, 0 );
188 static inline int futex_wake_one( const LONG *addr )
190 #ifdef MAC_OS_VERSION_14_4
191 if (__builtin_available( macOS 14.4, * ))
192 return os_sync_wake_by_address_any( (void *)addr, 4, OS_SYNC_WAKE_BY_ADDRESS_NONE );
193 #endif
194 return __ulock_wake( UL_COMPARE_AND_WAIT, (void *)addr, 0 );
197 #endif /* __APPLE__ */
199 /* create a struct security_descriptor and contained information in one contiguous piece of memory */
200 unsigned int alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_attributes **ret,
201 data_size_t *ret_len )
203 unsigned int len = sizeof(**ret);
204 SID *owner = NULL, *group = NULL;
205 ACL *dacl = NULL, *sacl = NULL;
206 SECURITY_DESCRIPTOR *sd;
208 *ret = NULL;
209 *ret_len = 0;
211 if (!attr) return STATUS_SUCCESS;
213 if (attr->Length != sizeof(*attr)) return STATUS_INVALID_PARAMETER;
215 if ((sd = attr->SecurityDescriptor))
217 len += sizeof(struct security_descriptor);
218 if (sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
219 if (sd->Control & SE_SELF_RELATIVE)
221 SECURITY_DESCRIPTOR_RELATIVE *rel = (SECURITY_DESCRIPTOR_RELATIVE *)sd;
222 if (rel->Owner) owner = (PSID)((BYTE *)rel + rel->Owner);
223 if (rel->Group) group = (PSID)((BYTE *)rel + rel->Group);
224 if ((sd->Control & SE_SACL_PRESENT) && rel->Sacl) sacl = (PSID)((BYTE *)rel + rel->Sacl);
225 if ((sd->Control & SE_DACL_PRESENT) && rel->Dacl) dacl = (PSID)((BYTE *)rel + rel->Dacl);
227 else
229 owner = sd->Owner;
230 group = sd->Group;
231 if (sd->Control & SE_SACL_PRESENT) sacl = sd->Sacl;
232 if (sd->Control & SE_DACL_PRESENT) dacl = sd->Dacl;
235 if (owner) len += offsetof( SID, SubAuthority[owner->SubAuthorityCount] );
236 if (group) len += offsetof( SID, SubAuthority[group->SubAuthorityCount] );
237 if (sacl) len += sacl->AclSize;
238 if (dacl) len += dacl->AclSize;
240 /* fix alignment for the Unicode name that follows the structure */
241 len = (len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
244 if (attr->ObjectName)
246 if ((ULONG_PTR)attr->ObjectName->Buffer & (sizeof(WCHAR) - 1)) return STATUS_DATATYPE_MISALIGNMENT;
247 if (attr->ObjectName->Length & (sizeof(WCHAR) - 1)) return STATUS_OBJECT_NAME_INVALID;
248 len += attr->ObjectName->Length;
250 else if (attr->RootDirectory) return STATUS_OBJECT_NAME_INVALID;
252 len = (len + 3) & ~3; /* DWORD-align the entire structure */
254 if (!(*ret = calloc( len, 1 ))) return STATUS_NO_MEMORY;
256 (*ret)->rootdir = wine_server_obj_handle( attr->RootDirectory );
257 (*ret)->attributes = attr->Attributes;
259 if (attr->SecurityDescriptor)
261 struct security_descriptor *descr = (struct security_descriptor *)(*ret + 1);
262 unsigned char *ptr = (unsigned char *)(descr + 1);
264 descr->control = sd->Control & ~SE_SELF_RELATIVE;
265 if (owner) descr->owner_len = offsetof( SID, SubAuthority[owner->SubAuthorityCount] );
266 if (group) descr->group_len = offsetof( SID, SubAuthority[group->SubAuthorityCount] );
267 if (sacl) descr->sacl_len = sacl->AclSize;
268 if (dacl) descr->dacl_len = dacl->AclSize;
270 memcpy( ptr, owner, descr->owner_len );
271 ptr += descr->owner_len;
272 memcpy( ptr, group, descr->group_len );
273 ptr += descr->group_len;
274 memcpy( ptr, sacl, descr->sacl_len );
275 ptr += descr->sacl_len;
276 memcpy( ptr, dacl, descr->dacl_len );
277 (*ret)->sd_len = (sizeof(*descr) + descr->owner_len + descr->group_len + descr->sacl_len +
278 descr->dacl_len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
281 if (attr->ObjectName)
283 unsigned char *ptr = (unsigned char *)(*ret + 1) + (*ret)->sd_len;
284 (*ret)->name_len = attr->ObjectName->Length;
285 memcpy( ptr, attr->ObjectName->Buffer, (*ret)->name_len );
288 *ret_len = len;
289 return STATUS_SUCCESS;
293 static unsigned int validate_open_object_attributes( const OBJECT_ATTRIBUTES *attr )
295 if (!attr || attr->Length != sizeof(*attr)) return STATUS_INVALID_PARAMETER;
297 if (attr->ObjectName)
299 if ((ULONG_PTR)attr->ObjectName->Buffer & (sizeof(WCHAR) - 1)) return STATUS_DATATYPE_MISALIGNMENT;
300 if (attr->ObjectName->Length & (sizeof(WCHAR) - 1)) return STATUS_OBJECT_NAME_INVALID;
302 else if (attr->RootDirectory) return STATUS_OBJECT_NAME_INVALID;
304 return STATUS_SUCCESS;
308 /******************************************************************************
309 * NtCreateSemaphore (NTDLL.@)
311 NTSTATUS WINAPI NtCreateSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
312 LONG initial, LONG max )
314 unsigned int ret;
315 data_size_t len;
316 struct object_attributes *objattr;
318 *handle = 0;
319 if (max <= 0 || initial < 0 || initial > max) return STATUS_INVALID_PARAMETER;
320 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
322 SERVER_START_REQ( create_semaphore )
324 req->access = access;
325 req->initial = initial;
326 req->max = max;
327 wine_server_add_data( req, objattr, len );
328 ret = wine_server_call( req );
329 *handle = wine_server_ptr_handle( reply->handle );
331 SERVER_END_REQ;
333 free( objattr );
334 return ret;
338 /******************************************************************************
339 * NtOpenSemaphore (NTDLL.@)
341 NTSTATUS WINAPI NtOpenSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
343 unsigned int ret;
345 *handle = 0;
346 if ((ret = validate_open_object_attributes( attr ))) return ret;
348 SERVER_START_REQ( open_semaphore )
350 req->access = access;
351 req->attributes = attr->Attributes;
352 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
353 if (attr->ObjectName)
354 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
355 ret = wine_server_call( req );
356 *handle = wine_server_ptr_handle( reply->handle );
358 SERVER_END_REQ;
359 return ret;
363 /******************************************************************************
364 * NtQuerySemaphore (NTDLL.@)
366 NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS class,
367 void *info, ULONG len, ULONG *ret_len )
369 unsigned int ret;
370 SEMAPHORE_BASIC_INFORMATION *out = info;
372 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, (int)len, ret_len);
374 if (class != SemaphoreBasicInformation)
376 FIXME("(%p,%d,%u) Unknown class\n", handle, class, (int)len);
377 return STATUS_INVALID_INFO_CLASS;
380 if (len != sizeof(SEMAPHORE_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
382 SERVER_START_REQ( query_semaphore )
384 req->handle = wine_server_obj_handle( handle );
385 if (!(ret = wine_server_call( req )))
387 out->CurrentCount = reply->current;
388 out->MaximumCount = reply->max;
389 if (ret_len) *ret_len = sizeof(SEMAPHORE_BASIC_INFORMATION);
392 SERVER_END_REQ;
393 return ret;
397 /******************************************************************************
398 * NtReleaseSemaphore (NTDLL.@)
400 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, ULONG *previous )
402 unsigned int ret;
404 SERVER_START_REQ( release_semaphore )
406 req->handle = wine_server_obj_handle( handle );
407 req->count = count;
408 if (!(ret = wine_server_call( req )))
410 if (previous) *previous = reply->prev_count;
413 SERVER_END_REQ;
414 return ret;
418 /**************************************************************************
419 * NtCreateEvent (NTDLL.@)
421 NTSTATUS WINAPI NtCreateEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
422 EVENT_TYPE type, BOOLEAN state )
424 unsigned int ret;
425 data_size_t len;
426 struct object_attributes *objattr;
428 *handle = 0;
429 if (type != NotificationEvent && type != SynchronizationEvent) return STATUS_INVALID_PARAMETER;
430 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
432 SERVER_START_REQ( create_event )
434 req->access = access;
435 req->manual_reset = (type == NotificationEvent);
436 req->initial_state = state;
437 wine_server_add_data( req, objattr, len );
438 ret = wine_server_call( req );
439 *handle = wine_server_ptr_handle( reply->handle );
441 SERVER_END_REQ;
443 free( objattr );
444 return ret;
448 /******************************************************************************
449 * NtOpenEvent (NTDLL.@)
451 NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
453 unsigned int ret;
455 *handle = 0;
456 if ((ret = validate_open_object_attributes( attr ))) return ret;
458 SERVER_START_REQ( open_event )
460 req->access = access;
461 req->attributes = attr->Attributes;
462 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
463 if (attr->ObjectName)
464 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
465 ret = wine_server_call( req );
466 *handle = wine_server_ptr_handle( reply->handle );
468 SERVER_END_REQ;
469 return ret;
473 /******************************************************************************
474 * NtSetEvent (NTDLL.@)
476 NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state )
478 unsigned int ret;
480 SERVER_START_REQ( event_op )
482 req->handle = wine_server_obj_handle( handle );
483 req->op = SET_EVENT;
484 ret = wine_server_call( req );
485 if (!ret && prev_state) *prev_state = reply->state;
487 SERVER_END_REQ;
488 return ret;
492 /******************************************************************************
493 * NtResetEvent (NTDLL.@)
495 NTSTATUS WINAPI NtResetEvent( HANDLE handle, LONG *prev_state )
497 unsigned int ret;
499 SERVER_START_REQ( event_op )
501 req->handle = wine_server_obj_handle( handle );
502 req->op = RESET_EVENT;
503 ret = wine_server_call( req );
504 if (!ret && prev_state) *prev_state = reply->state;
506 SERVER_END_REQ;
507 return ret;
511 /******************************************************************************
512 * NtClearEvent (NTDLL.@)
514 NTSTATUS WINAPI NtClearEvent( HANDLE handle )
516 /* FIXME: same as NtResetEvent ??? */
517 return NtResetEvent( handle, NULL );
521 /******************************************************************************
522 * NtPulseEvent (NTDLL.@)
524 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, LONG *prev_state )
526 unsigned int ret;
528 SERVER_START_REQ( event_op )
530 req->handle = wine_server_obj_handle( handle );
531 req->op = PULSE_EVENT;
532 ret = wine_server_call( req );
533 if (!ret && prev_state) *prev_state = reply->state;
535 SERVER_END_REQ;
536 return ret;
540 /******************************************************************************
541 * NtQueryEvent (NTDLL.@)
543 NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class,
544 void *info, ULONG len, ULONG *ret_len )
546 unsigned int ret;
547 EVENT_BASIC_INFORMATION *out = info;
549 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, (int)len, ret_len);
551 if (class != EventBasicInformation)
553 FIXME("(%p, %d, %d) Unknown class\n", handle, class, (int)len);
554 return STATUS_INVALID_INFO_CLASS;
557 if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
559 SERVER_START_REQ( query_event )
561 req->handle = wine_server_obj_handle( handle );
562 if (!(ret = wine_server_call( req )))
564 out->EventType = reply->manual_reset ? NotificationEvent : SynchronizationEvent;
565 out->EventState = reply->state;
566 if (ret_len) *ret_len = sizeof(EVENT_BASIC_INFORMATION);
569 SERVER_END_REQ;
570 return ret;
574 /******************************************************************************
575 * NtCreateMutant (NTDLL.@)
577 NTSTATUS WINAPI NtCreateMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
578 BOOLEAN owned )
580 unsigned int ret;
581 data_size_t len;
582 struct object_attributes *objattr;
584 *handle = 0;
585 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
587 SERVER_START_REQ( create_mutex )
589 req->access = access;
590 req->owned = owned;
591 wine_server_add_data( req, objattr, len );
592 ret = wine_server_call( req );
593 *handle = wine_server_ptr_handle( reply->handle );
595 SERVER_END_REQ;
597 free( objattr );
598 return ret;
602 /**************************************************************************
603 * NtOpenMutant (NTDLL.@)
605 NTSTATUS WINAPI NtOpenMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
607 unsigned int ret;
609 *handle = 0;
610 if ((ret = validate_open_object_attributes( attr ))) return ret;
612 SERVER_START_REQ( open_mutex )
614 req->access = access;
615 req->attributes = attr->Attributes;
616 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
617 if (attr->ObjectName)
618 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
619 ret = wine_server_call( req );
620 *handle = wine_server_ptr_handle( reply->handle );
622 SERVER_END_REQ;
623 return ret;
627 /**************************************************************************
628 * NtReleaseMutant (NTDLL.@)
630 NTSTATUS WINAPI NtReleaseMutant( HANDLE handle, LONG *prev_count )
632 unsigned int ret;
634 SERVER_START_REQ( release_mutex )
636 req->handle = wine_server_obj_handle( handle );
637 ret = wine_server_call( req );
638 if (prev_count) *prev_count = 1 - reply->prev_count;
640 SERVER_END_REQ;
641 return ret;
645 /******************************************************************
646 * NtQueryMutant (NTDLL.@)
648 NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class,
649 void *info, ULONG len, ULONG *ret_len )
651 unsigned int ret;
652 MUTANT_BASIC_INFORMATION *out = info;
654 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, (int)len, ret_len);
656 if (class != MutantBasicInformation)
658 FIXME( "(%p, %d, %d) Unknown class\n", handle, class, (int)len );
659 return STATUS_INVALID_INFO_CLASS;
662 if (len != sizeof(MUTANT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
664 SERVER_START_REQ( query_mutex )
666 req->handle = wine_server_obj_handle( handle );
667 if (!(ret = wine_server_call( req )))
669 out->CurrentCount = 1 - reply->count;
670 out->OwnedByCaller = reply->owned;
671 out->AbandonedState = reply->abandoned;
672 if (ret_len) *ret_len = sizeof(MUTANT_BASIC_INFORMATION);
675 SERVER_END_REQ;
676 return ret;
680 /**************************************************************************
681 * NtCreateJobObject (NTDLL.@)
683 NTSTATUS WINAPI NtCreateJobObject( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
685 unsigned int ret;
686 data_size_t len;
687 struct object_attributes *objattr;
689 *handle = 0;
690 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
692 SERVER_START_REQ( create_job )
694 req->access = access;
695 wine_server_add_data( req, objattr, len );
696 ret = wine_server_call( req );
697 *handle = wine_server_ptr_handle( reply->handle );
699 SERVER_END_REQ;
700 free( objattr );
701 return ret;
705 /**************************************************************************
706 * NtOpenJobObject (NTDLL.@)
708 NTSTATUS WINAPI NtOpenJobObject( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
710 unsigned int ret;
712 *handle = 0;
713 if ((ret = validate_open_object_attributes( attr ))) return ret;
715 SERVER_START_REQ( open_job )
717 req->access = access;
718 req->attributes = attr->Attributes;
719 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
720 if (attr->ObjectName)
721 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
722 ret = wine_server_call( req );
723 *handle = wine_server_ptr_handle( reply->handle );
725 SERVER_END_REQ;
726 return ret;
730 /**************************************************************************
731 * NtTerminateJobObject (NTDLL.@)
733 NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status )
735 unsigned int ret;
737 TRACE( "(%p, %d)\n", handle, (int)status );
739 SERVER_START_REQ( terminate_job )
741 req->handle = wine_server_obj_handle( handle );
742 req->status = status;
743 ret = wine_server_call( req );
745 SERVER_END_REQ;
747 return ret;
751 /**************************************************************************
752 * NtQueryInformationJobObject (NTDLL.@)
754 NTSTATUS WINAPI NtQueryInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, void *info,
755 ULONG len, ULONG *ret_len )
757 unsigned int ret;
759 TRACE( "semi-stub: %p %u %p %u %p\n", handle, class, info, (int)len, ret_len );
761 if (class >= MaxJobObjectInfoClass) return STATUS_INVALID_PARAMETER;
763 switch (class)
765 case JobObjectBasicAccountingInformation:
767 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION *accounting = info;
769 if (len < sizeof(*accounting)) return STATUS_INFO_LENGTH_MISMATCH;
770 SERVER_START_REQ(get_job_info)
772 req->handle = wine_server_obj_handle( handle );
773 if (!(ret = wine_server_call( req )))
775 memset( accounting, 0, sizeof(*accounting) );
776 accounting->TotalProcesses = reply->total_processes;
777 accounting->ActiveProcesses = reply->active_processes;
780 SERVER_END_REQ;
781 if (ret_len) *ret_len = sizeof(*accounting);
782 return ret;
784 case JobObjectBasicProcessIdList:
786 JOBOBJECT_BASIC_PROCESS_ID_LIST *process = info;
787 DWORD count, i;
789 if (len < sizeof(*process)) return STATUS_INFO_LENGTH_MISMATCH;
791 count = len - offsetof( JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList );
792 count /= sizeof(process->ProcessIdList[0]);
794 SERVER_START_REQ( get_job_info )
796 req->handle = wine_server_user_handle(handle);
797 wine_server_set_reply(req, process->ProcessIdList, count * sizeof(process_id_t));
798 if (!(ret = wine_server_call(req)))
800 process->NumberOfAssignedProcesses = reply->active_processes;
801 process->NumberOfProcessIdsInList = min(count, reply->active_processes);
804 SERVER_END_REQ;
806 if (ret != STATUS_SUCCESS) return ret;
808 if (sizeof(process_id_t) < sizeof(process->ProcessIdList[0]))
810 /* start from the end to not overwrite */
811 for (i = process->NumberOfProcessIdsInList; i--;)
813 ULONG_PTR id = ((process_id_t *)process->ProcessIdList)[i];
814 process->ProcessIdList[i] = id;
818 if (ret_len)
819 *ret_len = offsetof( JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[process->NumberOfProcessIdsInList] );
820 return count < process->NumberOfAssignedProcesses ? STATUS_MORE_ENTRIES : STATUS_SUCCESS;
822 case JobObjectExtendedLimitInformation:
824 JOBOBJECT_EXTENDED_LIMIT_INFORMATION *extended_limit = info;
826 if (len < sizeof(*extended_limit)) return STATUS_INFO_LENGTH_MISMATCH;
827 memset( extended_limit, 0, sizeof(*extended_limit) );
828 if (ret_len) *ret_len = sizeof(*extended_limit);
829 return STATUS_SUCCESS;
831 case JobObjectBasicLimitInformation:
833 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit = info;
835 if (len < sizeof(*basic_limit)) return STATUS_INFO_LENGTH_MISMATCH;
836 memset( basic_limit, 0, sizeof(*basic_limit) );
837 if (ret_len) *ret_len = sizeof(*basic_limit);
838 return STATUS_SUCCESS;
840 default:
841 return STATUS_NOT_IMPLEMENTED;
846 /**************************************************************************
847 * NtSetInformationJobObject (NTDLL.@)
849 NTSTATUS WINAPI NtSetInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, void *info, ULONG len )
851 unsigned int status = STATUS_NOT_IMPLEMENTED;
852 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit;
853 ULONG info_size = sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION);
854 DWORD limit_flags = JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS;
856 TRACE( "(%p, %u, %p, %u)\n", handle, class, info, (int)len );
858 if (class >= MaxJobObjectInfoClass) return STATUS_INVALID_PARAMETER;
860 switch (class)
863 case JobObjectExtendedLimitInformation:
864 info_size = sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION);
865 limit_flags = JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS;
866 /* fall through */
867 case JobObjectBasicLimitInformation:
868 if (len != info_size) return STATUS_INVALID_PARAMETER;
869 basic_limit = info;
870 if (basic_limit->LimitFlags & ~limit_flags) return STATUS_INVALID_PARAMETER;
871 SERVER_START_REQ( set_job_limits )
873 req->handle = wine_server_obj_handle( handle );
874 req->limit_flags = basic_limit->LimitFlags;
875 status = wine_server_call( req );
877 SERVER_END_REQ;
878 break;
879 case JobObjectAssociateCompletionPortInformation:
880 if (len != sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT)) return STATUS_INVALID_PARAMETER;
881 SERVER_START_REQ( set_job_completion_port )
883 JOBOBJECT_ASSOCIATE_COMPLETION_PORT *port_info = info;
884 req->job = wine_server_obj_handle( handle );
885 req->port = wine_server_obj_handle( port_info->CompletionPort );
886 req->key = wine_server_client_ptr( port_info->CompletionKey );
887 status = wine_server_call( req );
889 SERVER_END_REQ;
890 break;
891 case JobObjectBasicUIRestrictions:
892 status = STATUS_SUCCESS;
893 /* fall through */
894 default:
895 FIXME( "stub: %p %u %p %u\n", handle, class, info, (int)len );
897 return status;
901 /**************************************************************************
902 * NtIsProcessInJob (NTDLL.@)
904 NTSTATUS WINAPI NtIsProcessInJob( HANDLE process, HANDLE job )
906 unsigned int status;
908 TRACE( "(%p %p)\n", job, process );
910 SERVER_START_REQ( process_in_job )
912 req->job = wine_server_obj_handle( job );
913 req->process = wine_server_obj_handle( process );
914 status = wine_server_call( req );
916 SERVER_END_REQ;
917 return status;
921 /**************************************************************************
922 * NtAssignProcessToJobObject (NTDLL.@)
924 NTSTATUS WINAPI NtAssignProcessToJobObject( HANDLE job, HANDLE process )
926 unsigned int status;
928 TRACE( "(%p %p)\n", job, process );
930 SERVER_START_REQ( assign_job )
932 req->job = wine_server_obj_handle( job );
933 req->process = wine_server_obj_handle( process );
934 status = wine_server_call( req );
936 SERVER_END_REQ;
937 return status;
941 /**********************************************************************
942 * NtCreateDebugObject (NTDLL.@)
944 NTSTATUS WINAPI NtCreateDebugObject( HANDLE *handle, ACCESS_MASK access,
945 OBJECT_ATTRIBUTES *attr, ULONG flags )
947 unsigned int ret;
948 data_size_t len;
949 struct object_attributes *objattr;
951 *handle = 0;
952 if (flags & ~DEBUG_KILL_ON_CLOSE) return STATUS_INVALID_PARAMETER;
953 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
955 SERVER_START_REQ( create_debug_obj )
957 req->access = access;
958 req->flags = flags;
959 wine_server_add_data( req, objattr, len );
960 ret = wine_server_call( req );
961 *handle = wine_server_ptr_handle( reply->handle );
963 SERVER_END_REQ;
964 free( objattr );
965 return ret;
969 /**********************************************************************
970 * NtSetInformationDebugObject (NTDLL.@)
972 NTSTATUS WINAPI NtSetInformationDebugObject( HANDLE handle, DEBUGOBJECTINFOCLASS class,
973 void *info, ULONG len, ULONG *ret_len )
975 unsigned int ret;
976 ULONG flags;
978 if (class != DebugObjectKillProcessOnExitInformation) return STATUS_INVALID_PARAMETER;
979 if (len != sizeof(ULONG))
981 if (ret_len) *ret_len = sizeof(ULONG);
982 return STATUS_INFO_LENGTH_MISMATCH;
984 flags = *(ULONG *)info;
985 if (flags & ~DEBUG_KILL_ON_CLOSE) return STATUS_INVALID_PARAMETER;
987 SERVER_START_REQ( set_debug_obj_info )
989 req->debug = wine_server_obj_handle( handle );
990 req->flags = flags;
991 ret = wine_server_call( req );
993 SERVER_END_REQ;
994 if (!ret && ret_len) *ret_len = 0;
995 return ret;
999 /* convert the server event data to an NT state change; helper for NtWaitForDebugEvent */
1000 static NTSTATUS event_data_to_state_change( const debug_event_t *data, DBGUI_WAIT_STATE_CHANGE *state )
1002 int i;
1004 switch (data->code)
1006 case DbgIdle:
1007 case DbgReplyPending:
1008 return STATUS_PENDING;
1009 case DbgCreateThreadStateChange:
1011 DBGUI_CREATE_THREAD *info = &state->StateInfo.CreateThread;
1012 info->HandleToThread = wine_server_ptr_handle( data->create_thread.handle );
1013 info->NewThread.StartAddress = wine_server_get_ptr( data->create_thread.start );
1014 return STATUS_SUCCESS;
1016 case DbgCreateProcessStateChange:
1018 DBGUI_CREATE_PROCESS *info = &state->StateInfo.CreateProcessInfo;
1019 info->HandleToProcess = wine_server_ptr_handle( data->create_process.process );
1020 info->HandleToThread = wine_server_ptr_handle( data->create_process.thread );
1021 info->NewProcess.FileHandle = wine_server_ptr_handle( data->create_process.file );
1022 info->NewProcess.BaseOfImage = wine_server_get_ptr( data->create_process.base );
1023 info->NewProcess.DebugInfoFileOffset = data->create_process.dbg_offset;
1024 info->NewProcess.DebugInfoSize = data->create_process.dbg_size;
1025 info->NewProcess.InitialThread.StartAddress = wine_server_get_ptr( data->create_process.start );
1026 return STATUS_SUCCESS;
1028 case DbgExitThreadStateChange:
1029 state->StateInfo.ExitThread.ExitStatus = data->exit.exit_code;
1030 return STATUS_SUCCESS;
1031 case DbgExitProcessStateChange:
1032 state->StateInfo.ExitProcess.ExitStatus = data->exit.exit_code;
1033 return STATUS_SUCCESS;
1034 case DbgExceptionStateChange:
1035 case DbgBreakpointStateChange:
1036 case DbgSingleStepStateChange:
1038 DBGKM_EXCEPTION *info = &state->StateInfo.Exception;
1039 info->FirstChance = data->exception.first;
1040 info->ExceptionRecord.ExceptionCode = data->exception.exc_code;
1041 info->ExceptionRecord.ExceptionFlags = data->exception.flags;
1042 info->ExceptionRecord.ExceptionRecord = wine_server_get_ptr( data->exception.record );
1043 info->ExceptionRecord.ExceptionAddress = wine_server_get_ptr( data->exception.address );
1044 info->ExceptionRecord.NumberParameters = data->exception.nb_params;
1045 for (i = 0; i < data->exception.nb_params; i++)
1046 info->ExceptionRecord.ExceptionInformation[i] = data->exception.params[i];
1047 return STATUS_SUCCESS;
1049 case DbgLoadDllStateChange:
1051 DBGKM_LOAD_DLL *info = &state->StateInfo.LoadDll;
1052 info->FileHandle = wine_server_ptr_handle( data->load_dll.handle );
1053 info->BaseOfDll = wine_server_get_ptr( data->load_dll.base );
1054 info->DebugInfoFileOffset = data->load_dll.dbg_offset;
1055 info->DebugInfoSize = data->load_dll.dbg_size;
1056 info->NamePointer = wine_server_get_ptr( data->load_dll.name );
1057 if ((DWORD_PTR)data->load_dll.base != data->load_dll.base)
1058 return STATUS_PARTIAL_COPY;
1059 return STATUS_SUCCESS;
1061 case DbgUnloadDllStateChange:
1062 state->StateInfo.UnloadDll.BaseAddress = wine_server_get_ptr( data->unload_dll.base );
1063 if ((DWORD_PTR)data->unload_dll.base != data->unload_dll.base)
1064 return STATUS_PARTIAL_COPY;
1065 return STATUS_SUCCESS;
1067 return STATUS_INTERNAL_ERROR;
1070 #ifndef _WIN64
1071 /* helper to NtWaitForDebugEvent; retrieve machine from PE image */
1072 static NTSTATUS get_image_machine( HANDLE handle, USHORT *machine )
1074 IMAGE_DOS_HEADER dos_hdr;
1075 IMAGE_NT_HEADERS nt_hdr;
1076 IO_STATUS_BLOCK iosb;
1077 LARGE_INTEGER offset;
1078 FILE_POSITION_INFORMATION pos_info;
1079 NTSTATUS status;
1081 offset.QuadPart = 0;
1082 status = NtReadFile( handle, NULL, NULL, NULL,
1083 &iosb, &dos_hdr, sizeof(dos_hdr), &offset, NULL );
1084 if (!status)
1086 offset.QuadPart = dos_hdr.e_lfanew;
1087 status = NtReadFile( handle, NULL, NULL, NULL, &iosb,
1088 &nt_hdr, FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader), &offset, NULL );
1089 if (!status)
1090 *machine = nt_hdr.FileHeader.Machine;
1091 /* Reset file pos at beginning of file */
1092 pos_info.CurrentByteOffset.QuadPart = 0;
1093 NtSetInformationFile( handle, &iosb, &pos_info, sizeof(pos_info), FilePositionInformation );
1095 return status;
1097 #endif
1099 /**********************************************************************
1100 * NtWaitForDebugEvent (NTDLL.@)
1102 NTSTATUS WINAPI NtWaitForDebugEvent( HANDLE handle, BOOLEAN alertable, LARGE_INTEGER *timeout,
1103 DBGUI_WAIT_STATE_CHANGE *state )
1105 debug_event_t data;
1106 unsigned int ret;
1107 BOOL wait = TRUE;
1109 for (;;)
1111 SERVER_START_REQ( wait_debug_event )
1113 req->debug = wine_server_obj_handle( handle );
1114 wine_server_set_reply( req, &data, sizeof(data) );
1115 ret = wine_server_call( req );
1116 if (!ret)
1118 ret = event_data_to_state_change( &data, state );
1119 state->NewState = data.code;
1120 state->AppClientId.UniqueProcess = ULongToHandle( reply->pid );
1121 state->AppClientId.UniqueThread = ULongToHandle( reply->tid );
1124 SERVER_END_REQ;
1126 #ifndef _WIN64
1127 /* don't pass 64bit load events to 32bit callers */
1128 if (!ret && state->NewState == DbgLoadDllStateChange)
1130 USHORT machine;
1131 if (!get_image_machine( state->StateInfo.LoadDll.FileHandle, &machine ) &&
1132 machine != current_machine)
1133 ret = STATUS_PARTIAL_COPY;
1135 if (ret == STATUS_PARTIAL_COPY)
1137 if (state->NewState == DbgLoadDllStateChange)
1138 NtClose( state->StateInfo.LoadDll.FileHandle );
1139 NtDebugContinue( handle, &state->AppClientId, DBG_CONTINUE );
1140 wait = TRUE;
1141 continue;
1143 #endif
1144 if (ret != STATUS_PENDING) return ret;
1145 if (!wait) return STATUS_TIMEOUT;
1146 wait = FALSE;
1147 ret = NtWaitForSingleObject( handle, alertable, timeout );
1148 if (ret != STATUS_WAIT_0) return ret;
1153 /**************************************************************************
1154 * NtCreateDirectoryObject (NTDLL.@)
1156 NTSTATUS WINAPI NtCreateDirectoryObject( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
1158 unsigned int ret;
1159 data_size_t len;
1160 struct object_attributes *objattr;
1162 *handle = 0;
1163 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1165 SERVER_START_REQ( create_directory )
1167 req->access = access;
1168 wine_server_add_data( req, objattr, len );
1169 ret = wine_server_call( req );
1170 *handle = wine_server_ptr_handle( reply->handle );
1172 SERVER_END_REQ;
1173 free( objattr );
1174 return ret;
1178 /**************************************************************************
1179 * NtOpenDirectoryObject (NTDLL.@)
1181 NTSTATUS WINAPI NtOpenDirectoryObject( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1183 unsigned int ret;
1185 *handle = 0;
1186 if ((ret = validate_open_object_attributes( attr ))) return ret;
1188 SERVER_START_REQ( open_directory )
1190 req->access = access;
1191 req->attributes = attr->Attributes;
1192 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1193 if (attr->ObjectName)
1194 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1195 ret = wine_server_call( req );
1196 *handle = wine_server_ptr_handle( reply->handle );
1198 SERVER_END_REQ;
1199 return ret;
1203 /**************************************************************************
1204 * NtQueryDirectoryObject (NTDLL.@)
1206 NTSTATUS WINAPI NtQueryDirectoryObject( HANDLE handle, DIRECTORY_BASIC_INFORMATION *buffer,
1207 ULONG size, BOOLEAN single_entry, BOOLEAN restart,
1208 ULONG *context, ULONG *ret_size )
1210 unsigned int status, i, count, total_len, pos, used_size, used_count, strpool_head;
1211 ULONG index = restart ? 0 : *context;
1212 struct directory_entry *entries;
1214 if (!(entries = malloc( size ))) return STATUS_NO_MEMORY;
1216 SERVER_START_REQ( get_directory_entries )
1218 req->handle = wine_server_obj_handle( handle );
1219 req->index = index;
1220 req->max_count = single_entry ? 1 : UINT_MAX;
1221 wine_server_set_reply( req, entries, size );
1222 status = wine_server_call( req );
1223 count = reply->count;
1224 total_len = reply->total_len;
1226 SERVER_END_REQ;
1228 if (status && status != STATUS_MORE_ENTRIES)
1230 free( entries );
1231 return status;
1234 used_count = 0;
1235 used_size = sizeof(*buffer); /* "null terminator" entry */
1236 for (i = pos = 0; i < count; i++)
1238 const struct directory_entry *entry = (const struct directory_entry *)((char *)entries + pos);
1239 unsigned int entry_size = sizeof(*buffer) + entry->name_len + entry->type_len + 2 * sizeof(WCHAR);
1241 if (used_size + entry_size > size)
1243 status = STATUS_MORE_ENTRIES;
1244 break;
1246 used_count++;
1247 used_size += entry_size;
1248 pos += sizeof(*entry) + ((entry->name_len + entry->type_len + 3) & ~3);
1252 * Avoid making strpool_head a pointer, since it can point beyond end
1253 * of the buffer. Out-of-bounds pointers trigger undefined behavior
1254 * just by existing, even when they are never dereferenced.
1256 strpool_head = sizeof(*buffer) * (used_count + 1); /* after the "null terminator" entry */
1257 for (i = pos = 0; i < used_count; i++)
1259 const struct directory_entry *entry = (const struct directory_entry *)((char *)entries + pos);
1261 buffer[i].ObjectName.Buffer = (WCHAR *)((char *)buffer + strpool_head);
1262 buffer[i].ObjectName.Length = entry->name_len;
1263 buffer[i].ObjectName.MaximumLength = entry->name_len + sizeof(WCHAR);
1264 memcpy( buffer[i].ObjectName.Buffer, (entry + 1), entry->name_len );
1265 buffer[i].ObjectName.Buffer[entry->name_len / sizeof(WCHAR)] = 0;
1266 strpool_head += entry->name_len + sizeof(WCHAR);
1268 buffer[i].ObjectTypeName.Buffer = (WCHAR *)((char *)buffer + strpool_head);
1269 buffer[i].ObjectTypeName.Length = entry->type_len;
1270 buffer[i].ObjectTypeName.MaximumLength = entry->type_len + sizeof(WCHAR);
1271 memcpy( buffer[i].ObjectTypeName.Buffer, (char *)(entry + 1) + entry->name_len, entry->type_len );
1272 buffer[i].ObjectTypeName.Buffer[entry->type_len / sizeof(WCHAR)] = 0;
1273 strpool_head += entry->type_len + sizeof(WCHAR);
1275 pos += sizeof(*entry) + ((entry->name_len + entry->type_len + 3) & ~3);
1278 if (size >= sizeof(*buffer))
1279 memset( &buffer[used_count], 0, sizeof(buffer[used_count]) );
1281 free( entries );
1283 if (!count && !status)
1285 if (ret_size) *ret_size = sizeof(*buffer);
1286 return STATUS_NO_MORE_ENTRIES;
1289 if (single_entry && !used_count)
1291 if (ret_size) *ret_size = 2 * sizeof(*buffer) + 2 * sizeof(WCHAR) + total_len;
1292 return STATUS_BUFFER_TOO_SMALL;
1295 *context = index + used_count;
1296 if (ret_size) *ret_size = strpool_head;
1297 return status;
1301 /**************************************************************************
1302 * NtCreateSymbolicLinkObject (NTDLL.@)
1304 NTSTATUS WINAPI NtCreateSymbolicLinkObject( HANDLE *handle, ACCESS_MASK access,
1305 OBJECT_ATTRIBUTES *attr, UNICODE_STRING *target )
1307 unsigned int ret;
1308 data_size_t len;
1309 struct object_attributes *objattr;
1311 *handle = 0;
1312 if (!target->MaximumLength) return STATUS_INVALID_PARAMETER;
1313 if (!target->Buffer) return STATUS_ACCESS_VIOLATION;
1314 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1316 SERVER_START_REQ( create_symlink )
1318 req->access = access;
1319 wine_server_add_data( req, objattr, len );
1320 wine_server_add_data( req, target->Buffer, target->Length );
1321 ret = wine_server_call( req );
1322 *handle = wine_server_ptr_handle( reply->handle );
1324 SERVER_END_REQ;
1325 free( objattr );
1326 return ret;
1330 /**************************************************************************
1331 * NtOpenSymbolicLinkObject (NTDLL.@)
1333 NTSTATUS WINAPI NtOpenSymbolicLinkObject( HANDLE *handle, ACCESS_MASK access,
1334 const OBJECT_ATTRIBUTES *attr )
1336 unsigned int ret;
1338 *handle = 0;
1339 if ((ret = validate_open_object_attributes( attr ))) return ret;
1341 SERVER_START_REQ( open_symlink )
1343 req->access = access;
1344 req->attributes = attr->Attributes;
1345 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1346 if (attr->ObjectName)
1347 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1348 ret = wine_server_call( req );
1349 *handle = wine_server_ptr_handle( reply->handle );
1351 SERVER_END_REQ;
1352 return ret;
1356 /**************************************************************************
1357 * NtQuerySymbolicLinkObject (NTDLL.@)
1359 NTSTATUS WINAPI NtQuerySymbolicLinkObject( HANDLE handle, UNICODE_STRING *target, ULONG *length )
1361 unsigned int ret;
1363 if (!target) return STATUS_ACCESS_VIOLATION;
1365 SERVER_START_REQ( query_symlink )
1367 req->handle = wine_server_obj_handle( handle );
1368 if (target->MaximumLength >= sizeof(WCHAR))
1369 wine_server_set_reply( req, target->Buffer, target->MaximumLength - sizeof(WCHAR) );
1370 if (!(ret = wine_server_call( req )))
1372 target->Length = wine_server_reply_size(reply);
1373 target->Buffer[target->Length / sizeof(WCHAR)] = 0;
1374 if (length) *length = reply->total + sizeof(WCHAR);
1376 else if (length && ret == STATUS_BUFFER_TOO_SMALL) *length = reply->total + sizeof(WCHAR);
1378 SERVER_END_REQ;
1379 return ret;
1383 /**************************************************************************
1384 * NtMakePermanentObject (NTDLL.@)
1386 NTSTATUS WINAPI NtMakePermanentObject( HANDLE handle )
1388 unsigned int ret;
1390 TRACE("%p\n", handle);
1392 SERVER_START_REQ( set_object_permanence )
1394 req->handle = wine_server_obj_handle( handle );
1395 req->permanent = 1;
1396 ret = wine_server_call( req );
1398 SERVER_END_REQ;
1399 return ret;
1403 /**************************************************************************
1404 * NtMakeTemporaryObject (NTDLL.@)
1406 NTSTATUS WINAPI NtMakeTemporaryObject( HANDLE handle )
1408 unsigned int ret;
1410 TRACE("%p\n", handle);
1412 SERVER_START_REQ( set_object_permanence )
1414 req->handle = wine_server_obj_handle( handle );
1415 req->permanent = 0;
1416 ret = wine_server_call( req );
1418 SERVER_END_REQ;
1419 return ret;
1423 /**************************************************************************
1424 * NtCreateTimer (NTDLL.@)
1426 NTSTATUS WINAPI NtCreateTimer( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
1427 TIMER_TYPE type )
1429 unsigned int ret;
1430 data_size_t len;
1431 struct object_attributes *objattr;
1433 *handle = 0;
1434 if (type != NotificationTimer && type != SynchronizationTimer) return STATUS_INVALID_PARAMETER;
1435 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1437 SERVER_START_REQ( create_timer )
1439 req->access = access;
1440 req->manual = (type == NotificationTimer);
1441 wine_server_add_data( req, objattr, len );
1442 ret = wine_server_call( req );
1443 *handle = wine_server_ptr_handle( reply->handle );
1445 SERVER_END_REQ;
1447 free( objattr );
1448 return ret;
1453 /**************************************************************************
1454 * NtOpenTimer (NTDLL.@)
1456 NTSTATUS WINAPI NtOpenTimer( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1458 unsigned int ret;
1460 *handle = 0;
1461 if ((ret = validate_open_object_attributes( attr ))) return ret;
1463 SERVER_START_REQ( open_timer )
1465 req->access = access;
1466 req->attributes = attr->Attributes;
1467 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1468 if (attr->ObjectName)
1469 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1470 ret = wine_server_call( req );
1471 *handle = wine_server_ptr_handle( reply->handle );
1473 SERVER_END_REQ;
1474 return ret;
1478 /**************************************************************************
1479 * NtSetTimer (NTDLL.@)
1481 NTSTATUS WINAPI NtSetTimer( HANDLE handle, const LARGE_INTEGER *when, PTIMER_APC_ROUTINE callback,
1482 void *arg, BOOLEAN resume, ULONG period, BOOLEAN *state )
1484 unsigned int ret = STATUS_SUCCESS;
1486 TRACE( "(%p,%p,%p,%p,%08x,0x%08x,%p)\n", handle, when, callback, arg, resume, (int)period, state );
1488 SERVER_START_REQ( set_timer )
1490 req->handle = wine_server_obj_handle( handle );
1491 req->period = period;
1492 req->expire = when->QuadPart;
1493 req->callback = wine_server_client_ptr( callback );
1494 req->arg = wine_server_client_ptr( arg );
1495 ret = wine_server_call( req );
1496 if (state) *state = reply->signaled;
1498 SERVER_END_REQ;
1500 /* set error but can still succeed */
1501 if (resume && ret == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
1502 return ret;
1506 /**************************************************************************
1507 * NtCancelTimer (NTDLL.@)
1509 NTSTATUS WINAPI NtCancelTimer( HANDLE handle, BOOLEAN *state )
1511 unsigned int ret;
1513 SERVER_START_REQ( cancel_timer )
1515 req->handle = wine_server_obj_handle( handle );
1516 ret = wine_server_call( req );
1517 if (state) *state = reply->signaled;
1519 SERVER_END_REQ;
1520 return ret;
1524 /******************************************************************************
1525 * NtQueryTimer (NTDLL.@)
1527 NTSTATUS WINAPI NtQueryTimer( HANDLE handle, TIMER_INFORMATION_CLASS class,
1528 void *info, ULONG len, ULONG *ret_len )
1530 TIMER_BASIC_INFORMATION *basic_info = info;
1531 unsigned int ret;
1532 LARGE_INTEGER now;
1534 TRACE( "(%p,%d,%p,0x%08x,%p)\n", handle, class, info, (int)len, ret_len );
1536 switch (class)
1538 case TimerBasicInformation:
1539 if (len < sizeof(TIMER_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
1541 SERVER_START_REQ( get_timer_info )
1543 req->handle = wine_server_obj_handle( handle );
1544 ret = wine_server_call(req);
1545 /* convert server time to absolute NTDLL time */
1546 basic_info->RemainingTime.QuadPart = reply->when;
1547 basic_info->TimerState = reply->signaled;
1549 SERVER_END_REQ;
1551 /* convert into relative time */
1552 if (basic_info->RemainingTime.QuadPart > 0) NtQuerySystemTime( &now );
1553 else
1555 NtQueryPerformanceCounter( &now, NULL );
1556 basic_info->RemainingTime.QuadPart = -basic_info->RemainingTime.QuadPart;
1559 if (now.QuadPart > basic_info->RemainingTime.QuadPart)
1560 basic_info->RemainingTime.QuadPart = 0;
1561 else
1562 basic_info->RemainingTime.QuadPart -= now.QuadPart;
1564 if (ret_len) *ret_len = sizeof(TIMER_BASIC_INFORMATION);
1565 return ret;
1568 FIXME( "Unhandled class %d\n", class );
1569 return STATUS_INVALID_INFO_CLASS;
1573 /******************************************************************
1574 * NtWaitForMultipleObjects (NTDLL.@)
1576 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
1577 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1579 select_op_t select_op;
1580 UINT i, flags = SELECT_INTERRUPTIBLE;
1582 if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
1584 if (alertable) flags |= SELECT_ALERTABLE;
1585 select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL;
1586 for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] );
1587 return server_wait( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout );
1591 /******************************************************************
1592 * NtWaitForSingleObject (NTDLL.@)
1594 NTSTATUS WINAPI NtWaitForSingleObject( HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
1596 return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );
1600 /******************************************************************
1601 * NtSignalAndWaitForSingleObject (NTDLL.@)
1603 NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait,
1604 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1606 select_op_t select_op;
1607 UINT flags = SELECT_INTERRUPTIBLE;
1609 if (!signal) return STATUS_INVALID_HANDLE;
1611 if (alertable) flags |= SELECT_ALERTABLE;
1612 select_op.signal_and_wait.op = SELECT_SIGNAL_AND_WAIT;
1613 select_op.signal_and_wait.wait = wine_server_obj_handle( wait );
1614 select_op.signal_and_wait.signal = wine_server_obj_handle( signal );
1615 return server_wait( &select_op, sizeof(select_op.signal_and_wait), flags, timeout );
1619 /******************************************************************
1620 * NtYieldExecution (NTDLL.@)
1622 NTSTATUS WINAPI NtYieldExecution(void)
1624 #ifdef HAVE_SCHED_YIELD
1625 #ifdef RUSAGE_THREAD
1626 struct rusage u1, u2;
1627 int ret;
1629 ret = getrusage( RUSAGE_THREAD, &u1 );
1630 #endif
1631 sched_yield();
1632 #ifdef RUSAGE_THREAD
1633 if (!ret) ret = getrusage( RUSAGE_THREAD, &u2 );
1634 if (!ret && u1.ru_nvcsw == u2.ru_nvcsw && u1.ru_nivcsw == u2.ru_nivcsw) return STATUS_NO_YIELD_PERFORMED;
1635 #endif
1636 return STATUS_SUCCESS;
1637 #else
1638 return STATUS_NO_YIELD_PERFORMED;
1639 #endif
1643 /******************************************************************
1644 * NtDelayExecution (NTDLL.@)
1646 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
1648 /* if alertable, we need to query the server */
1649 if (alertable) return server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout );
1651 if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */
1653 for (;;) select( 0, NULL, NULL, NULL, NULL );
1655 else
1657 LARGE_INTEGER now;
1658 timeout_t when, diff;
1660 if ((when = timeout->QuadPart) < 0)
1662 NtQuerySystemTime( &now );
1663 when = now.QuadPart - when;
1666 /* Note that we yield after establishing the desired timeout */
1667 NtYieldExecution();
1668 if (!when) return STATUS_SUCCESS;
1670 for (;;)
1672 struct timeval tv;
1673 NtQuerySystemTime( &now );
1674 diff = (when - now.QuadPart + 9) / 10;
1675 if (diff <= 0) break;
1676 tv.tv_sec = diff / 1000000;
1677 tv.tv_usec = diff % 1000000;
1678 if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
1681 return STATUS_SUCCESS;
1685 /******************************************************************************
1686 * NtQueryPerformanceCounter (NTDLL.@)
1688 NTSTATUS WINAPI NtQueryPerformanceCounter( LARGE_INTEGER *counter, LARGE_INTEGER *frequency )
1690 counter->QuadPart = monotonic_counter();
1691 if (frequency) frequency->QuadPart = TICKSPERSEC;
1692 return STATUS_SUCCESS;
1696 /***********************************************************************
1697 * NtQuerySystemTime (NTDLL.@)
1699 NTSTATUS WINAPI NtQuerySystemTime( LARGE_INTEGER *time )
1701 #ifdef HAVE_CLOCK_GETTIME
1702 struct timespec ts;
1703 static clockid_t clock_id = CLOCK_MONOTONIC; /* placeholder */
1705 if (clock_id == CLOCK_MONOTONIC)
1707 #ifdef CLOCK_REALTIME_COARSE
1708 struct timespec res;
1710 /* Use CLOCK_REALTIME_COARSE if it has 1 ms or better resolution */
1711 if (!clock_getres( CLOCK_REALTIME_COARSE, &res ) && res.tv_sec == 0 && res.tv_nsec <= 1000000)
1712 clock_id = CLOCK_REALTIME_COARSE;
1713 else
1714 #endif /* CLOCK_REALTIME_COARSE */
1715 clock_id = CLOCK_REALTIME;
1718 if (!clock_gettime( clock_id, &ts ))
1720 time->QuadPart = ticks_from_time_t( ts.tv_sec ) + (ts.tv_nsec + 50) / 100;
1722 else
1723 #endif /* HAVE_CLOCK_GETTIME */
1725 struct timeval now;
1727 gettimeofday( &now, 0 );
1728 time->QuadPart = ticks_from_time_t( now.tv_sec ) + now.tv_usec * 10;
1730 return STATUS_SUCCESS;
1734 /***********************************************************************
1735 * NtSetSystemTime (NTDLL.@)
1737 NTSTATUS WINAPI NtSetSystemTime( const LARGE_INTEGER *new, LARGE_INTEGER *old )
1739 LARGE_INTEGER now;
1740 LONGLONG diff;
1742 NtQuerySystemTime( &now );
1743 if (old) *old = now;
1744 diff = new->QuadPart - now.QuadPart;
1745 if (diff > -TICKSPERSEC / 2 && diff < TICKSPERSEC / 2) return STATUS_SUCCESS;
1746 ERR( "not allowed: difference %d ms\n", (int)(diff / 10000) );
1747 return STATUS_PRIVILEGE_NOT_HELD;
1751 /***********************************************************************
1752 * NtQueryTimerResolution (NTDLL.@)
1754 NTSTATUS WINAPI NtQueryTimerResolution( ULONG *min_res, ULONG *max_res, ULONG *current_res )
1756 TRACE( "(%p,%p,%p)\n", min_res, max_res, current_res );
1757 *max_res = *current_res = 10000; /* See NtSetTimerResolution() */
1758 *min_res = 156250;
1759 return STATUS_SUCCESS;
1763 /***********************************************************************
1764 * NtSetTimerResolution (NTDLL.@)
1766 NTSTATUS WINAPI NtSetTimerResolution( ULONG res, BOOLEAN set, ULONG *current_res )
1768 static BOOL has_request = FALSE;
1770 TRACE( "(%u,%u,%p), semi-stub!\n", (int)res, set, current_res );
1772 /* Wine has no support for anything other that 1 ms and does not keep of
1773 * track resolution requests anyway.
1774 * Fortunately NtSetTimerResolution() should ignore requests to lower the
1775 * timer resolution. So by claiming that 'some other process' requested the
1776 * max resolution already, there no need to actually change it.
1778 *current_res = 10000;
1780 /* Just keep track of whether this process requested a specific timer
1781 * resolution.
1783 if (!has_request && !set)
1784 return STATUS_TIMER_RESOLUTION_NOT_SET;
1785 has_request = set;
1787 return STATUS_SUCCESS;
1791 /******************************************************************************
1792 * NtSetIntervalProfile (NTDLL.@)
1794 NTSTATUS WINAPI NtSetIntervalProfile( ULONG interval, KPROFILE_SOURCE source )
1796 FIXME( "%u,%d\n", (int)interval, source );
1797 return STATUS_SUCCESS;
1801 /******************************************************************************
1802 * NtGetTickCount (NTDLL.@)
1804 ULONG WINAPI NtGetTickCount(void)
1806 /* note: we ignore TickCountMultiplier */
1807 return user_shared_data->TickCount.LowPart;
1811 /******************************************************************************
1812 * RtlGetSystemTimePrecise (NTDLL.@)
1814 NTSTATUS system_time_precise( void *args )
1816 LONGLONG *ret = args;
1817 struct timeval now;
1818 #ifdef HAVE_CLOCK_GETTIME
1819 struct timespec ts;
1821 if (!clock_gettime( CLOCK_REALTIME, &ts ))
1823 *ret = ticks_from_time_t( ts.tv_sec ) + (ts.tv_nsec + 50) / 100;
1824 return STATUS_SUCCESS;
1826 #endif
1827 gettimeofday( &now, 0 );
1828 *ret = ticks_from_time_t( now.tv_sec ) + now.tv_usec * 10;
1829 return STATUS_SUCCESS;
1833 /******************************************************************************
1834 * NtCreateKeyedEvent (NTDLL.@)
1836 NTSTATUS WINAPI NtCreateKeyedEvent( HANDLE *handle, ACCESS_MASK access,
1837 const OBJECT_ATTRIBUTES *attr, ULONG flags )
1839 unsigned int ret;
1840 data_size_t len;
1841 struct object_attributes *objattr;
1843 *handle = 0;
1844 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1846 SERVER_START_REQ( create_keyed_event )
1848 req->access = access;
1849 wine_server_add_data( req, objattr, len );
1850 ret = wine_server_call( req );
1851 *handle = wine_server_ptr_handle( reply->handle );
1853 SERVER_END_REQ;
1855 free( objattr );
1856 return ret;
1860 /******************************************************************************
1861 * NtOpenKeyedEvent (NTDLL.@)
1863 NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1865 unsigned int ret;
1867 *handle = 0;
1868 if ((ret = validate_open_object_attributes( attr ))) return ret;
1870 SERVER_START_REQ( open_keyed_event )
1872 req->access = access;
1873 req->attributes = attr->Attributes;
1874 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1875 if (attr->ObjectName)
1876 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1877 ret = wine_server_call( req );
1878 *handle = wine_server_ptr_handle( reply->handle );
1880 SERVER_END_REQ;
1881 return ret;
1884 /******************************************************************************
1885 * NtWaitForKeyedEvent (NTDLL.@)
1887 NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
1888 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1890 select_op_t select_op;
1891 UINT flags = SELECT_INTERRUPTIBLE;
1893 if (!handle) handle = keyed_event;
1894 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1895 if (alertable) flags |= SELECT_ALERTABLE;
1896 select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT;
1897 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1898 select_op.keyed_event.key = wine_server_client_ptr( key );
1899 return server_wait( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1903 /******************************************************************************
1904 * NtReleaseKeyedEvent (NTDLL.@)
1906 NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key,
1907 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1909 select_op_t select_op;
1910 UINT flags = SELECT_INTERRUPTIBLE;
1912 if (!handle) handle = keyed_event;
1913 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1914 if (alertable) flags |= SELECT_ALERTABLE;
1915 select_op.keyed_event.op = SELECT_KEYED_EVENT_RELEASE;
1916 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1917 select_op.keyed_event.key = wine_server_client_ptr( key );
1918 return server_wait( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1922 /***********************************************************************
1923 * NtCreateIoCompletion (NTDLL.@)
1925 NTSTATUS WINAPI NtCreateIoCompletion( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
1926 ULONG threads )
1928 unsigned int status;
1929 data_size_t len;
1930 struct object_attributes *objattr;
1932 TRACE( "(%p, %x, %p, %d)\n", handle, (int)access, attr, (int)threads );
1934 *handle = 0;
1935 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
1937 SERVER_START_REQ( create_completion )
1939 req->access = access;
1940 req->concurrent = threads;
1941 wine_server_add_data( req, objattr, len );
1942 if (!(status = wine_server_call( req ))) *handle = wine_server_ptr_handle( reply->handle );
1944 SERVER_END_REQ;
1946 free( objattr );
1947 return status;
1951 /***********************************************************************
1952 * NtOpenIoCompletion (NTDLL.@)
1954 NTSTATUS WINAPI NtOpenIoCompletion( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1956 unsigned int status;
1958 *handle = 0;
1959 if ((status = validate_open_object_attributes( attr ))) return status;
1961 SERVER_START_REQ( open_completion )
1963 req->access = access;
1964 req->attributes = attr->Attributes;
1965 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1966 if (attr->ObjectName)
1967 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1968 status = wine_server_call( req );
1969 *handle = wine_server_ptr_handle( reply->handle );
1971 SERVER_END_REQ;
1972 return status;
1976 /***********************************************************************
1977 * NtSetIoCompletion (NTDLL.@)
1979 NTSTATUS WINAPI NtSetIoCompletion( HANDLE handle, ULONG_PTR key, ULONG_PTR value,
1980 NTSTATUS status, SIZE_T count )
1982 unsigned int ret;
1984 TRACE( "(%p, %lx, %lx, %x, %lx)\n", handle, key, value, (int)status, count );
1986 SERVER_START_REQ( add_completion )
1988 req->handle = wine_server_obj_handle( handle );
1989 req->ckey = key;
1990 req->cvalue = value;
1991 req->status = status;
1992 req->information = count;
1993 ret = wine_server_call( req );
1995 SERVER_END_REQ;
1996 return ret;
2000 /***********************************************************************
2001 * NtRemoveIoCompletion (NTDLL.@)
2003 NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR *value,
2004 IO_STATUS_BLOCK *io, LARGE_INTEGER *timeout )
2006 unsigned int status;
2008 TRACE( "(%p, %p, %p, %p, %p)\n", handle, key, value, io, timeout );
2010 for (;;)
2012 SERVER_START_REQ( remove_completion )
2014 req->handle = wine_server_obj_handle( handle );
2015 if (!(status = wine_server_call( req )))
2017 *key = reply->ckey;
2018 *value = reply->cvalue;
2019 io->Information = reply->information;
2020 io->Status = reply->status;
2023 SERVER_END_REQ;
2024 if (status != STATUS_PENDING) return status;
2025 status = NtWaitForSingleObject( handle, FALSE, timeout );
2026 if (status != WAIT_OBJECT_0) return status;
2031 /***********************************************************************
2032 * NtRemoveIoCompletionEx (NTDLL.@)
2034 NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORMATION *info, ULONG count,
2035 ULONG *written, LARGE_INTEGER *timeout, BOOLEAN alertable )
2037 unsigned int status;
2038 ULONG i = 0;
2040 TRACE( "%p %p %u %p %p %u\n", handle, info, (int)count, written, timeout, alertable );
2042 for (;;)
2044 while (i < count)
2046 SERVER_START_REQ( remove_completion )
2048 req->handle = wine_server_obj_handle( handle );
2049 if (!(status = wine_server_call( req )))
2051 info[i].CompletionKey = reply->ckey;
2052 info[i].CompletionValue = reply->cvalue;
2053 info[i].IoStatusBlock.Information = reply->information;
2054 info[i].IoStatusBlock.Status = reply->status;
2057 SERVER_END_REQ;
2058 if (status != STATUS_SUCCESS) break;
2059 ++i;
2061 if (i || status != STATUS_PENDING)
2063 if (status == STATUS_PENDING) status = STATUS_SUCCESS;
2064 break;
2066 status = NtWaitForSingleObject( handle, alertable, timeout );
2067 if (status != WAIT_OBJECT_0) break;
2069 *written = i ? i : 1;
2070 return status;
2074 /***********************************************************************
2075 * NtQueryIoCompletion (NTDLL.@)
2077 NTSTATUS WINAPI NtQueryIoCompletion( HANDLE handle, IO_COMPLETION_INFORMATION_CLASS class,
2078 void *buffer, ULONG len, ULONG *ret_len )
2080 unsigned int status;
2082 TRACE( "(%p, %d, %p, 0x%x, %p)\n", handle, class, buffer, (int)len, ret_len );
2084 if (!buffer) return STATUS_INVALID_PARAMETER;
2086 switch (class)
2088 case IoCompletionBasicInformation:
2090 ULONG *info = buffer;
2091 if (ret_len) *ret_len = sizeof(*info);
2092 if (len == sizeof(*info))
2094 SERVER_START_REQ( query_completion )
2096 req->handle = wine_server_obj_handle( handle );
2097 if (!(status = wine_server_call( req ))) *info = reply->depth;
2099 SERVER_END_REQ;
2101 else status = STATUS_INFO_LENGTH_MISMATCH;
2102 break;
2104 default:
2105 return STATUS_INVALID_PARAMETER;
2107 return status;
2111 /***********************************************************************
2112 * NtCreateSection (NTDLL.@)
2114 NTSTATUS WINAPI NtCreateSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
2115 const LARGE_INTEGER *size, ULONG protect,
2116 ULONG sec_flags, HANDLE file )
2118 unsigned int ret;
2119 unsigned int file_access;
2120 data_size_t len;
2121 struct object_attributes *objattr;
2123 *handle = 0;
2125 switch (protect & 0xff)
2127 case PAGE_READONLY:
2128 case PAGE_EXECUTE_READ:
2129 case PAGE_WRITECOPY:
2130 case PAGE_EXECUTE_WRITECOPY:
2131 file_access = FILE_READ_DATA;
2132 break;
2133 case PAGE_READWRITE:
2134 case PAGE_EXECUTE_READWRITE:
2135 if (sec_flags & SEC_IMAGE) file_access = FILE_READ_DATA;
2136 else file_access = FILE_READ_DATA | FILE_WRITE_DATA;
2137 break;
2138 case PAGE_EXECUTE:
2139 case PAGE_NOACCESS:
2140 file_access = 0;
2141 break;
2142 default:
2143 return STATUS_INVALID_PAGE_PROTECTION;
2146 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
2148 SERVER_START_REQ( create_mapping )
2150 req->access = access;
2151 req->flags = sec_flags;
2152 req->file_handle = wine_server_obj_handle( file );
2153 req->file_access = file_access;
2154 req->size = size ? size->QuadPart : 0;
2155 wine_server_add_data( req, objattr, len );
2156 ret = wine_server_call( req );
2157 *handle = wine_server_ptr_handle( reply->handle );
2159 SERVER_END_REQ;
2161 free( objattr );
2162 return ret;
2166 /***********************************************************************
2167 * NtOpenSection (NTDLL.@)
2169 NTSTATUS WINAPI NtOpenSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
2171 unsigned int ret;
2173 *handle = 0;
2174 if ((ret = validate_open_object_attributes( attr ))) return ret;
2176 SERVER_START_REQ( open_mapping )
2178 req->access = access;
2179 req->attributes = attr->Attributes;
2180 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
2181 if (attr->ObjectName)
2182 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
2183 ret = wine_server_call( req );
2184 *handle = wine_server_ptr_handle( reply->handle );
2186 SERVER_END_REQ;
2187 return ret;
2191 /***********************************************************************
2192 * NtCreatePort (NTDLL.@)
2194 NTSTATUS WINAPI NtCreatePort( HANDLE *handle, OBJECT_ATTRIBUTES *attr, ULONG info_len,
2195 ULONG data_len, ULONG *reserved )
2197 FIXME( "(%p,%p,%u,%u,%p),stub!\n", handle, attr, (int)info_len, (int)data_len, reserved );
2198 return STATUS_NOT_IMPLEMENTED;
2202 /***********************************************************************
2203 * NtConnectPort (NTDLL.@)
2205 NTSTATUS WINAPI NtConnectPort( HANDLE *handle, UNICODE_STRING *name, SECURITY_QUALITY_OF_SERVICE *qos,
2206 LPC_SECTION_WRITE *write, LPC_SECTION_READ *read, ULONG *max_len,
2207 void *info, ULONG *info_len )
2209 FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p),stub!\n", handle, debugstr_us(name), qos,
2210 write, read, max_len, info, info_len );
2211 if (info && info_len) TRACE("msg = %s\n", debugstr_an( info, *info_len ));
2212 return STATUS_NOT_IMPLEMENTED;
2216 /***********************************************************************
2217 * NtSecureConnectPort (NTDLL.@)
2219 NTSTATUS WINAPI NtSecureConnectPort( HANDLE *handle, UNICODE_STRING *name, SECURITY_QUALITY_OF_SERVICE *qos,
2220 LPC_SECTION_WRITE *write, PSID sid, LPC_SECTION_READ *read,
2221 ULONG *max_len, void *info, ULONG *info_len )
2223 FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p,%p),stub!\n", handle, debugstr_us(name), qos,
2224 write, sid, read, max_len, info, info_len );
2225 return STATUS_NOT_IMPLEMENTED;
2229 /***********************************************************************
2230 * NtListenPort (NTDLL.@)
2232 NTSTATUS WINAPI NtListenPort( HANDLE handle, LPC_MESSAGE *msg )
2234 FIXME("(%p,%p),stub!\n", handle, msg );
2235 return STATUS_NOT_IMPLEMENTED;
2239 /***********************************************************************
2240 * NtAcceptConnectPort (NTDLL.@)
2242 NTSTATUS WINAPI NtAcceptConnectPort( HANDLE *handle, ULONG id, LPC_MESSAGE *msg, BOOLEAN accept,
2243 LPC_SECTION_WRITE *write, LPC_SECTION_READ *read )
2245 FIXME("(%p,%u,%p,%d,%p,%p),stub!\n", handle, (int)id, msg, accept, write, read );
2246 return STATUS_NOT_IMPLEMENTED;
2250 /***********************************************************************
2251 * NtCompleteConnectPort (NTDLL.@)
2253 NTSTATUS WINAPI NtCompleteConnectPort( HANDLE handle )
2255 FIXME( "(%p),stub!\n", handle );
2256 return STATUS_NOT_IMPLEMENTED;
2260 /***********************************************************************
2261 * NtRegisterThreadTerminatePort (NTDLL.@)
2263 NTSTATUS WINAPI NtRegisterThreadTerminatePort( HANDLE handle )
2265 FIXME( "(%p),stub!\n", handle );
2266 return STATUS_NOT_IMPLEMENTED;
2270 /***********************************************************************
2271 * NtRequestWaitReplyPort (NTDLL.@)
2273 NTSTATUS WINAPI NtRequestWaitReplyPort( HANDLE handle, LPC_MESSAGE *msg_in, LPC_MESSAGE *msg_out )
2275 FIXME( "(%p,%p,%p),stub!\n", handle, msg_in, msg_out );
2276 if (msg_in)
2277 TRACE("datasize %u msgsize %u type %u ranges %u client %p/%p msgid %lu size %lu data %s\n",
2278 msg_in->DataSize, msg_in->MessageSize, msg_in->MessageType, msg_in->VirtualRangesOffset,
2279 msg_in->ClientId.UniqueProcess, msg_in->ClientId.UniqueThread, msg_in->MessageId,
2280 msg_in->SectionSize, debugstr_an( (const char *)msg_in->Data, msg_in->DataSize ));
2281 return STATUS_NOT_IMPLEMENTED;
2285 /***********************************************************************
2286 * NtReplyWaitReceivePort (NTDLL.@)
2288 NTSTATUS WINAPI NtReplyWaitReceivePort( HANDLE handle, ULONG *id, LPC_MESSAGE *reply, LPC_MESSAGE *msg )
2290 FIXME("(%p,%p,%p,%p),stub!\n", handle, id, reply, msg );
2291 return STATUS_NOT_IMPLEMENTED;
2295 #define MAX_ATOM_LEN 255
2296 #define IS_INTATOM(x) (((ULONG_PTR)(x) >> 16) == 0)
2298 static unsigned int is_integral_atom( const WCHAR *atomstr, ULONG len, RTL_ATOM *ret_atom )
2300 RTL_ATOM atom;
2302 if ((ULONG_PTR)atomstr >> 16)
2304 const WCHAR* ptr = atomstr;
2305 if (!len) return STATUS_OBJECT_NAME_INVALID;
2307 if (*ptr++ == '#')
2309 atom = 0;
2310 while (ptr < atomstr + len && *ptr >= '0' && *ptr <= '9')
2312 atom = atom * 10 + *ptr++ - '0';
2314 if (ptr > atomstr + 1 && ptr == atomstr + len) goto done;
2316 if (len > MAX_ATOM_LEN) return STATUS_INVALID_PARAMETER;
2317 return STATUS_MORE_ENTRIES;
2319 else atom = LOWORD( atomstr );
2320 done:
2321 if (!atom || atom >= MAXINTATOM) return STATUS_INVALID_PARAMETER;
2322 *ret_atom = atom;
2323 return STATUS_SUCCESS;
2326 static ULONG integral_atom_name( WCHAR *buffer, ULONG len, RTL_ATOM atom )
2328 char tmp[16];
2329 int ret = snprintf( tmp, sizeof(tmp), "#%u", atom );
2331 len /= sizeof(WCHAR);
2332 if (len)
2334 if (len <= ret) ret = len - 1;
2335 ascii_to_unicode( buffer, tmp, ret );
2336 buffer[ret] = 0;
2338 return ret * sizeof(WCHAR);
2342 /***********************************************************************
2343 * NtAddAtom (NTDLL.@)
2345 NTSTATUS WINAPI NtAddAtom( const WCHAR *name, ULONG length, RTL_ATOM *atom )
2347 unsigned int status = is_integral_atom( name, length / sizeof(WCHAR), atom );
2349 if (status == STATUS_MORE_ENTRIES)
2351 SERVER_START_REQ( add_atom )
2353 wine_server_add_data( req, name, length );
2354 status = wine_server_call( req );
2355 *atom = reply->atom;
2357 SERVER_END_REQ;
2359 TRACE( "%s -> %x\n", debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
2360 return status;
2364 /***********************************************************************
2365 * NtDeleteAtom (NTDLL.@)
2367 NTSTATUS WINAPI NtDeleteAtom( RTL_ATOM atom )
2369 unsigned int status;
2371 SERVER_START_REQ( delete_atom )
2373 req->atom = atom;
2374 status = wine_server_call( req );
2376 SERVER_END_REQ;
2377 return status;
2381 /***********************************************************************
2382 * NtFindAtom (NTDLL.@)
2384 NTSTATUS WINAPI NtFindAtom( const WCHAR *name, ULONG length, RTL_ATOM *atom )
2386 unsigned int status = is_integral_atom( name, length / sizeof(WCHAR), atom );
2388 if (status == STATUS_MORE_ENTRIES)
2390 SERVER_START_REQ( find_atom )
2392 wine_server_add_data( req, name, length );
2393 status = wine_server_call( req );
2394 *atom = reply->atom;
2396 SERVER_END_REQ;
2398 TRACE( "%s -> %x\n", debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
2399 return status;
2403 /***********************************************************************
2404 * NtQueryInformationAtom (NTDLL.@)
2406 NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS class,
2407 void *ptr, ULONG size, ULONG *retsize )
2409 unsigned int status;
2411 switch (class)
2413 case AtomBasicInformation:
2415 ULONG name_len;
2416 ATOM_BASIC_INFORMATION *abi = ptr;
2418 if (size < sizeof(ATOM_BASIC_INFORMATION)) return STATUS_INVALID_PARAMETER;
2419 name_len = size - sizeof(ATOM_BASIC_INFORMATION);
2421 if (atom < MAXINTATOM)
2423 if (atom)
2425 abi->NameLength = integral_atom_name( abi->Name, name_len, atom );
2426 status = name_len ? STATUS_SUCCESS : STATUS_BUFFER_TOO_SMALL;
2427 abi->ReferenceCount = 1;
2428 abi->Pinned = 1;
2430 else status = STATUS_INVALID_PARAMETER;
2432 else
2434 SERVER_START_REQ( get_atom_information )
2436 req->atom = atom;
2437 if (name_len) wine_server_set_reply( req, abi->Name, name_len );
2438 status = wine_server_call( req );
2439 if (status == STATUS_SUCCESS)
2441 name_len = wine_server_reply_size( reply );
2442 if (name_len)
2444 abi->NameLength = name_len;
2445 abi->Name[name_len / sizeof(WCHAR)] = 0;
2447 else
2449 name_len = reply->total;
2450 abi->NameLength = name_len;
2451 status = STATUS_BUFFER_TOO_SMALL;
2453 abi->ReferenceCount = reply->count;
2454 abi->Pinned = reply->pinned;
2456 else name_len = 0;
2458 SERVER_END_REQ;
2460 TRACE( "%x -> %s (%u)\n", atom, debugstr_wn(abi->Name, abi->NameLength / sizeof(WCHAR)), status );
2461 if (retsize) *retsize = sizeof(ATOM_BASIC_INFORMATION) + name_len;
2462 break;
2465 default:
2466 FIXME( "Unsupported class %u\n", class );
2467 status = STATUS_INVALID_INFO_CLASS;
2468 break;
2470 return status;
2474 union tid_alert_entry
2476 #ifdef USE_FUTEX
2477 LONG futex;
2478 #elif defined(HAVE_KQUEUE)
2479 int kq;
2480 #else
2481 HANDLE event;
2482 #endif
2485 #define TID_ALERT_BLOCK_SIZE (65536 / sizeof(union tid_alert_entry))
2486 static union tid_alert_entry *tid_alert_blocks[4096];
2488 static unsigned int handle_to_index( HANDLE handle, unsigned int *block_idx )
2490 unsigned int idx = (wine_server_obj_handle(handle) >> 2) - 1;
2491 *block_idx = idx / TID_ALERT_BLOCK_SIZE;
2492 return idx % TID_ALERT_BLOCK_SIZE;
2495 static union tid_alert_entry *get_tid_alert_entry( HANDLE tid )
2497 unsigned int block_idx, idx = handle_to_index( tid, &block_idx );
2498 union tid_alert_entry *entry;
2500 if (block_idx > ARRAY_SIZE(tid_alert_blocks))
2502 FIXME( "tid %p is too high\n", tid );
2503 return NULL;
2506 if (!tid_alert_blocks[block_idx])
2508 static const size_t size = TID_ALERT_BLOCK_SIZE * sizeof(union tid_alert_entry);
2509 void *ptr = anon_mmap_alloc( size, PROT_READ | PROT_WRITE );
2510 if (ptr == MAP_FAILED) return NULL;
2511 if (InterlockedCompareExchangePointer( (void **)&tid_alert_blocks[block_idx], ptr, NULL ))
2512 munmap( ptr, size ); /* someone beat us to it */
2515 entry = &tid_alert_blocks[block_idx][idx % TID_ALERT_BLOCK_SIZE];
2517 #ifdef USE_FUTEX
2518 return entry;
2519 #elif defined(HAVE_KQUEUE)
2520 if (!entry->kq)
2522 int kq = kqueue();
2523 static const struct kevent init_event =
2525 .ident = 1,
2526 .filter = EVFILT_USER,
2527 .flags = EV_ADD | EV_CLEAR,
2528 .fflags = 0,
2529 .data = 0,
2530 .udata = NULL
2533 if (kq == -1)
2535 ERR( "kqueue failed with error: %d (%s)\n", errno, strerror( errno ) );
2536 return NULL;
2539 if (kevent( kq, &init_event, 1, NULL, 0, NULL) == -1)
2541 ERR( "kevent creation failed with error: %d (%s)\n", errno, strerror( errno ) );
2542 close( kq );
2543 return NULL;
2546 if (InterlockedCompareExchange( (LONG *)&entry->kq, kq, 0 ))
2547 close( kq );
2549 #else
2550 if (!entry->event)
2552 HANDLE event;
2554 if (NtCreateEvent( &event, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE ))
2555 return NULL;
2556 if (InterlockedCompareExchangePointer( &entry->event, event, NULL ))
2557 NtClose( event );
2559 #endif
2561 return entry;
2565 /***********************************************************************
2566 * NtAlertThreadByThreadId (NTDLL.@)
2568 NTSTATUS WINAPI NtAlertThreadByThreadId( HANDLE tid )
2570 union tid_alert_entry *entry = get_tid_alert_entry( tid );
2572 TRACE( "%p\n", tid );
2574 if (!entry) return STATUS_INVALID_CID;
2576 #ifdef USE_FUTEX
2578 LONG *futex = &entry->futex;
2579 if (!InterlockedExchange( futex, 1 ))
2580 futex_wake_one( futex );
2581 return STATUS_SUCCESS;
2583 #elif defined(HAVE_KQUEUE)
2585 static const struct kevent signal_event =
2587 .ident = 1,
2588 .filter = EVFILT_USER,
2589 .flags = 0,
2590 .fflags = NOTE_TRIGGER,
2591 .data = 0,
2592 .udata = NULL
2595 kevent( entry->kq, &signal_event, 1, NULL, 0, NULL );
2596 return STATUS_SUCCESS;
2598 #else
2599 return NtSetEvent( entry->event, NULL );
2600 #endif
2604 #if defined(USE_FUTEX) || defined(HAVE_KQUEUE)
2605 static LONGLONG get_absolute_timeout( const LARGE_INTEGER *timeout )
2607 LARGE_INTEGER now;
2609 if (timeout->QuadPart >= 0) return timeout->QuadPart;
2610 NtQuerySystemTime( &now );
2611 return now.QuadPart - timeout->QuadPart;
2614 static LONGLONG update_timeout( ULONGLONG end )
2616 LARGE_INTEGER now;
2617 LONGLONG timeleft;
2619 NtQuerySystemTime( &now );
2620 timeleft = end - now.QuadPart;
2621 if (timeleft < 0) timeleft = 0;
2622 return timeleft;
2624 #endif
2627 /***********************************************************************
2628 * NtWaitForAlertByThreadId (NTDLL.@)
2630 NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEGER *timeout )
2632 union tid_alert_entry *entry = get_tid_alert_entry( NtCurrentTeb()->ClientId.UniqueThread );
2634 TRACE( "%p %s\n", address, debugstr_timeout( timeout ) );
2636 if (!entry) return STATUS_INVALID_CID;
2638 #ifdef USE_FUTEX
2640 LONG *futex = &entry->futex;
2641 ULONGLONG end;
2642 int ret;
2644 if (timeout)
2646 if (timeout->QuadPart == TIMEOUT_INFINITE)
2647 timeout = NULL;
2648 else
2649 end = get_absolute_timeout( timeout );
2652 while (!InterlockedExchange( futex, 0 ))
2654 if (timeout)
2656 LONGLONG timeleft = update_timeout( end );
2657 struct timespec timespec;
2659 timespec.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC;
2660 timespec.tv_nsec = (timeleft % TICKSPERSEC) * 100;
2661 ret = futex_wait( futex, 0, &timespec );
2663 else
2664 ret = futex_wait( futex, 0, NULL );
2666 if (ret == -1 && errno == ETIMEDOUT) return STATUS_TIMEOUT;
2668 return STATUS_ALERTED;
2670 #elif defined(HAVE_KQUEUE)
2672 ULONGLONG end;
2673 int ret;
2674 struct timespec timespec;
2675 struct kevent wait_event;
2677 if (timeout)
2679 if (timeout->QuadPart == TIMEOUT_INFINITE)
2680 timeout = NULL;
2681 else
2682 end = get_absolute_timeout( timeout );
2687 if (timeout)
2689 LONGLONG timeleft = update_timeout( end );
2691 timespec.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC;
2692 timespec.tv_nsec = (timeleft % TICKSPERSEC) * 100;
2693 if (timespec.tv_sec > 0x7FFFFFFF) timeout = NULL;
2696 ret = kevent( entry->kq, NULL, 0, &wait_event, 1, timeout ? &timespec : NULL );
2697 } while (ret == -1 && errno == EINTR);
2699 switch (ret)
2701 case 1:
2702 return STATUS_ALERTED;
2703 case 0:
2704 return STATUS_TIMEOUT;
2705 default:
2706 ERR( "kevent failed with error: %d (%s)\n", errno, strerror( errno ) );
2707 return STATUS_INVALID_HANDLE;
2710 #else
2712 NTSTATUS status = NtWaitForSingleObject( entry->event, FALSE, timeout );
2713 if (!status) return STATUS_ALERTED;
2714 return status;
2716 #endif
2720 /***********************************************************************
2721 * NtCreateTransaction (NTDLL.@)
2723 NTSTATUS WINAPI NtCreateTransaction( HANDLE *handle, ACCESS_MASK mask, OBJECT_ATTRIBUTES *obj_attr, GUID *guid, HANDLE tm,
2724 ULONG options, ULONG isol_level, ULONG isol_flags, PLARGE_INTEGER timeout, UNICODE_STRING *description )
2726 FIXME( "%p, %#x, %p, %s, %p, 0x%08x, 0x%08x, 0x%08x, %p, %p stub.\n", handle, (int)mask, obj_attr, debugstr_guid(guid), tm,
2727 (int)options, (int)isol_level, (int)isol_flags, timeout, description );
2729 *handle = ULongToHandle(1);
2731 return STATUS_SUCCESS;
2734 /***********************************************************************
2735 * NtCommitTransaction (NTDLL.@)
2737 NTSTATUS WINAPI NtCommitTransaction( HANDLE transaction, BOOLEAN wait )
2739 FIXME( "%p, %d stub.\n", transaction, wait );
2741 return STATUS_SUCCESS;
2744 /***********************************************************************
2745 * NtRollbackTransaction (NTDLL.@)
2747 NTSTATUS WINAPI NtRollbackTransaction( HANDLE transaction, BOOLEAN wait )
2749 FIXME( "%p, %d stub.\n", transaction, wait );
2751 return STATUS_ACCESS_VIOLATION;