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
35 #include <sys/types.h>
37 #ifdef HAVE_SYS_SYSCALL_H
38 #include <sys/syscall.h>
46 #ifdef HAVE_SYS_RESOURCE_H
47 # include <sys/resource.h>
55 # include <mach/mach_time.h>
58 # include <sys/event.h>
62 #define WIN32_NO_STATUS
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)
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;
92 return mach_absolute_time() * timebase
.numer
/ timebase
.denom
/ 100;
93 #elif defined(HAVE_CLOCK_GETTIME)
95 #ifdef CLOCK_MONOTONIC_RAW
96 if (!clock_gettime( CLOCK_MONOTONIC_RAW
, &ts
))
97 return ts
.tv_sec
* (ULONGLONG
)TICKSPERSEC
+ ts
.tv_nsec
/ 100;
99 if (!clock_gettime( CLOCK_MONOTONIC
, &ts
))
100 return ts
.tv_sec
* (ULONGLONG
)TICKSPERSEC
+ ts
.tv_nsec
/ 100;
102 gettimeofday( &now
, 0 );
103 return ticks_from_time_t( now
.tv_sec
) + now
.tv_usec
* 10 - server_start_time
;
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)
120 } timeout32
= { timeout
->tv_sec
, timeout
->tv_nsec
};
122 return syscall( __NR_futex
, addr
, FUTEX_WAIT_PRIVATE
, val
, &timeout32
, 0, 0 );
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__)
137 #include <AvailabilityMacros.h>
139 #ifdef MAC_OS_VERSION_14_4
140 #include <os/os_sync_wait_on_address.h>
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
;
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
);
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);
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
);
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
;
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
);
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
);
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
)
316 struct object_attributes
*objattr
;
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
;
327 wine_server_add_data( req
, objattr
, len
);
328 ret
= wine_server_call( req
);
329 *handle
= wine_server_ptr_handle( reply
->handle
);
338 /******************************************************************************
339 * NtOpenSemaphore (NTDLL.@)
341 NTSTATUS WINAPI
NtOpenSemaphore( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
363 /******************************************************************************
364 * NtQuerySemaphore (NTDLL.@)
366 NTSTATUS WINAPI
NtQuerySemaphore( HANDLE handle
, SEMAPHORE_INFORMATION_CLASS
class,
367 void *info
, ULONG len
, ULONG
*ret_len
)
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
);
397 /******************************************************************************
398 * NtReleaseSemaphore (NTDLL.@)
400 NTSTATUS WINAPI
NtReleaseSemaphore( HANDLE handle
, ULONG count
, ULONG
*previous
)
404 SERVER_START_REQ( release_semaphore
)
406 req
->handle
= wine_server_obj_handle( handle
);
408 if (!(ret
= wine_server_call( req
)))
410 if (previous
) *previous
= reply
->prev_count
;
418 /**************************************************************************
419 * NtCreateEvent (NTDLL.@)
421 NTSTATUS WINAPI
NtCreateEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
422 EVENT_TYPE type
, BOOLEAN state
)
426 struct object_attributes
*objattr
;
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
);
448 /******************************************************************************
449 * NtOpenEvent (NTDLL.@)
451 NTSTATUS WINAPI
NtOpenEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
473 /******************************************************************************
474 * NtSetEvent (NTDLL.@)
476 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, LONG
*prev_state
)
480 SERVER_START_REQ( event_op
)
482 req
->handle
= wine_server_obj_handle( handle
);
484 ret
= wine_server_call( req
);
485 if (!ret
&& prev_state
) *prev_state
= reply
->state
;
492 /******************************************************************************
493 * NtResetEvent (NTDLL.@)
495 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, LONG
*prev_state
)
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
;
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
)
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
;
540 /******************************************************************************
541 * NtQueryEvent (NTDLL.@)
543 NTSTATUS WINAPI
NtQueryEvent( HANDLE handle
, EVENT_INFORMATION_CLASS
class,
544 void *info
, ULONG len
, ULONG
*ret_len
)
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
);
574 /******************************************************************************
575 * NtCreateMutant (NTDLL.@)
577 NTSTATUS WINAPI
NtCreateMutant( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
582 struct object_attributes
*objattr
;
585 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
587 SERVER_START_REQ( create_mutex
)
589 req
->access
= access
;
591 wine_server_add_data( req
, objattr
, len
);
592 ret
= wine_server_call( req
);
593 *handle
= wine_server_ptr_handle( reply
->handle
);
602 /**************************************************************************
603 * NtOpenMutant (NTDLL.@)
605 NTSTATUS WINAPI
NtOpenMutant( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
627 /**************************************************************************
628 * NtReleaseMutant (NTDLL.@)
630 NTSTATUS WINAPI
NtReleaseMutant( HANDLE handle
, LONG
*prev_count
)
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
;
645 /******************************************************************
646 * NtQueryMutant (NTDLL.@)
648 NTSTATUS WINAPI
NtQueryMutant( HANDLE handle
, MUTANT_INFORMATION_CLASS
class,
649 void *info
, ULONG len
, ULONG
*ret_len
)
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
);
680 /**************************************************************************
681 * NtCreateJobObject (NTDLL.@)
683 NTSTATUS WINAPI
NtCreateJobObject( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
687 struct object_attributes
*objattr
;
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
);
705 /**************************************************************************
706 * NtOpenJobObject (NTDLL.@)
708 NTSTATUS WINAPI
NtOpenJobObject( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
730 /**************************************************************************
731 * NtTerminateJobObject (NTDLL.@)
733 NTSTATUS WINAPI
NtTerminateJobObject( HANDLE handle
, NTSTATUS status
)
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
);
751 /**************************************************************************
752 * NtQueryInformationJobObject (NTDLL.@)
754 NTSTATUS WINAPI
NtQueryInformationJobObject( HANDLE handle
, JOBOBJECTINFOCLASS
class, void *info
,
755 ULONG len
, ULONG
*ret_len
)
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
;
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
;
781 if (ret_len
) *ret_len
= sizeof(*accounting
);
784 case JobObjectBasicProcessIdList
:
786 JOBOBJECT_BASIC_PROCESS_ID_LIST
*process
= info
;
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
);
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
;
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
;
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
;
863 case JobObjectExtendedLimitInformation
:
864 info_size
= sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION
);
865 limit_flags
= JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS
;
867 case JobObjectBasicLimitInformation
:
868 if (len
!= info_size
) return STATUS_INVALID_PARAMETER
;
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
);
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
);
891 case JobObjectBasicUIRestrictions
:
892 status
= STATUS_SUCCESS
;
895 FIXME( "stub: %p %u %p %u\n", handle
, class, info
, (int)len
);
901 /**************************************************************************
902 * NtIsProcessInJob (NTDLL.@)
904 NTSTATUS WINAPI
NtIsProcessInJob( HANDLE process
, HANDLE job
)
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
);
921 /**************************************************************************
922 * NtAssignProcessToJobObject (NTDLL.@)
924 NTSTATUS WINAPI
NtAssignProcessToJobObject( HANDLE job
, HANDLE process
)
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
);
941 /**********************************************************************
942 * NtCreateDebugObject (NTDLL.@)
944 NTSTATUS WINAPI
NtCreateDebugObject( HANDLE
*handle
, ACCESS_MASK access
,
945 OBJECT_ATTRIBUTES
*attr
, ULONG flags
)
949 struct object_attributes
*objattr
;
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
;
959 wine_server_add_data( req
, objattr
, len
);
960 ret
= wine_server_call( req
);
961 *handle
= wine_server_ptr_handle( reply
->handle
);
969 /**********************************************************************
970 * NtSetInformationDebugObject (NTDLL.@)
972 NTSTATUS WINAPI
NtSetInformationDebugObject( HANDLE handle
, DEBUGOBJECTINFOCLASS
class,
973 void *info
, ULONG len
, ULONG
*ret_len
)
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
);
991 ret
= wine_server_call( req
);
994 if (!ret
&& ret_len
) *ret_len
= 0;
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
)
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
;
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
;
1081 offset
.QuadPart
= 0;
1082 status
= NtReadFile( handle
, NULL
, NULL
, NULL
,
1083 &iosb
, &dos_hdr
, sizeof(dos_hdr
), &offset
, NULL
);
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
);
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
);
1099 /**********************************************************************
1100 * NtWaitForDebugEvent (NTDLL.@)
1102 NTSTATUS WINAPI
NtWaitForDebugEvent( HANDLE handle
, BOOLEAN alertable
, LARGE_INTEGER
*timeout
,
1103 DBGUI_WAIT_STATE_CHANGE
*state
)
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
);
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
);
1127 /* don't pass 64bit load events to 32bit callers */
1128 if (!ret
&& state
->NewState
== DbgLoadDllStateChange
)
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
);
1144 if (ret
!= STATUS_PENDING
) return ret
;
1145 if (!wait
) return STATUS_TIMEOUT
;
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
)
1160 struct object_attributes
*objattr
;
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
);
1178 /**************************************************************************
1179 * NtOpenDirectoryObject (NTDLL.@)
1181 NTSTATUS WINAPI
NtOpenDirectoryObject( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
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
);
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
;
1228 if (status
&& status
!= STATUS_MORE_ENTRIES
)
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
;
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
]) );
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
;
1301 /**************************************************************************
1302 * NtCreateSymbolicLinkObject (NTDLL.@)
1304 NTSTATUS WINAPI
NtCreateSymbolicLinkObject( HANDLE
*handle
, ACCESS_MASK access
,
1305 OBJECT_ATTRIBUTES
*attr
, UNICODE_STRING
*target
)
1309 struct object_attributes
*objattr
;
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
);
1330 /**************************************************************************
1331 * NtOpenSymbolicLinkObject (NTDLL.@)
1333 NTSTATUS WINAPI
NtOpenSymbolicLinkObject( HANDLE
*handle
, ACCESS_MASK access
,
1334 const OBJECT_ATTRIBUTES
*attr
)
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
);
1356 /**************************************************************************
1357 * NtQuerySymbolicLinkObject (NTDLL.@)
1359 NTSTATUS WINAPI
NtQuerySymbolicLinkObject( HANDLE handle
, UNICODE_STRING
*target
, ULONG
*length
)
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
);
1383 /**************************************************************************
1384 * NtMakePermanentObject (NTDLL.@)
1386 NTSTATUS WINAPI
NtMakePermanentObject( HANDLE handle
)
1390 TRACE("%p\n", handle
);
1392 SERVER_START_REQ( set_object_permanence
)
1394 req
->handle
= wine_server_obj_handle( handle
);
1396 ret
= wine_server_call( req
);
1403 /**************************************************************************
1404 * NtMakeTemporaryObject (NTDLL.@)
1406 NTSTATUS WINAPI
NtMakeTemporaryObject( HANDLE handle
)
1410 TRACE("%p\n", handle
);
1412 SERVER_START_REQ( set_object_permanence
)
1414 req
->handle
= wine_server_obj_handle( handle
);
1416 ret
= wine_server_call( req
);
1423 /**************************************************************************
1424 * NtCreateTimer (NTDLL.@)
1426 NTSTATUS WINAPI
NtCreateTimer( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
1431 struct object_attributes
*objattr
;
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
);
1453 /**************************************************************************
1454 * NtOpenTimer (NTDLL.@)
1456 NTSTATUS WINAPI
NtOpenTimer( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
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
;
1500 /* set error but can still succeed */
1501 if (resume
&& ret
== STATUS_SUCCESS
) return STATUS_TIMER_RESUME_IGNORED
;
1506 /**************************************************************************
1507 * NtCancelTimer (NTDLL.@)
1509 NTSTATUS WINAPI
NtCancelTimer( HANDLE handle
, BOOLEAN
*state
)
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
;
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
;
1534 TRACE( "(%p,%d,%p,0x%08x,%p)\n", handle
, class, info
, (int)len
, ret_len
);
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
;
1551 /* convert into relative time */
1552 if (basic_info
->RemainingTime
.QuadPart
> 0) NtQuerySystemTime( &now
);
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;
1562 basic_info
->RemainingTime
.QuadPart
-= now
.QuadPart
;
1564 if (ret_len
) *ret_len
= sizeof(TIMER_BASIC_INFORMATION
);
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
;
1629 ret
= getrusage( RUSAGE_THREAD
, &u1
);
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
;
1636 return STATUS_SUCCESS
;
1638 return STATUS_NO_YIELD_PERFORMED
;
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
);
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 */
1668 if (!when
) return STATUS_SUCCESS
;
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
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
;
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;
1723 #endif /* HAVE_CLOCK_GETTIME */
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
)
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() */
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
1783 if (!has_request
&& !set
)
1784 return STATUS_TIMER_RESOLUTION_NOT_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
;
1818 #ifdef HAVE_CLOCK_GETTIME
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
;
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
)
1841 struct object_attributes
*objattr
;
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
);
1860 /******************************************************************************
1861 * NtOpenKeyedEvent (NTDLL.@)
1863 NTSTATUS WINAPI
NtOpenKeyedEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
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
,
1928 unsigned int status
;
1930 struct object_attributes
*objattr
;
1932 TRACE( "(%p, %x, %p, %d)\n", handle
, (int)access
, attr
, (int)threads
);
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
);
1951 /***********************************************************************
1952 * NtOpenIoCompletion (NTDLL.@)
1954 NTSTATUS WINAPI
NtOpenIoCompletion( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
1956 unsigned int status
;
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
);
1976 /***********************************************************************
1977 * NtSetIoCompletion (NTDLL.@)
1979 NTSTATUS WINAPI
NtSetIoCompletion( HANDLE handle
, ULONG_PTR key
, ULONG_PTR value
,
1980 NTSTATUS status
, SIZE_T count
)
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
);
1990 req
->cvalue
= value
;
1991 req
->status
= status
;
1992 req
->information
= count
;
1993 ret
= wine_server_call( req
);
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
);
2012 SERVER_START_REQ( remove_completion
)
2014 req
->handle
= wine_server_obj_handle( handle
);
2015 if (!(status
= wine_server_call( req
)))
2018 *value
= reply
->cvalue
;
2019 io
->Information
= reply
->information
;
2020 io
->Status
= reply
->status
;
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
;
2040 TRACE( "%p %p %u %p %p %u\n", handle
, info
, (int)count
, written
, timeout
, alertable
);
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
;
2058 if (status
!= STATUS_SUCCESS
) break;
2061 if (i
|| status
!= STATUS_PENDING
)
2063 if (status
== STATUS_PENDING
) status
= STATUS_SUCCESS
;
2066 status
= NtWaitForSingleObject( handle
, alertable
, timeout
);
2067 if (status
!= WAIT_OBJECT_0
) break;
2069 *written
= i
? i
: 1;
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
;
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
;
2101 else status
= STATUS_INFO_LENGTH_MISMATCH
;
2105 return STATUS_INVALID_PARAMETER
;
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
)
2119 unsigned int file_access
;
2121 struct object_attributes
*objattr
;
2125 switch (protect
& 0xff)
2128 case PAGE_EXECUTE_READ
:
2129 case PAGE_WRITECOPY
:
2130 case PAGE_EXECUTE_WRITECOPY
:
2131 file_access
= FILE_READ_DATA
;
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
;
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
);
2166 /***********************************************************************
2167 * NtOpenSection (NTDLL.@)
2169 NTSTATUS WINAPI
NtOpenSection( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
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
);
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
)
2302 if ((ULONG_PTR
)atomstr
>> 16)
2304 const WCHAR
* ptr
= atomstr
;
2305 if (!len
) return STATUS_OBJECT_NAME_INVALID
;
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
);
2321 if (!atom
|| atom
>= MAXINTATOM
) return STATUS_INVALID_PARAMETER
;
2323 return STATUS_SUCCESS
;
2326 static ULONG
integral_atom_name( WCHAR
*buffer
, ULONG len
, RTL_ATOM atom
)
2329 int ret
= snprintf( tmp
, sizeof(tmp
), "#%u", atom
);
2331 len
/= sizeof(WCHAR
);
2334 if (len
<= ret
) ret
= len
- 1;
2335 ascii_to_unicode( buffer
, tmp
, ret
);
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
;
2359 TRACE( "%s -> %x\n", debugstr_wn(name
, length
/sizeof(WCHAR
)), status
== STATUS_SUCCESS
? *atom
: 0 );
2364 /***********************************************************************
2365 * NtDeleteAtom (NTDLL.@)
2367 NTSTATUS WINAPI
NtDeleteAtom( RTL_ATOM atom
)
2369 unsigned int status
;
2371 SERVER_START_REQ( delete_atom
)
2374 status
= wine_server_call( req
);
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
;
2398 TRACE( "%s -> %x\n", debugstr_wn(name
, length
/sizeof(WCHAR
)), status
== STATUS_SUCCESS
? *atom
: 0 );
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
;
2413 case AtomBasicInformation
:
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
)
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;
2430 else status
= STATUS_INVALID_PARAMETER
;
2434 SERVER_START_REQ( get_atom_information
)
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
);
2444 abi
->NameLength
= name_len
;
2445 abi
->Name
[name_len
/ sizeof(WCHAR
)] = 0;
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
;
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
;
2466 FIXME( "Unsupported class %u\n", class );
2467 status
= STATUS_INVALID_INFO_CLASS
;
2474 union tid_alert_entry
2478 #elif defined(HAVE_KQUEUE)
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
);
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
];
2519 #elif defined(HAVE_KQUEUE)
2523 static const struct kevent init_event
=
2526 .filter
= EVFILT_USER
,
2527 .flags
= EV_ADD
| EV_CLEAR
,
2535 ERR( "kqueue failed with error: %d (%s)\n", errno
, strerror( errno
) );
2539 if (kevent( kq
, &init_event
, 1, NULL
, 0, NULL
) == -1)
2541 ERR( "kevent creation failed with error: %d (%s)\n", errno
, strerror( errno
) );
2546 if (InterlockedCompareExchange( (LONG
*)&entry
->kq
, kq
, 0 ))
2554 if (NtCreateEvent( &event
, EVENT_ALL_ACCESS
, NULL
, SynchronizationEvent
, FALSE
))
2556 if (InterlockedCompareExchangePointer( &entry
->event
, event
, NULL
))
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
;
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
=
2588 .filter
= EVFILT_USER
,
2590 .fflags
= NOTE_TRIGGER
,
2595 kevent( entry
->kq
, &signal_event
, 1, NULL
, 0, NULL
);
2596 return STATUS_SUCCESS
;
2599 return NtSetEvent( entry
->event
, NULL
);
2604 #if defined(USE_FUTEX) || defined(HAVE_KQUEUE)
2605 static LONGLONG
get_absolute_timeout( const LARGE_INTEGER
*timeout
)
2609 if (timeout
->QuadPart
>= 0) return timeout
->QuadPart
;
2610 NtQuerySystemTime( &now
);
2611 return now
.QuadPart
- timeout
->QuadPart
;
2614 static LONGLONG
update_timeout( ULONGLONG end
)
2619 NtQuerySystemTime( &now
);
2620 timeleft
= end
- now
.QuadPart
;
2621 if (timeleft
< 0) timeleft
= 0;
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
;
2640 LONG
*futex
= &entry
->futex
;
2646 if (timeout
->QuadPart
== TIMEOUT_INFINITE
)
2649 end
= get_absolute_timeout( timeout
);
2652 while (!InterlockedExchange( futex
, 0 ))
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, ×pec
);
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)
2674 struct timespec timespec
;
2675 struct kevent wait_event
;
2679 if (timeout
->QuadPart
== TIMEOUT_INFINITE
)
2682 end
= get_absolute_timeout( 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
? ×pec
: NULL
);
2697 } while (ret
== -1 && errno
== EINTR
);
2702 return STATUS_ALERTED
;
2704 return STATUS_TIMEOUT
;
2706 ERR( "kevent failed with error: %d (%s)\n", errno
, strerror( errno
) );
2707 return STATUS_INVALID_HANDLE
;
2712 NTSTATUS status
= NtWaitForSingleObject( entry
->event
, FALSE
, timeout
);
2713 if (!status
) return STATUS_ALERTED
;
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
;