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>
52 # include <mach/mach.h>
53 # include <mach/task.h>
54 # include <mach/semaphore.h>
55 # include <mach/mach_time.h>
59 #define WIN32_NO_STATUS
60 #define NONAMELESSUNION
64 #include "wine/server.h"
65 #include "wine/debug.h"
66 #include "unix_private.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(sync
);
70 HANDLE keyed_event
= 0;
72 static const char *debugstr_timeout( const LARGE_INTEGER
*timeout
)
74 if (!timeout
) return "(infinite)";
75 return wine_dbgstr_longlong( timeout
->QuadPart
);
78 /* return a monotonic time counter, in Win32 ticks */
79 static inline ULONGLONG
monotonic_counter(void)
83 static mach_timebase_info_data_t timebase
;
85 if (!timebase
.denom
) mach_timebase_info( &timebase
);
86 #ifdef HAVE_MACH_CONTINUOUS_TIME
87 if (&mach_continuous_time
!= NULL
)
88 return mach_continuous_time() * timebase
.numer
/ timebase
.denom
/ 100;
90 return mach_absolute_time() * timebase
.numer
/ timebase
.denom
/ 100;
91 #elif defined(HAVE_CLOCK_GETTIME)
93 #ifdef CLOCK_MONOTONIC_RAW
94 if (!clock_gettime( CLOCK_MONOTONIC_RAW
, &ts
))
95 return ts
.tv_sec
* (ULONGLONG
)TICKSPERSEC
+ ts
.tv_nsec
/ 100;
97 if (!clock_gettime( CLOCK_MONOTONIC
, &ts
))
98 return ts
.tv_sec
* (ULONGLONG
)TICKSPERSEC
+ ts
.tv_nsec
/ 100;
100 gettimeofday( &now
, 0 );
101 return ticks_from_time_t( now
.tv_sec
) + now
.tv_usec
* 10 - server_start_time
;
110 static int futex_private
= 128;
112 static inline int futex_wait( const int *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
| futex_private
, val
, &timeout32
, 0, 0 );
125 return syscall( __NR_futex
, addr
, FUTEX_WAIT
| futex_private
, val
, timeout
, 0, 0 );
128 static inline int futex_wake( const int *addr
, int val
)
130 return syscall( __NR_futex
, addr
, FUTEX_WAKE
| futex_private
, val
, NULL
, 0, 0 );
133 static inline int use_futexes(void)
135 static int supported
= -1;
139 futex_wait( &supported
, 10, NULL
);
143 futex_wait( &supported
, 10, NULL
);
145 supported
= (errno
!= ENOSYS
);
153 /* create a struct security_descriptor and contained information in one contiguous piece of memory */
154 NTSTATUS
alloc_object_attributes( const OBJECT_ATTRIBUTES
*attr
, struct object_attributes
**ret
,
155 data_size_t
*ret_len
)
157 unsigned int len
= sizeof(**ret
);
158 SID
*owner
= NULL
, *group
= NULL
;
159 ACL
*dacl
= NULL
, *sacl
= NULL
;
160 SECURITY_DESCRIPTOR
*sd
;
165 if (!attr
) return STATUS_SUCCESS
;
167 if (attr
->Length
!= sizeof(*attr
)) return STATUS_INVALID_PARAMETER
;
169 if ((sd
= attr
->SecurityDescriptor
))
171 len
+= sizeof(struct security_descriptor
);
172 if (sd
->Revision
!= SECURITY_DESCRIPTOR_REVISION
) return STATUS_UNKNOWN_REVISION
;
173 if (sd
->Control
& SE_SELF_RELATIVE
)
175 SECURITY_DESCRIPTOR_RELATIVE
*rel
= (SECURITY_DESCRIPTOR_RELATIVE
*)sd
;
176 if (rel
->Owner
) owner
= (PSID
)((BYTE
*)rel
+ rel
->Owner
);
177 if (rel
->Group
) group
= (PSID
)((BYTE
*)rel
+ rel
->Group
);
178 if ((sd
->Control
& SE_SACL_PRESENT
) && rel
->Sacl
) sacl
= (PSID
)((BYTE
*)rel
+ rel
->Sacl
);
179 if ((sd
->Control
& SE_DACL_PRESENT
) && rel
->Dacl
) dacl
= (PSID
)((BYTE
*)rel
+ rel
->Dacl
);
185 if (sd
->Control
& SE_SACL_PRESENT
) sacl
= sd
->Sacl
;
186 if (sd
->Control
& SE_DACL_PRESENT
) dacl
= sd
->Dacl
;
189 if (owner
) len
+= offsetof( SID
, SubAuthority
[owner
->SubAuthorityCount
] );
190 if (group
) len
+= offsetof( SID
, SubAuthority
[group
->SubAuthorityCount
] );
191 if (sacl
) len
+= sacl
->AclSize
;
192 if (dacl
) len
+= dacl
->AclSize
;
194 /* fix alignment for the Unicode name that follows the structure */
195 len
= (len
+ sizeof(WCHAR
) - 1) & ~(sizeof(WCHAR
) - 1);
198 if (attr
->ObjectName
)
200 if ((ULONG_PTR
)attr
->ObjectName
->Buffer
& (sizeof(WCHAR
) - 1)) return STATUS_DATATYPE_MISALIGNMENT
;
201 if (attr
->ObjectName
->Length
& (sizeof(WCHAR
) - 1)) return STATUS_OBJECT_NAME_INVALID
;
202 len
+= attr
->ObjectName
->Length
;
204 else if (attr
->RootDirectory
) return STATUS_OBJECT_NAME_INVALID
;
206 len
= (len
+ 3) & ~3; /* DWORD-align the entire structure */
208 if (!(*ret
= calloc( len
, 1 ))) return STATUS_NO_MEMORY
;
210 (*ret
)->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
211 (*ret
)->attributes
= attr
->Attributes
;
213 if (attr
->SecurityDescriptor
)
215 struct security_descriptor
*descr
= (struct security_descriptor
*)(*ret
+ 1);
216 unsigned char *ptr
= (unsigned char *)(descr
+ 1);
218 descr
->control
= sd
->Control
& ~SE_SELF_RELATIVE
;
219 if (owner
) descr
->owner_len
= offsetof( SID
, SubAuthority
[owner
->SubAuthorityCount
] );
220 if (group
) descr
->group_len
= offsetof( SID
, SubAuthority
[group
->SubAuthorityCount
] );
221 if (sacl
) descr
->sacl_len
= sacl
->AclSize
;
222 if (dacl
) descr
->dacl_len
= dacl
->AclSize
;
224 memcpy( ptr
, owner
, descr
->owner_len
);
225 ptr
+= descr
->owner_len
;
226 memcpy( ptr
, group
, descr
->group_len
);
227 ptr
+= descr
->group_len
;
228 memcpy( ptr
, sacl
, descr
->sacl_len
);
229 ptr
+= descr
->sacl_len
;
230 memcpy( ptr
, dacl
, descr
->dacl_len
);
231 (*ret
)->sd_len
= (sizeof(*descr
) + descr
->owner_len
+ descr
->group_len
+ descr
->sacl_len
+
232 descr
->dacl_len
+ sizeof(WCHAR
) - 1) & ~(sizeof(WCHAR
) - 1);
235 if (attr
->ObjectName
)
237 unsigned char *ptr
= (unsigned char *)(*ret
+ 1) + (*ret
)->sd_len
;
238 (*ret
)->name_len
= attr
->ObjectName
->Length
;
239 memcpy( ptr
, attr
->ObjectName
->Buffer
, (*ret
)->name_len
);
243 return STATUS_SUCCESS
;
247 static NTSTATUS
validate_open_object_attributes( const OBJECT_ATTRIBUTES
*attr
)
249 if (!attr
|| attr
->Length
!= sizeof(*attr
)) return STATUS_INVALID_PARAMETER
;
251 if (attr
->ObjectName
)
253 if ((ULONG_PTR
)attr
->ObjectName
->Buffer
& (sizeof(WCHAR
) - 1)) return STATUS_DATATYPE_MISALIGNMENT
;
254 if (attr
->ObjectName
->Length
& (sizeof(WCHAR
) - 1)) return STATUS_OBJECT_NAME_INVALID
;
256 else if (attr
->RootDirectory
) return STATUS_OBJECT_NAME_INVALID
;
258 return STATUS_SUCCESS
;
262 /******************************************************************************
263 * NtCreateSemaphore (NTDLL.@)
265 NTSTATUS WINAPI
NtCreateSemaphore( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
266 LONG initial
, LONG max
)
270 struct object_attributes
*objattr
;
273 if (max
<= 0 || initial
< 0 || initial
> max
) return STATUS_INVALID_PARAMETER
;
274 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
276 SERVER_START_REQ( create_semaphore
)
278 req
->access
= access
;
279 req
->initial
= initial
;
281 wine_server_add_data( req
, objattr
, len
);
282 ret
= wine_server_call( req
);
283 *handle
= wine_server_ptr_handle( reply
->handle
);
292 /******************************************************************************
293 * NtOpenSemaphore (NTDLL.@)
295 NTSTATUS WINAPI
NtOpenSemaphore( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
300 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
302 SERVER_START_REQ( open_semaphore
)
304 req
->access
= access
;
305 req
->attributes
= attr
->Attributes
;
306 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
307 if (attr
->ObjectName
)
308 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
309 ret
= wine_server_call( req
);
310 *handle
= wine_server_ptr_handle( reply
->handle
);
317 /******************************************************************************
318 * NtQuerySemaphore (NTDLL.@)
320 NTSTATUS WINAPI
NtQuerySemaphore( HANDLE handle
, SEMAPHORE_INFORMATION_CLASS
class,
321 void *info
, ULONG len
, ULONG
*ret_len
)
324 SEMAPHORE_BASIC_INFORMATION
*out
= info
;
326 TRACE("(%p, %u, %p, %u, %p)\n", handle
, class, info
, len
, ret_len
);
328 if (class != SemaphoreBasicInformation
)
330 FIXME("(%p,%d,%u) Unknown class\n", handle
, class, len
);
331 return STATUS_INVALID_INFO_CLASS
;
334 if (len
!= sizeof(SEMAPHORE_BASIC_INFORMATION
)) return STATUS_INFO_LENGTH_MISMATCH
;
336 SERVER_START_REQ( query_semaphore
)
338 req
->handle
= wine_server_obj_handle( handle
);
339 if (!(ret
= wine_server_call( req
)))
341 out
->CurrentCount
= reply
->current
;
342 out
->MaximumCount
= reply
->max
;
343 if (ret_len
) *ret_len
= sizeof(SEMAPHORE_BASIC_INFORMATION
);
351 /******************************************************************************
352 * NtReleaseSemaphore (NTDLL.@)
354 NTSTATUS WINAPI
NtReleaseSemaphore( HANDLE handle
, ULONG count
, ULONG
*previous
)
358 SERVER_START_REQ( release_semaphore
)
360 req
->handle
= wine_server_obj_handle( handle
);
362 if (!(ret
= wine_server_call( req
)))
364 if (previous
) *previous
= reply
->prev_count
;
372 /**************************************************************************
373 * NtCreateEvent (NTDLL.@)
375 NTSTATUS WINAPI
NtCreateEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
376 EVENT_TYPE type
, BOOLEAN state
)
380 struct object_attributes
*objattr
;
383 if (type
!= NotificationEvent
&& type
!= SynchronizationEvent
) return STATUS_INVALID_PARAMETER
;
384 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
386 SERVER_START_REQ( create_event
)
388 req
->access
= access
;
389 req
->manual_reset
= (type
== NotificationEvent
);
390 req
->initial_state
= state
;
391 wine_server_add_data( req
, objattr
, len
);
392 ret
= wine_server_call( req
);
393 *handle
= wine_server_ptr_handle( reply
->handle
);
402 /******************************************************************************
403 * NtOpenEvent (NTDLL.@)
405 NTSTATUS WINAPI
NtOpenEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
410 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
412 SERVER_START_REQ( open_event
)
414 req
->access
= access
;
415 req
->attributes
= attr
->Attributes
;
416 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
417 if (attr
->ObjectName
)
418 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
419 ret
= wine_server_call( req
);
420 *handle
= wine_server_ptr_handle( reply
->handle
);
427 /******************************************************************************
428 * NtSetEvent (NTDLL.@)
430 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, LONG
*prev_state
)
434 SERVER_START_REQ( event_op
)
436 req
->handle
= wine_server_obj_handle( handle
);
438 ret
= wine_server_call( req
);
439 if (!ret
&& prev_state
) *prev_state
= reply
->state
;
446 /******************************************************************************
447 * NtResetEvent (NTDLL.@)
449 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, LONG
*prev_state
)
453 SERVER_START_REQ( event_op
)
455 req
->handle
= wine_server_obj_handle( handle
);
456 req
->op
= RESET_EVENT
;
457 ret
= wine_server_call( req
);
458 if (!ret
&& prev_state
) *prev_state
= reply
->state
;
465 /******************************************************************************
466 * NtClearEvent (NTDLL.@)
468 NTSTATUS WINAPI
NtClearEvent( HANDLE handle
)
470 /* FIXME: same as NtResetEvent ??? */
471 return NtResetEvent( handle
, NULL
);
475 /******************************************************************************
476 * NtPulseEvent (NTDLL.@)
478 NTSTATUS WINAPI
NtPulseEvent( HANDLE handle
, LONG
*prev_state
)
482 SERVER_START_REQ( event_op
)
484 req
->handle
= wine_server_obj_handle( handle
);
485 req
->op
= PULSE_EVENT
;
486 ret
= wine_server_call( req
);
487 if (!ret
&& prev_state
) *prev_state
= reply
->state
;
494 /******************************************************************************
495 * NtQueryEvent (NTDLL.@)
497 NTSTATUS WINAPI
NtQueryEvent( HANDLE handle
, EVENT_INFORMATION_CLASS
class,
498 void *info
, ULONG len
, ULONG
*ret_len
)
501 EVENT_BASIC_INFORMATION
*out
= info
;
503 TRACE("(%p, %u, %p, %u, %p)\n", handle
, class, info
, len
, ret_len
);
505 if (class != EventBasicInformation
)
507 FIXME("(%p, %d, %d) Unknown class\n",
509 return STATUS_INVALID_INFO_CLASS
;
512 if (len
!= sizeof(EVENT_BASIC_INFORMATION
)) return STATUS_INFO_LENGTH_MISMATCH
;
514 SERVER_START_REQ( query_event
)
516 req
->handle
= wine_server_obj_handle( handle
);
517 if (!(ret
= wine_server_call( req
)))
519 out
->EventType
= reply
->manual_reset
? NotificationEvent
: SynchronizationEvent
;
520 out
->EventState
= reply
->state
;
521 if (ret_len
) *ret_len
= sizeof(EVENT_BASIC_INFORMATION
);
529 /******************************************************************************
530 * NtCreateMutant (NTDLL.@)
532 NTSTATUS WINAPI
NtCreateMutant( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
537 struct object_attributes
*objattr
;
540 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
542 SERVER_START_REQ( create_mutex
)
544 req
->access
= access
;
546 wine_server_add_data( req
, objattr
, len
);
547 ret
= wine_server_call( req
);
548 *handle
= wine_server_ptr_handle( reply
->handle
);
557 /**************************************************************************
558 * NtOpenMutant (NTDLL.@)
560 NTSTATUS WINAPI
NtOpenMutant( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
565 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
567 SERVER_START_REQ( open_mutex
)
569 req
->access
= access
;
570 req
->attributes
= attr
->Attributes
;
571 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
572 if (attr
->ObjectName
)
573 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
574 ret
= wine_server_call( req
);
575 *handle
= wine_server_ptr_handle( reply
->handle
);
582 /**************************************************************************
583 * NtReleaseMutant (NTDLL.@)
585 NTSTATUS WINAPI
NtReleaseMutant( HANDLE handle
, LONG
*prev_count
)
589 SERVER_START_REQ( release_mutex
)
591 req
->handle
= wine_server_obj_handle( handle
);
592 ret
= wine_server_call( req
);
593 if (prev_count
) *prev_count
= 1 - reply
->prev_count
;
600 /******************************************************************
601 * NtQueryMutant (NTDLL.@)
603 NTSTATUS WINAPI
NtQueryMutant( HANDLE handle
, MUTANT_INFORMATION_CLASS
class,
604 void *info
, ULONG len
, ULONG
*ret_len
)
607 MUTANT_BASIC_INFORMATION
*out
= info
;
609 TRACE("(%p, %u, %p, %u, %p)\n", handle
, class, info
, len
, ret_len
);
611 if (class != MutantBasicInformation
)
613 FIXME( "(%p, %d, %d) Unknown class\n", handle
, class, len
);
614 return STATUS_INVALID_INFO_CLASS
;
617 if (len
!= sizeof(MUTANT_BASIC_INFORMATION
)) return STATUS_INFO_LENGTH_MISMATCH
;
619 SERVER_START_REQ( query_mutex
)
621 req
->handle
= wine_server_obj_handle( handle
);
622 if (!(ret
= wine_server_call( req
)))
624 out
->CurrentCount
= 1 - reply
->count
;
625 out
->OwnedByCaller
= reply
->owned
;
626 out
->AbandonedState
= reply
->abandoned
;
627 if (ret_len
) *ret_len
= sizeof(MUTANT_BASIC_INFORMATION
);
635 /**************************************************************************
636 * NtCreateJobObject (NTDLL.@)
638 NTSTATUS WINAPI
NtCreateJobObject( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
642 struct object_attributes
*objattr
;
645 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
647 SERVER_START_REQ( create_job
)
649 req
->access
= access
;
650 wine_server_add_data( req
, objattr
, len
);
651 ret
= wine_server_call( req
);
652 *handle
= wine_server_ptr_handle( reply
->handle
);
660 /**************************************************************************
661 * NtOpenJobObject (NTDLL.@)
663 NTSTATUS WINAPI
NtOpenJobObject( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
668 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
670 SERVER_START_REQ( open_job
)
672 req
->access
= access
;
673 req
->attributes
= attr
->Attributes
;
674 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
675 if (attr
->ObjectName
)
676 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
677 ret
= wine_server_call( req
);
678 *handle
= wine_server_ptr_handle( reply
->handle
);
685 /**************************************************************************
686 * NtTerminateJobObject (NTDLL.@)
688 NTSTATUS WINAPI
NtTerminateJobObject( HANDLE handle
, NTSTATUS status
)
692 TRACE( "(%p, %d)\n", handle
, status
);
694 SERVER_START_REQ( terminate_job
)
696 req
->handle
= wine_server_obj_handle( handle
);
697 req
->status
= status
;
698 ret
= wine_server_call( req
);
706 /**************************************************************************
707 * NtQueryInformationJobObject (NTDLL.@)
709 NTSTATUS WINAPI
NtQueryInformationJobObject( HANDLE handle
, JOBOBJECTINFOCLASS
class, void *info
,
710 ULONG len
, ULONG
*ret_len
)
714 TRACE( "semi-stub: %p %u %p %u %p\n", handle
, class, info
, len
, ret_len
);
716 if (class >= MaxJobObjectInfoClass
) return STATUS_INVALID_PARAMETER
;
720 case JobObjectBasicAccountingInformation
:
722 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION
*accounting
= info
;
724 if (len
< sizeof(*accounting
)) return STATUS_INFO_LENGTH_MISMATCH
;
725 SERVER_START_REQ(get_job_info
)
727 req
->handle
= wine_server_obj_handle( handle
);
728 if (!(ret
= wine_server_call( req
)))
730 memset( accounting
, 0, sizeof(*accounting
) );
731 accounting
->TotalProcesses
= reply
->total_processes
;
732 accounting
->ActiveProcesses
= reply
->active_processes
;
736 if (ret_len
) *ret_len
= sizeof(*accounting
);
739 case JobObjectBasicProcessIdList
:
741 JOBOBJECT_BASIC_PROCESS_ID_LIST
*process
= info
;
744 if (len
< sizeof(*process
)) return STATUS_INFO_LENGTH_MISMATCH
;
746 count
= len
- offsetof( JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
);
747 count
/= sizeof(process
->ProcessIdList
[0]);
749 SERVER_START_REQ( get_job_info
)
751 req
->handle
= wine_server_user_handle(handle
);
752 wine_server_set_reply(req
, process
->ProcessIdList
, count
* sizeof(process_id_t
));
753 if (!(ret
= wine_server_call(req
)))
755 process
->NumberOfAssignedProcesses
= reply
->active_processes
;
756 process
->NumberOfProcessIdsInList
= min(count
, reply
->active_processes
);
761 if (ret
!= STATUS_SUCCESS
) return ret
;
763 if (sizeof(process_id_t
) < sizeof(process
->ProcessIdList
[0]))
765 /* start from the end to not overwrite */
766 for (i
= process
->NumberOfProcessIdsInList
; i
--;)
768 ULONG_PTR id
= ((process_id_t
*)process
->ProcessIdList
)[i
];
769 process
->ProcessIdList
[i
] = id
;
774 *ret_len
= offsetof( JOBOBJECT_BASIC_PROCESS_ID_LIST
, ProcessIdList
[process
->NumberOfProcessIdsInList
] );
775 return count
< process
->NumberOfAssignedProcesses
? STATUS_MORE_ENTRIES
: STATUS_SUCCESS
;
777 case JobObjectExtendedLimitInformation
:
779 JOBOBJECT_EXTENDED_LIMIT_INFORMATION
*extended_limit
= info
;
781 if (len
< sizeof(*extended_limit
)) return STATUS_INFO_LENGTH_MISMATCH
;
782 memset( extended_limit
, 0, sizeof(*extended_limit
) );
783 if (ret_len
) *ret_len
= sizeof(*extended_limit
);
784 return STATUS_SUCCESS
;
786 case JobObjectBasicLimitInformation
:
788 JOBOBJECT_BASIC_LIMIT_INFORMATION
*basic_limit
= info
;
790 if (len
< sizeof(*basic_limit
)) return STATUS_INFO_LENGTH_MISMATCH
;
791 memset( basic_limit
, 0, sizeof(*basic_limit
) );
792 if (ret_len
) *ret_len
= sizeof(*basic_limit
);
793 return STATUS_SUCCESS
;
796 return STATUS_NOT_IMPLEMENTED
;
801 /**************************************************************************
802 * NtSetInformationJobObject (NTDLL.@)
804 NTSTATUS WINAPI
NtSetInformationJobObject( HANDLE handle
, JOBOBJECTINFOCLASS
class, void *info
, ULONG len
)
806 NTSTATUS status
= STATUS_NOT_IMPLEMENTED
;
807 JOBOBJECT_BASIC_LIMIT_INFORMATION
*basic_limit
;
808 ULONG info_size
= sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION
);
809 DWORD limit_flags
= JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS
;
811 TRACE( "(%p, %u, %p, %u)\n", handle
, class, info
, len
);
813 if (class >= MaxJobObjectInfoClass
) return STATUS_INVALID_PARAMETER
;
818 case JobObjectExtendedLimitInformation
:
819 info_size
= sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION
);
820 limit_flags
= JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS
;
822 case JobObjectBasicLimitInformation
:
823 if (len
!= info_size
) return STATUS_INVALID_PARAMETER
;
825 if (basic_limit
->LimitFlags
& ~limit_flags
) return STATUS_INVALID_PARAMETER
;
826 SERVER_START_REQ( set_job_limits
)
828 req
->handle
= wine_server_obj_handle( handle
);
829 req
->limit_flags
= basic_limit
->LimitFlags
;
830 status
= wine_server_call( req
);
834 case JobObjectAssociateCompletionPortInformation
:
835 if (len
!= sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT
)) return STATUS_INVALID_PARAMETER
;
836 SERVER_START_REQ( set_job_completion_port
)
838 JOBOBJECT_ASSOCIATE_COMPLETION_PORT
*port_info
= info
;
839 req
->job
= wine_server_obj_handle( handle
);
840 req
->port
= wine_server_obj_handle( port_info
->CompletionPort
);
841 req
->key
= wine_server_client_ptr( port_info
->CompletionKey
);
842 status
= wine_server_call( req
);
846 case JobObjectBasicUIRestrictions
:
847 status
= STATUS_SUCCESS
;
850 FIXME( "stub: %p %u %p %u\n", handle
, class, info
, len
);
856 /**************************************************************************
857 * NtIsProcessInJob (NTDLL.@)
859 NTSTATUS WINAPI
NtIsProcessInJob( HANDLE process
, HANDLE job
)
863 TRACE( "(%p %p)\n", job
, process
);
865 SERVER_START_REQ( process_in_job
)
867 req
->job
= wine_server_obj_handle( job
);
868 req
->process
= wine_server_obj_handle( process
);
869 status
= wine_server_call( req
);
876 /**************************************************************************
877 * NtAssignProcessToJobObject (NTDLL.@)
879 NTSTATUS WINAPI
NtAssignProcessToJobObject( HANDLE job
, HANDLE process
)
883 TRACE( "(%p %p)\n", job
, process
);
885 SERVER_START_REQ( assign_job
)
887 req
->job
= wine_server_obj_handle( job
);
888 req
->process
= wine_server_obj_handle( process
);
889 status
= wine_server_call( req
);
896 /**********************************************************************
897 * NtCreateDebugObject (NTDLL.@)
899 NTSTATUS WINAPI
NtCreateDebugObject( HANDLE
*handle
, ACCESS_MASK access
,
900 OBJECT_ATTRIBUTES
*attr
, ULONG flags
)
904 struct object_attributes
*objattr
;
907 if (flags
& ~DEBUG_KILL_ON_CLOSE
) return STATUS_INVALID_PARAMETER
;
908 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
910 SERVER_START_REQ( create_debug_obj
)
912 req
->access
= access
;
914 wine_server_add_data( req
, objattr
, len
);
915 ret
= wine_server_call( req
);
916 *handle
= wine_server_ptr_handle( reply
->handle
);
924 /**********************************************************************
925 * NtSetInformationDebugObject (NTDLL.@)
927 NTSTATUS WINAPI
NtSetInformationDebugObject( HANDLE handle
, DEBUGOBJECTINFOCLASS
class,
928 void *info
, ULONG len
, ULONG
*ret_len
)
933 if (class != DebugObjectKillProcessOnExitInformation
) return STATUS_INVALID_PARAMETER
;
934 if (len
!= sizeof(ULONG
))
936 if (ret_len
) *ret_len
= sizeof(ULONG
);
937 return STATUS_INFO_LENGTH_MISMATCH
;
939 flags
= *(ULONG
*)info
;
940 if (flags
& ~DEBUG_KILL_ON_CLOSE
) return STATUS_INVALID_PARAMETER
;
942 SERVER_START_REQ( set_debug_obj_info
)
944 req
->debug
= wine_server_obj_handle( handle
);
946 ret
= wine_server_call( req
);
949 if (!ret
&& ret_len
) *ret_len
= 0;
954 /* convert the server event data to an NT state change; helper for NtWaitForDebugEvent */
955 static NTSTATUS
event_data_to_state_change( const debug_event_t
*data
, DBGUI_WAIT_STATE_CHANGE
*state
)
962 case DbgReplyPending
:
963 return STATUS_PENDING
;
964 case DbgCreateThreadStateChange
:
966 DBGUI_CREATE_THREAD
*info
= &state
->StateInfo
.CreateThread
;
967 info
->HandleToThread
= wine_server_ptr_handle( data
->create_thread
.handle
);
968 info
->NewThread
.StartAddress
= wine_server_get_ptr( data
->create_thread
.start
);
969 return STATUS_SUCCESS
;
971 case DbgCreateProcessStateChange
:
973 DBGUI_CREATE_PROCESS
*info
= &state
->StateInfo
.CreateProcessInfo
;
974 info
->HandleToProcess
= wine_server_ptr_handle( data
->create_process
.process
);
975 info
->HandleToThread
= wine_server_ptr_handle( data
->create_process
.thread
);
976 info
->NewProcess
.FileHandle
= wine_server_ptr_handle( data
->create_process
.file
);
977 info
->NewProcess
.BaseOfImage
= wine_server_get_ptr( data
->create_process
.base
);
978 info
->NewProcess
.DebugInfoFileOffset
= data
->create_process
.dbg_offset
;
979 info
->NewProcess
.DebugInfoSize
= data
->create_process
.dbg_size
;
980 info
->NewProcess
.InitialThread
.StartAddress
= wine_server_get_ptr( data
->create_process
.start
);
981 return STATUS_SUCCESS
;
983 case DbgExitThreadStateChange
:
984 state
->StateInfo
.ExitThread
.ExitStatus
= data
->exit
.exit_code
;
985 return STATUS_SUCCESS
;
986 case DbgExitProcessStateChange
:
987 state
->StateInfo
.ExitProcess
.ExitStatus
= data
->exit
.exit_code
;
988 return STATUS_SUCCESS
;
989 case DbgExceptionStateChange
:
990 case DbgBreakpointStateChange
:
991 case DbgSingleStepStateChange
:
993 DBGKM_EXCEPTION
*info
= &state
->StateInfo
.Exception
;
994 info
->FirstChance
= data
->exception
.first
;
995 info
->ExceptionRecord
.ExceptionCode
= data
->exception
.exc_code
;
996 info
->ExceptionRecord
.ExceptionFlags
= data
->exception
.flags
;
997 info
->ExceptionRecord
.ExceptionRecord
= wine_server_get_ptr( data
->exception
.record
);
998 info
->ExceptionRecord
.ExceptionAddress
= wine_server_get_ptr( data
->exception
.address
);
999 info
->ExceptionRecord
.NumberParameters
= data
->exception
.nb_params
;
1000 for (i
= 0; i
< data
->exception
.nb_params
; i
++)
1001 info
->ExceptionRecord
.ExceptionInformation
[i
] = data
->exception
.params
[i
];
1002 return STATUS_SUCCESS
;
1004 case DbgLoadDllStateChange
:
1006 DBGKM_LOAD_DLL
*info
= &state
->StateInfo
.LoadDll
;
1007 info
->FileHandle
= wine_server_ptr_handle( data
->load_dll
.handle
);
1008 info
->BaseOfDll
= wine_server_get_ptr( data
->load_dll
.base
);
1009 info
->DebugInfoFileOffset
= data
->load_dll
.dbg_offset
;
1010 info
->DebugInfoSize
= data
->load_dll
.dbg_size
;
1011 info
->NamePointer
= wine_server_get_ptr( data
->load_dll
.name
);
1012 return STATUS_SUCCESS
;
1014 case DbgUnloadDllStateChange
:
1015 state
->StateInfo
.UnloadDll
.BaseAddress
= wine_server_get_ptr( data
->unload_dll
.base
);
1016 return STATUS_SUCCESS
;
1018 return STATUS_INTERNAL_ERROR
;
1021 /**********************************************************************
1022 * NtWaitForDebugEvent (NTDLL.@)
1024 NTSTATUS WINAPI
NtWaitForDebugEvent( HANDLE handle
, BOOLEAN alertable
, LARGE_INTEGER
*timeout
,
1025 DBGUI_WAIT_STATE_CHANGE
*state
)
1033 SERVER_START_REQ( wait_debug_event
)
1035 req
->debug
= wine_server_obj_handle( handle
);
1036 wine_server_set_reply( req
, &data
, sizeof(data
) );
1037 ret
= wine_server_call( req
);
1038 if (!ret
&& !(ret
= event_data_to_state_change( &data
, state
)))
1040 state
->NewState
= data
.code
;
1041 state
->AppClientId
.UniqueProcess
= ULongToHandle( reply
->pid
);
1042 state
->AppClientId
.UniqueThread
= ULongToHandle( reply
->tid
);
1047 if (ret
!= STATUS_PENDING
) return ret
;
1048 if (!wait
) return STATUS_TIMEOUT
;
1050 ret
= NtWaitForSingleObject( handle
, alertable
, timeout
);
1051 if (ret
!= STATUS_WAIT_0
) return ret
;
1056 /**************************************************************************
1057 * NtCreateDirectoryObject (NTDLL.@)
1059 NTSTATUS WINAPI
NtCreateDirectoryObject( HANDLE
*handle
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
1063 struct object_attributes
*objattr
;
1066 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
1068 SERVER_START_REQ( create_directory
)
1070 req
->access
= access
;
1071 wine_server_add_data( req
, objattr
, len
);
1072 ret
= wine_server_call( req
);
1073 *handle
= wine_server_ptr_handle( reply
->handle
);
1081 /**************************************************************************
1082 * NtOpenDirectoryObject (NTDLL.@)
1084 NTSTATUS WINAPI
NtOpenDirectoryObject( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
1089 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
1091 SERVER_START_REQ( open_directory
)
1093 req
->access
= access
;
1094 req
->attributes
= attr
->Attributes
;
1095 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
1096 if (attr
->ObjectName
)
1097 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
1098 ret
= wine_server_call( req
);
1099 *handle
= wine_server_ptr_handle( reply
->handle
);
1106 /**************************************************************************
1107 * NtQueryDirectoryObject (NTDLL.@)
1109 NTSTATUS WINAPI
NtQueryDirectoryObject( HANDLE handle
, DIRECTORY_BASIC_INFORMATION
*buffer
,
1110 ULONG size
, BOOLEAN single_entry
, BOOLEAN restart
,
1111 ULONG
*context
, ULONG
*ret_size
)
1113 ULONG index
= restart
? 0 : *context
;
1118 SERVER_START_REQ( get_directory_entry
)
1120 req
->handle
= wine_server_obj_handle( handle
);
1122 if (size
>= 2 * sizeof(*buffer
) + 2 * sizeof(WCHAR
))
1123 wine_server_set_reply( req
, buffer
+ 2, size
- 2 * sizeof(*buffer
) - 2 * sizeof(WCHAR
) );
1124 if (!(ret
= wine_server_call( req
)))
1126 buffer
->ObjectName
.Buffer
= (WCHAR
*)(buffer
+ 2);
1127 buffer
->ObjectName
.Length
= reply
->name_len
;
1128 buffer
->ObjectName
.MaximumLength
= reply
->name_len
+ sizeof(WCHAR
);
1129 buffer
->ObjectTypeName
.Buffer
= (WCHAR
*)(buffer
+ 2) + reply
->name_len
/sizeof(WCHAR
) + 1;
1130 buffer
->ObjectTypeName
.Length
= wine_server_reply_size( reply
) - reply
->name_len
;
1131 buffer
->ObjectTypeName
.MaximumLength
= buffer
->ObjectTypeName
.Length
+ sizeof(WCHAR
);
1132 /* make room for the terminating null */
1133 memmove( buffer
->ObjectTypeName
.Buffer
, buffer
->ObjectTypeName
.Buffer
- 1,
1134 buffer
->ObjectTypeName
.Length
);
1135 buffer
->ObjectName
.Buffer
[buffer
->ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1136 buffer
->ObjectTypeName
.Buffer
[buffer
->ObjectTypeName
.Length
/sizeof(WCHAR
)] = 0;
1138 memset( &buffer
[1], 0, sizeof(buffer
[1]) );
1140 *context
= index
+ 1;
1142 else if (ret
== STATUS_NO_MORE_ENTRIES
)
1144 if (size
> sizeof(*buffer
))
1145 memset( buffer
, 0, sizeof(*buffer
) );
1146 if (ret_size
) *ret_size
= sizeof(*buffer
);
1149 if (ret_size
&& (!ret
|| ret
== STATUS_BUFFER_TOO_SMALL
))
1150 *ret_size
= 2 * sizeof(*buffer
) + reply
->total_len
+ 2 * sizeof(WCHAR
);
1156 FIXME("multiple entries not implemented\n");
1157 ret
= STATUS_NOT_IMPLEMENTED
;
1163 /**************************************************************************
1164 * NtCreateSymbolicLinkObject (NTDLL.@)
1166 NTSTATUS WINAPI
NtCreateSymbolicLinkObject( HANDLE
*handle
, ACCESS_MASK access
,
1167 OBJECT_ATTRIBUTES
*attr
, UNICODE_STRING
*target
)
1171 struct object_attributes
*objattr
;
1174 if (!target
->MaximumLength
) return STATUS_INVALID_PARAMETER
;
1175 if (!target
->Buffer
) return STATUS_ACCESS_VIOLATION
;
1176 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
1178 SERVER_START_REQ( create_symlink
)
1180 req
->access
= access
;
1181 wine_server_add_data( req
, objattr
, len
);
1182 wine_server_add_data( req
, target
->Buffer
, target
->Length
);
1183 ret
= wine_server_call( req
);
1184 *handle
= wine_server_ptr_handle( reply
->handle
);
1192 /**************************************************************************
1193 * NtOpenSymbolicLinkObject (NTDLL.@)
1195 NTSTATUS WINAPI
NtOpenSymbolicLinkObject( HANDLE
*handle
, ACCESS_MASK access
,
1196 const OBJECT_ATTRIBUTES
*attr
)
1201 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
1203 SERVER_START_REQ( open_symlink
)
1205 req
->access
= access
;
1206 req
->attributes
= attr
->Attributes
;
1207 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
1208 if (attr
->ObjectName
)
1209 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
1210 ret
= wine_server_call( req
);
1211 *handle
= wine_server_ptr_handle( reply
->handle
);
1218 /**************************************************************************
1219 * NtQuerySymbolicLinkObject (NTDLL.@)
1221 NTSTATUS WINAPI
NtQuerySymbolicLinkObject( HANDLE handle
, UNICODE_STRING
*target
, ULONG
*length
)
1225 if (!target
) return STATUS_ACCESS_VIOLATION
;
1227 SERVER_START_REQ( query_symlink
)
1229 req
->handle
= wine_server_obj_handle( handle
);
1230 if (target
->MaximumLength
>= sizeof(WCHAR
))
1231 wine_server_set_reply( req
, target
->Buffer
, target
->MaximumLength
- sizeof(WCHAR
) );
1232 if (!(ret
= wine_server_call( req
)))
1234 target
->Length
= wine_server_reply_size(reply
);
1235 target
->Buffer
[target
->Length
/ sizeof(WCHAR
)] = 0;
1236 if (length
) *length
= reply
->total
+ sizeof(WCHAR
);
1238 else if (length
&& ret
== STATUS_BUFFER_TOO_SMALL
) *length
= reply
->total
+ sizeof(WCHAR
);
1245 /**************************************************************************
1246 * NtMakeTemporaryObject (NTDLL.@)
1248 NTSTATUS WINAPI
NtMakeTemporaryObject( HANDLE handle
)
1252 TRACE("%p\n", handle
);
1254 SERVER_START_REQ( make_temporary
)
1256 req
->handle
= wine_server_obj_handle( handle
);
1257 ret
= wine_server_call( req
);
1264 /**************************************************************************
1265 * NtCreateTimer (NTDLL.@)
1267 NTSTATUS WINAPI
NtCreateTimer( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
1272 struct object_attributes
*objattr
;
1275 if (type
!= NotificationTimer
&& type
!= SynchronizationTimer
) return STATUS_INVALID_PARAMETER
;
1276 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
1278 SERVER_START_REQ( create_timer
)
1280 req
->access
= access
;
1281 req
->manual
= (type
== NotificationTimer
);
1282 wine_server_add_data( req
, objattr
, len
);
1283 ret
= wine_server_call( req
);
1284 *handle
= wine_server_ptr_handle( reply
->handle
);
1294 /**************************************************************************
1295 * NtOpenTimer (NTDLL.@)
1297 NTSTATUS WINAPI
NtOpenTimer( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
1302 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
1304 SERVER_START_REQ( open_timer
)
1306 req
->access
= access
;
1307 req
->attributes
= attr
->Attributes
;
1308 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
1309 if (attr
->ObjectName
)
1310 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
1311 ret
= wine_server_call( req
);
1312 *handle
= wine_server_ptr_handle( reply
->handle
);
1319 /**************************************************************************
1320 * NtSetTimer (NTDLL.@)
1322 NTSTATUS WINAPI
NtSetTimer( HANDLE handle
, const LARGE_INTEGER
*when
, PTIMER_APC_ROUTINE callback
,
1323 void *arg
, BOOLEAN resume
, ULONG period
, BOOLEAN
*state
)
1325 NTSTATUS ret
= STATUS_SUCCESS
;
1327 TRACE( "(%p,%p,%p,%p,%08x,0x%08x,%p)\n", handle
, when
, callback
, arg
, resume
, period
, state
);
1329 SERVER_START_REQ( set_timer
)
1331 req
->handle
= wine_server_obj_handle( handle
);
1332 req
->period
= period
;
1333 req
->expire
= when
->QuadPart
;
1334 req
->callback
= wine_server_client_ptr( callback
);
1335 req
->arg
= wine_server_client_ptr( arg
);
1336 ret
= wine_server_call( req
);
1337 if (state
) *state
= reply
->signaled
;
1341 /* set error but can still succeed */
1342 if (resume
&& ret
== STATUS_SUCCESS
) return STATUS_TIMER_RESUME_IGNORED
;
1347 /**************************************************************************
1348 * NtCancelTimer (NTDLL.@)
1350 NTSTATUS WINAPI
NtCancelTimer( HANDLE handle
, BOOLEAN
*state
)
1354 SERVER_START_REQ( cancel_timer
)
1356 req
->handle
= wine_server_obj_handle( handle
);
1357 ret
= wine_server_call( req
);
1358 if (state
) *state
= reply
->signaled
;
1365 /******************************************************************************
1366 * NtQueryTimer (NTDLL.@)
1368 NTSTATUS WINAPI
NtQueryTimer( HANDLE handle
, TIMER_INFORMATION_CLASS
class,
1369 void *info
, ULONG len
, ULONG
*ret_len
)
1371 TIMER_BASIC_INFORMATION
*basic_info
= info
;
1375 TRACE( "(%p,%d,%p,0x%08x,%p)\n", handle
, class, info
, len
, ret_len
);
1379 case TimerBasicInformation
:
1380 if (len
< sizeof(TIMER_BASIC_INFORMATION
)) return STATUS_INFO_LENGTH_MISMATCH
;
1382 SERVER_START_REQ( get_timer_info
)
1384 req
->handle
= wine_server_obj_handle( handle
);
1385 ret
= wine_server_call(req
);
1386 /* convert server time to absolute NTDLL time */
1387 basic_info
->RemainingTime
.QuadPart
= reply
->when
;
1388 basic_info
->TimerState
= reply
->signaled
;
1392 /* convert into relative time */
1393 if (basic_info
->RemainingTime
.QuadPart
> 0) NtQuerySystemTime( &now
);
1396 NtQueryPerformanceCounter( &now
, NULL
);
1397 basic_info
->RemainingTime
.QuadPart
= -basic_info
->RemainingTime
.QuadPart
;
1400 if (now
.QuadPart
> basic_info
->RemainingTime
.QuadPart
)
1401 basic_info
->RemainingTime
.QuadPart
= 0;
1403 basic_info
->RemainingTime
.QuadPart
-= now
.QuadPart
;
1405 if (ret_len
) *ret_len
= sizeof(TIMER_BASIC_INFORMATION
);
1409 FIXME( "Unhandled class %d\n", class );
1410 return STATUS_INVALID_INFO_CLASS
;
1414 /******************************************************************
1415 * NtWaitForMultipleObjects (NTDLL.@)
1417 NTSTATUS WINAPI
NtWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
, BOOLEAN wait_any
,
1418 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1420 select_op_t select_op
;
1421 UINT i
, flags
= SELECT_INTERRUPTIBLE
;
1423 if (!count
|| count
> MAXIMUM_WAIT_OBJECTS
) return STATUS_INVALID_PARAMETER_1
;
1425 if (alertable
) flags
|= SELECT_ALERTABLE
;
1426 select_op
.wait
.op
= wait_any
? SELECT_WAIT
: SELECT_WAIT_ALL
;
1427 for (i
= 0; i
< count
; i
++) select_op
.wait
.handles
[i
] = wine_server_obj_handle( handles
[i
] );
1428 return server_wait( &select_op
, offsetof( select_op_t
, wait
.handles
[count
] ), flags
, timeout
);
1432 /******************************************************************
1433 * NtWaitForSingleObject (NTDLL.@)
1435 NTSTATUS WINAPI
NtWaitForSingleObject( HANDLE handle
, BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1437 return NtWaitForMultipleObjects( 1, &handle
, FALSE
, alertable
, timeout
);
1441 /******************************************************************
1442 * NtSignalAndWaitForSingleObject (NTDLL.@)
1444 NTSTATUS WINAPI
NtSignalAndWaitForSingleObject( HANDLE signal
, HANDLE wait
,
1445 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1447 select_op_t select_op
;
1448 UINT flags
= SELECT_INTERRUPTIBLE
;
1450 if (!signal
) return STATUS_INVALID_HANDLE
;
1452 if (alertable
) flags
|= SELECT_ALERTABLE
;
1453 select_op
.signal_and_wait
.op
= SELECT_SIGNAL_AND_WAIT
;
1454 select_op
.signal_and_wait
.wait
= wine_server_obj_handle( wait
);
1455 select_op
.signal_and_wait
.signal
= wine_server_obj_handle( signal
);
1456 return server_wait( &select_op
, sizeof(select_op
.signal_and_wait
), flags
, timeout
);
1460 /******************************************************************
1461 * NtYieldExecution (NTDLL.@)
1463 NTSTATUS WINAPI
NtYieldExecution(void)
1465 #ifdef HAVE_SCHED_YIELD
1467 return STATUS_SUCCESS
;
1469 return STATUS_NO_YIELD_PERFORMED
;
1474 /******************************************************************
1475 * NtDelayExecution (NTDLL.@)
1477 NTSTATUS WINAPI
NtDelayExecution( BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1479 /* if alertable, we need to query the server */
1480 if (alertable
) return server_wait( NULL
, 0, SELECT_INTERRUPTIBLE
| SELECT_ALERTABLE
, timeout
);
1482 if (!timeout
|| timeout
->QuadPart
== TIMEOUT_INFINITE
) /* sleep forever */
1484 for (;;) select( 0, NULL
, NULL
, NULL
, NULL
);
1489 timeout_t when
, diff
;
1491 if ((when
= timeout
->QuadPart
) < 0)
1493 NtQuerySystemTime( &now
);
1494 when
= now
.QuadPart
- when
;
1497 /* Note that we yield after establishing the desired timeout */
1499 if (!when
) return STATUS_SUCCESS
;
1504 NtQuerySystemTime( &now
);
1505 diff
= (when
- now
.QuadPart
+ 9) / 10;
1506 if (diff
<= 0) break;
1507 tv
.tv_sec
= diff
/ 1000000;
1508 tv
.tv_usec
= diff
% 1000000;
1509 if (select( 0, NULL
, NULL
, NULL
, &tv
) != -1) break;
1512 return STATUS_SUCCESS
;
1516 /******************************************************************************
1517 * NtQueryPerformanceCounter (NTDLL.@)
1519 NTSTATUS WINAPI
NtQueryPerformanceCounter( LARGE_INTEGER
*counter
, LARGE_INTEGER
*frequency
)
1521 counter
->QuadPart
= monotonic_counter();
1522 if (frequency
) frequency
->QuadPart
= TICKSPERSEC
;
1523 return STATUS_SUCCESS
;
1527 /***********************************************************************
1528 * NtQuerySystemTime (NTDLL.@)
1530 NTSTATUS WINAPI
NtQuerySystemTime( LARGE_INTEGER
*time
)
1532 #ifdef HAVE_CLOCK_GETTIME
1534 static clockid_t clock_id
= CLOCK_MONOTONIC
; /* placeholder */
1536 if (clock_id
== CLOCK_MONOTONIC
)
1538 #ifdef CLOCK_REALTIME_COARSE
1539 struct timespec res
;
1541 /* Use CLOCK_REALTIME_COARSE if it has 1 ms or better resolution */
1542 if (!clock_getres( CLOCK_REALTIME_COARSE
, &res
) && res
.tv_sec
== 0 && res
.tv_nsec
<= 1000000)
1543 clock_id
= CLOCK_REALTIME_COARSE
;
1545 #endif /* CLOCK_REALTIME_COARSE */
1546 clock_id
= CLOCK_REALTIME
;
1549 if (!clock_gettime( clock_id
, &ts
))
1551 time
->QuadPart
= ticks_from_time_t( ts
.tv_sec
) + (ts
.tv_nsec
+ 50) / 100;
1554 #endif /* HAVE_CLOCK_GETTIME */
1558 gettimeofday( &now
, 0 );
1559 time
->QuadPart
= ticks_from_time_t( now
.tv_sec
) + now
.tv_usec
* 10;
1561 return STATUS_SUCCESS
;
1565 /***********************************************************************
1566 * NtSetSystemTime (NTDLL.@)
1568 NTSTATUS WINAPI
NtSetSystemTime( const LARGE_INTEGER
*new, LARGE_INTEGER
*old
)
1573 NtQuerySystemTime( &now
);
1574 if (old
) *old
= now
;
1575 diff
= new->QuadPart
- now
.QuadPart
;
1576 if (diff
> -TICKSPERSEC
/ 2 && diff
< TICKSPERSEC
/ 2) return STATUS_SUCCESS
;
1577 ERR( "not allowed: difference %d ms\n", (int)(diff
/ 10000) );
1578 return STATUS_PRIVILEGE_NOT_HELD
;
1582 /***********************************************************************
1583 * NtQueryTimerResolution (NTDLL.@)
1585 NTSTATUS WINAPI
NtQueryTimerResolution( ULONG
*min_res
, ULONG
*max_res
, ULONG
*current_res
)
1587 TRACE( "(%p,%p,%p)\n", min_res
, max_res
, current_res
);
1588 *max_res
= *current_res
= 10000; /* See NtSetTimerResolution() */
1590 return STATUS_SUCCESS
;
1594 /***********************************************************************
1595 * NtSetTimerResolution (NTDLL.@)
1597 NTSTATUS WINAPI
NtSetTimerResolution( ULONG res
, BOOLEAN set
, ULONG
*current_res
)
1599 static BOOL has_request
= FALSE
;
1601 TRACE( "(%u,%u,%p), semi-stub!\n", res
, set
, current_res
);
1603 /* Wine has no support for anything other that 1 ms and does not keep of
1604 * track resolution requests anyway.
1605 * Fortunately NtSetTimerResolution() should ignore requests to lower the
1606 * timer resolution. So by claiming that 'some other process' requested the
1607 * max resolution already, there no need to actually change it.
1609 *current_res
= 10000;
1611 /* Just keep track of whether this process requested a specific timer
1614 if (!has_request
&& !set
)
1615 return STATUS_TIMER_RESOLUTION_NOT_SET
;
1618 return STATUS_SUCCESS
;
1622 /******************************************************************************
1623 * NtSetIntervalProfile (NTDLL.@)
1625 NTSTATUS WINAPI
NtSetIntervalProfile( ULONG interval
, KPROFILE_SOURCE source
)
1627 FIXME( "%u,%d\n", interval
, source
);
1628 return STATUS_SUCCESS
;
1632 /******************************************************************************
1633 * NtGetTickCount (NTDLL.@)
1635 ULONG WINAPI
NtGetTickCount(void)
1637 /* note: we ignore TickCountMultiplier */
1638 return user_shared_data
->u
.TickCount
.LowPart
;
1642 /******************************************************************************
1643 * RtlGetSystemTimePrecise (NTDLL.@)
1645 LONGLONG WINAPI
RtlGetSystemTimePrecise(void)
1648 #ifdef HAVE_CLOCK_GETTIME
1651 if (!clock_gettime( CLOCK_REALTIME
, &ts
))
1652 return ticks_from_time_t( ts
.tv_sec
) + (ts
.tv_nsec
+ 50) / 100;
1654 gettimeofday( &now
, 0 );
1655 return ticks_from_time_t( now
.tv_sec
) + now
.tv_usec
* 10;
1659 /******************************************************************************
1660 * NtCreateKeyedEvent (NTDLL.@)
1662 NTSTATUS WINAPI
NtCreateKeyedEvent( HANDLE
*handle
, ACCESS_MASK access
,
1663 const OBJECT_ATTRIBUTES
*attr
, ULONG flags
)
1667 struct object_attributes
*objattr
;
1670 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
1672 SERVER_START_REQ( create_keyed_event
)
1674 req
->access
= access
;
1675 wine_server_add_data( req
, objattr
, len
);
1676 ret
= wine_server_call( req
);
1677 *handle
= wine_server_ptr_handle( reply
->handle
);
1686 /******************************************************************************
1687 * NtOpenKeyedEvent (NTDLL.@)
1689 NTSTATUS WINAPI
NtOpenKeyedEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
1694 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
1696 SERVER_START_REQ( open_keyed_event
)
1698 req
->access
= access
;
1699 req
->attributes
= attr
->Attributes
;
1700 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
1701 if (attr
->ObjectName
)
1702 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
1703 ret
= wine_server_call( req
);
1704 *handle
= wine_server_ptr_handle( reply
->handle
);
1710 /******************************************************************************
1711 * NtWaitForKeyedEvent (NTDLL.@)
1713 NTSTATUS WINAPI
NtWaitForKeyedEvent( HANDLE handle
, const void *key
,
1714 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1716 select_op_t select_op
;
1717 UINT flags
= SELECT_INTERRUPTIBLE
;
1719 if (!handle
) handle
= keyed_event
;
1720 if ((ULONG_PTR
)key
& 1) return STATUS_INVALID_PARAMETER_1
;
1721 if (alertable
) flags
|= SELECT_ALERTABLE
;
1722 select_op
.keyed_event
.op
= SELECT_KEYED_EVENT_WAIT
;
1723 select_op
.keyed_event
.handle
= wine_server_obj_handle( handle
);
1724 select_op
.keyed_event
.key
= wine_server_client_ptr( key
);
1725 return server_wait( &select_op
, sizeof(select_op
.keyed_event
), flags
, timeout
);
1729 /******************************************************************************
1730 * NtReleaseKeyedEvent (NTDLL.@)
1732 NTSTATUS WINAPI
NtReleaseKeyedEvent( HANDLE handle
, const void *key
,
1733 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1735 select_op_t select_op
;
1736 UINT flags
= SELECT_INTERRUPTIBLE
;
1738 if (!handle
) handle
= keyed_event
;
1739 if ((ULONG_PTR
)key
& 1) return STATUS_INVALID_PARAMETER_1
;
1740 if (alertable
) flags
|= SELECT_ALERTABLE
;
1741 select_op
.keyed_event
.op
= SELECT_KEYED_EVENT_RELEASE
;
1742 select_op
.keyed_event
.handle
= wine_server_obj_handle( handle
);
1743 select_op
.keyed_event
.key
= wine_server_client_ptr( key
);
1744 return server_wait( &select_op
, sizeof(select_op
.keyed_event
), flags
, timeout
);
1748 /***********************************************************************
1749 * NtCreateIoCompletion (NTDLL.@)
1751 NTSTATUS WINAPI
NtCreateIoCompletion( HANDLE
*handle
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
1756 struct object_attributes
*objattr
;
1758 TRACE( "(%p, %x, %p, %d)\n", handle
, access
, attr
, threads
);
1761 if ((status
= alloc_object_attributes( attr
, &objattr
, &len
))) return status
;
1763 SERVER_START_REQ( create_completion
)
1765 req
->access
= access
;
1766 req
->concurrent
= threads
;
1767 wine_server_add_data( req
, objattr
, len
);
1768 if (!(status
= wine_server_call( req
))) *handle
= wine_server_ptr_handle( reply
->handle
);
1777 /***********************************************************************
1778 * NtOpenIoCompletion (NTDLL.@)
1780 NTSTATUS WINAPI
NtOpenIoCompletion( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
1785 if ((status
= validate_open_object_attributes( attr
))) return status
;
1787 SERVER_START_REQ( open_completion
)
1789 req
->access
= access
;
1790 req
->attributes
= attr
->Attributes
;
1791 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
1792 if (attr
->ObjectName
)
1793 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
1794 status
= wine_server_call( req
);
1795 *handle
= wine_server_ptr_handle( reply
->handle
);
1802 /***********************************************************************
1803 * NtSetIoCompletion (NTDLL.@)
1805 NTSTATUS WINAPI
NtSetIoCompletion( HANDLE handle
, ULONG_PTR key
, ULONG_PTR value
,
1806 NTSTATUS status
, SIZE_T count
)
1810 TRACE( "(%p, %lx, %lx, %x, %lx)\n", handle
, key
, value
, status
, count
);
1812 SERVER_START_REQ( add_completion
)
1814 req
->handle
= wine_server_obj_handle( handle
);
1816 req
->cvalue
= value
;
1817 req
->status
= status
;
1818 req
->information
= count
;
1819 ret
= wine_server_call( req
);
1826 /***********************************************************************
1827 * NtRemoveIoCompletion (NTDLL.@)
1829 NTSTATUS WINAPI
NtRemoveIoCompletion( HANDLE handle
, ULONG_PTR
*key
, ULONG_PTR
*value
,
1830 IO_STATUS_BLOCK
*io
, LARGE_INTEGER
*timeout
)
1834 TRACE( "(%p, %p, %p, %p, %p)\n", handle
, key
, value
, io
, timeout
);
1838 SERVER_START_REQ( remove_completion
)
1840 req
->handle
= wine_server_obj_handle( handle
);
1841 if (!(status
= wine_server_call( req
)))
1844 *value
= reply
->cvalue
;
1845 io
->Information
= reply
->information
;
1846 io
->u
.Status
= reply
->status
;
1850 if (status
!= STATUS_PENDING
) return status
;
1851 status
= NtWaitForSingleObject( handle
, FALSE
, timeout
);
1852 if (status
!= WAIT_OBJECT_0
) return status
;
1857 /***********************************************************************
1858 * NtRemoveIoCompletionEx (NTDLL.@)
1860 NTSTATUS WINAPI
NtRemoveIoCompletionEx( HANDLE handle
, FILE_IO_COMPLETION_INFORMATION
*info
, ULONG count
,
1861 ULONG
*written
, LARGE_INTEGER
*timeout
, BOOLEAN alertable
)
1866 TRACE( "%p %p %u %p %p %u\n", handle
, info
, count
, written
, timeout
, alertable
);
1872 SERVER_START_REQ( remove_completion
)
1874 req
->handle
= wine_server_obj_handle( handle
);
1875 if (!(status
= wine_server_call( req
)))
1877 info
[i
].CompletionKey
= reply
->ckey
;
1878 info
[i
].CompletionValue
= reply
->cvalue
;
1879 info
[i
].IoStatusBlock
.Information
= reply
->information
;
1880 info
[i
].IoStatusBlock
.u
.Status
= reply
->status
;
1884 if (status
!= STATUS_SUCCESS
) break;
1887 if (i
|| status
!= STATUS_PENDING
)
1889 if (status
== STATUS_PENDING
) status
= STATUS_SUCCESS
;
1892 status
= NtWaitForSingleObject( handle
, alertable
, timeout
);
1893 if (status
!= WAIT_OBJECT_0
) break;
1895 *written
= i
? i
: 1;
1900 /***********************************************************************
1901 * NtQueryIoCompletion (NTDLL.@)
1903 NTSTATUS WINAPI
NtQueryIoCompletion( HANDLE handle
, IO_COMPLETION_INFORMATION_CLASS
class,
1904 void *buffer
, ULONG len
, ULONG
*ret_len
)
1908 TRACE( "(%p, %d, %p, 0x%x, %p)\n", handle
, class, buffer
, len
, ret_len
);
1910 if (!buffer
) return STATUS_INVALID_PARAMETER
;
1914 case IoCompletionBasicInformation
:
1916 ULONG
*info
= buffer
;
1917 if (ret_len
) *ret_len
= sizeof(*info
);
1918 if (len
== sizeof(*info
))
1920 SERVER_START_REQ( query_completion
)
1922 req
->handle
= wine_server_obj_handle( handle
);
1923 if (!(status
= wine_server_call( req
))) *info
= reply
->depth
;
1927 else status
= STATUS_INFO_LENGTH_MISMATCH
;
1931 return STATUS_INVALID_PARAMETER
;
1937 /***********************************************************************
1938 * NtCreateSection (NTDLL.@)
1940 NTSTATUS WINAPI
NtCreateSection( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
1941 const LARGE_INTEGER
*size
, ULONG protect
,
1942 ULONG sec_flags
, HANDLE file
)
1945 unsigned int file_access
;
1947 struct object_attributes
*objattr
;
1951 switch (protect
& 0xff)
1954 case PAGE_EXECUTE_READ
:
1955 case PAGE_WRITECOPY
:
1956 case PAGE_EXECUTE_WRITECOPY
:
1957 file_access
= FILE_READ_DATA
;
1959 case PAGE_READWRITE
:
1960 case PAGE_EXECUTE_READWRITE
:
1961 if (sec_flags
& SEC_IMAGE
) file_access
= FILE_READ_DATA
;
1962 else file_access
= FILE_READ_DATA
| FILE_WRITE_DATA
;
1969 return STATUS_INVALID_PAGE_PROTECTION
;
1972 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
1974 SERVER_START_REQ( create_mapping
)
1976 req
->access
= access
;
1977 req
->flags
= sec_flags
;
1978 req
->file_handle
= wine_server_obj_handle( file
);
1979 req
->file_access
= file_access
;
1980 req
->size
= size
? size
->QuadPart
: 0;
1981 wine_server_add_data( req
, objattr
, len
);
1982 ret
= wine_server_call( req
);
1983 *handle
= wine_server_ptr_handle( reply
->handle
);
1992 /***********************************************************************
1993 * NtOpenSection (NTDLL.@)
1995 NTSTATUS WINAPI
NtOpenSection( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
2000 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
2002 SERVER_START_REQ( open_mapping
)
2004 req
->access
= access
;
2005 req
->attributes
= attr
->Attributes
;
2006 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
2007 if (attr
->ObjectName
)
2008 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
2009 ret
= wine_server_call( req
);
2010 *handle
= wine_server_ptr_handle( reply
->handle
);
2017 /***********************************************************************
2018 * NtCreatePort (NTDLL.@)
2020 NTSTATUS WINAPI
NtCreatePort( HANDLE
*handle
, OBJECT_ATTRIBUTES
*attr
, ULONG info_len
,
2021 ULONG data_len
, ULONG
*reserved
)
2023 FIXME( "(%p,%p,%u,%u,%p),stub!\n", handle
, attr
, info_len
, data_len
, reserved
);
2024 return STATUS_NOT_IMPLEMENTED
;
2028 /***********************************************************************
2029 * NtConnectPort (NTDLL.@)
2031 NTSTATUS WINAPI
NtConnectPort( HANDLE
*handle
, UNICODE_STRING
*name
, SECURITY_QUALITY_OF_SERVICE
*qos
,
2032 LPC_SECTION_WRITE
*write
, LPC_SECTION_READ
*read
, ULONG
*max_len
,
2033 void *info
, ULONG
*info_len
)
2035 FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p),stub!\n", handle
, debugstr_us(name
), qos
,
2036 write
, read
, max_len
, info
, info_len
);
2037 if (info
&& info_len
) TRACE("msg = %s\n", debugstr_an( info
, *info_len
));
2038 return STATUS_NOT_IMPLEMENTED
;
2042 /***********************************************************************
2043 * NtSecureConnectPort (NTDLL.@)
2045 NTSTATUS WINAPI
NtSecureConnectPort( HANDLE
*handle
, UNICODE_STRING
*name
, SECURITY_QUALITY_OF_SERVICE
*qos
,
2046 LPC_SECTION_WRITE
*write
, PSID sid
, LPC_SECTION_READ
*read
,
2047 ULONG
*max_len
, void *info
, ULONG
*info_len
)
2049 FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p,%p),stub!\n", handle
, debugstr_us(name
), qos
,
2050 write
, sid
, read
, max_len
, info
, info_len
);
2051 return STATUS_NOT_IMPLEMENTED
;
2055 /***********************************************************************
2056 * NtListenPort (NTDLL.@)
2058 NTSTATUS WINAPI
NtListenPort( HANDLE handle
, LPC_MESSAGE
*msg
)
2060 FIXME("(%p,%p),stub!\n", handle
, msg
);
2061 return STATUS_NOT_IMPLEMENTED
;
2065 /***********************************************************************
2066 * NtAcceptConnectPort (NTDLL.@)
2068 NTSTATUS WINAPI
NtAcceptConnectPort( HANDLE
*handle
, ULONG id
, LPC_MESSAGE
*msg
, BOOLEAN accept
,
2069 LPC_SECTION_WRITE
*write
, LPC_SECTION_READ
*read
)
2071 FIXME("(%p,%u,%p,%d,%p,%p),stub!\n", handle
, id
, msg
, accept
, write
, read
);
2072 return STATUS_NOT_IMPLEMENTED
;
2076 /***********************************************************************
2077 * NtCompleteConnectPort (NTDLL.@)
2079 NTSTATUS WINAPI
NtCompleteConnectPort( HANDLE handle
)
2081 FIXME( "(%p),stub!\n", handle
);
2082 return STATUS_NOT_IMPLEMENTED
;
2086 /***********************************************************************
2087 * NtRegisterThreadTerminatePort (NTDLL.@)
2089 NTSTATUS WINAPI
NtRegisterThreadTerminatePort( HANDLE handle
)
2091 FIXME( "(%p),stub!\n", handle
);
2092 return STATUS_NOT_IMPLEMENTED
;
2096 /***********************************************************************
2097 * NtRequestWaitReplyPort (NTDLL.@)
2099 NTSTATUS WINAPI
NtRequestWaitReplyPort( HANDLE handle
, LPC_MESSAGE
*msg_in
, LPC_MESSAGE
*msg_out
)
2101 FIXME( "(%p,%p,%p),stub!\n", handle
, msg_in
, msg_out
);
2103 TRACE("datasize %u msgsize %u type %u ranges %u client %p/%p msgid %lu size %lu data %s\n",
2104 msg_in
->DataSize
, msg_in
->MessageSize
, msg_in
->MessageType
, msg_in
->VirtualRangesOffset
,
2105 msg_in
->ClientId
.UniqueProcess
, msg_in
->ClientId
.UniqueThread
, msg_in
->MessageId
,
2106 msg_in
->SectionSize
, debugstr_an( (const char *)msg_in
->Data
, msg_in
->DataSize
));
2107 return STATUS_NOT_IMPLEMENTED
;
2111 /***********************************************************************
2112 * NtReplyWaitReceivePort (NTDLL.@)
2114 NTSTATUS WINAPI
NtReplyWaitReceivePort( HANDLE handle
, ULONG
*id
, LPC_MESSAGE
*reply
, LPC_MESSAGE
*msg
)
2116 FIXME("(%p,%p,%p,%p),stub!\n", handle
, id
, reply
, msg
);
2117 return STATUS_NOT_IMPLEMENTED
;
2121 #define MAX_ATOM_LEN 255
2122 #define IS_INTATOM(x) (((ULONG_PTR)(x) >> 16) == 0)
2124 static NTSTATUS
is_integral_atom( const WCHAR
*atomstr
, ULONG len
, RTL_ATOM
*ret_atom
)
2128 if ((ULONG_PTR
)atomstr
>> 16)
2130 const WCHAR
* ptr
= atomstr
;
2131 if (!len
) return STATUS_OBJECT_NAME_INVALID
;
2136 while (ptr
< atomstr
+ len
&& *ptr
>= '0' && *ptr
<= '9')
2138 atom
= atom
* 10 + *ptr
++ - '0';
2140 if (ptr
> atomstr
+ 1 && ptr
== atomstr
+ len
) goto done
;
2142 if (len
> MAX_ATOM_LEN
) return STATUS_INVALID_PARAMETER
;
2143 return STATUS_MORE_ENTRIES
;
2145 else atom
= LOWORD( atomstr
);
2147 if (!atom
|| atom
>= MAXINTATOM
) return STATUS_INVALID_PARAMETER
;
2149 return STATUS_SUCCESS
;
2152 static ULONG
integral_atom_name( WCHAR
*buffer
, ULONG len
, RTL_ATOM atom
)
2155 int ret
= sprintf( tmp
, "#%u", atom
);
2157 len
/= sizeof(WCHAR
);
2160 if (len
<= ret
) ret
= len
- 1;
2161 ascii_to_unicode( buffer
, tmp
, ret
);
2164 return ret
* sizeof(WCHAR
);
2168 /***********************************************************************
2169 * NtAddAtom (NTDLL.@)
2171 NTSTATUS WINAPI
NtAddAtom( const WCHAR
*name
, ULONG length
, RTL_ATOM
*atom
)
2173 NTSTATUS status
= is_integral_atom( name
, length
/ sizeof(WCHAR
), atom
);
2175 if (status
== STATUS_MORE_ENTRIES
)
2177 SERVER_START_REQ( add_atom
)
2179 wine_server_add_data( req
, name
, length
);
2180 status
= wine_server_call( req
);
2181 *atom
= reply
->atom
;
2185 TRACE( "%s -> %x\n", debugstr_wn(name
, length
/sizeof(WCHAR
)), status
== STATUS_SUCCESS
? *atom
: 0 );
2190 /***********************************************************************
2191 * NtDeleteAtom (NTDLL.@)
2193 NTSTATUS WINAPI
NtDeleteAtom( RTL_ATOM atom
)
2197 SERVER_START_REQ( delete_atom
)
2200 status
= wine_server_call( req
);
2207 /***********************************************************************
2208 * NtFindAtom (NTDLL.@)
2210 NTSTATUS WINAPI
NtFindAtom( const WCHAR
*name
, ULONG length
, RTL_ATOM
*atom
)
2212 NTSTATUS status
= is_integral_atom( name
, length
/ sizeof(WCHAR
), atom
);
2214 if (status
== STATUS_MORE_ENTRIES
)
2216 SERVER_START_REQ( find_atom
)
2218 wine_server_add_data( req
, name
, length
);
2219 status
= wine_server_call( req
);
2220 *atom
= reply
->atom
;
2224 TRACE( "%s -> %x\n", debugstr_wn(name
, length
/sizeof(WCHAR
)), status
== STATUS_SUCCESS
? *atom
: 0 );
2229 /***********************************************************************
2230 * NtQueryInformationAtom (NTDLL.@)
2232 NTSTATUS WINAPI
NtQueryInformationAtom( RTL_ATOM atom
, ATOM_INFORMATION_CLASS
class,
2233 void *ptr
, ULONG size
, ULONG
*retsize
)
2239 case AtomBasicInformation
:
2242 ATOM_BASIC_INFORMATION
*abi
= ptr
;
2244 if (size
< sizeof(ATOM_BASIC_INFORMATION
)) return STATUS_INVALID_PARAMETER
;
2245 name_len
= size
- sizeof(ATOM_BASIC_INFORMATION
);
2247 if (atom
< MAXINTATOM
)
2251 abi
->NameLength
= integral_atom_name( abi
->Name
, name_len
, atom
);
2252 status
= name_len
? STATUS_SUCCESS
: STATUS_BUFFER_TOO_SMALL
;
2253 abi
->ReferenceCount
= 1;
2256 else status
= STATUS_INVALID_PARAMETER
;
2260 SERVER_START_REQ( get_atom_information
)
2263 if (name_len
) wine_server_set_reply( req
, abi
->Name
, name_len
);
2264 status
= wine_server_call( req
);
2265 if (status
== STATUS_SUCCESS
)
2267 name_len
= wine_server_reply_size( reply
);
2270 abi
->NameLength
= name_len
;
2271 abi
->Name
[name_len
/ sizeof(WCHAR
)] = 0;
2275 name_len
= reply
->total
;
2276 abi
->NameLength
= name_len
;
2277 status
= STATUS_BUFFER_TOO_SMALL
;
2279 abi
->ReferenceCount
= reply
->count
;
2280 abi
->Pinned
= reply
->pinned
;
2286 TRACE( "%x -> %s (%u)\n", atom
, debugstr_wn(abi
->Name
, abi
->NameLength
/ sizeof(WCHAR
)), status
);
2287 if (retsize
) *retsize
= sizeof(ATOM_BASIC_INFORMATION
) + name_len
;
2292 FIXME( "Unsupported class %u\n", class );
2293 status
= STATUS_INVALID_INFO_CLASS
;
2300 union tid_alert_entry
2312 #define TID_ALERT_BLOCK_SIZE (65536 / sizeof(union tid_alert_entry))
2313 static union tid_alert_entry
*tid_alert_blocks
[4096];
2315 static unsigned int handle_to_index( HANDLE handle
, unsigned int *block_idx
)
2317 unsigned int idx
= (wine_server_obj_handle(handle
) >> 2) - 1;
2318 *block_idx
= idx
/ TID_ALERT_BLOCK_SIZE
;
2319 return idx
% TID_ALERT_BLOCK_SIZE
;
2322 static union tid_alert_entry
*get_tid_alert_entry( HANDLE tid
)
2324 unsigned int block_idx
, idx
= handle_to_index( tid
, &block_idx
);
2325 union tid_alert_entry
*entry
;
2327 if (block_idx
> ARRAY_SIZE(tid_alert_blocks
))
2329 FIXME( "tid %p is too high\n", tid
);
2333 if (!tid_alert_blocks
[block_idx
])
2335 static const size_t size
= TID_ALERT_BLOCK_SIZE
* sizeof(union tid_alert_entry
);
2336 void *ptr
= anon_mmap_alloc( size
, PROT_READ
| PROT_WRITE
);
2337 if (ptr
== MAP_FAILED
) return NULL
;
2338 if (InterlockedCompareExchangePointer( (void **)&tid_alert_blocks
[block_idx
], ptr
, NULL
))
2339 munmap( ptr
, size
); /* someone beat us to it */
2342 entry
= &tid_alert_blocks
[block_idx
][idx
% TID_ALERT_BLOCK_SIZE
];
2349 if (semaphore_create( mach_task_self(), &sem
, SYNC_POLICY_FIFO
, 0 ))
2351 if (InterlockedCompareExchange( (int *)&entry
->sem
, sem
, 0 ))
2352 semaphore_destroy( mach_task_self(), sem
);
2364 if (NtCreateEvent( &event
, EVENT_ALL_ACCESS
, NULL
, SynchronizationEvent
, FALSE
))
2366 if (InterlockedCompareExchangePointer( &entry
->event
, event
, NULL
))
2375 /***********************************************************************
2376 * NtAlertThreadByThreadId (NTDLL.@)
2378 NTSTATUS WINAPI
NtAlertThreadByThreadId( HANDLE tid
)
2380 union tid_alert_entry
*entry
= get_tid_alert_entry( tid
);
2382 TRACE( "%p\n", tid
);
2384 if (!entry
) return STATUS_INVALID_CID
;
2387 semaphore_signal( entry
->sem
);
2388 return STATUS_SUCCESS
;
2393 int *futex
= &entry
->futex
;
2394 if (!InterlockedExchange( futex
, 1 ))
2395 futex_wake( futex
, 1 );
2396 return STATUS_SUCCESS
;
2400 return NtSetEvent( entry
->event
, NULL
);
2405 #if defined(__linux__) || defined(__APPLE__)
2406 static LONGLONG
get_absolute_timeout( const LARGE_INTEGER
*timeout
)
2410 if (timeout
->QuadPart
>= 0) return timeout
->QuadPart
;
2411 NtQuerySystemTime( &now
);
2412 return now
.QuadPart
- timeout
->QuadPart
;
2415 static LONGLONG
update_timeout( ULONGLONG end
)
2420 NtQuerySystemTime( &now
);
2421 timeleft
= end
- now
.QuadPart
;
2422 if (timeleft
< 0) timeleft
= 0;
2430 /***********************************************************************
2431 * NtWaitForAlertByThreadId (NTDLL.@)
2433 NTSTATUS WINAPI
NtWaitForAlertByThreadId( const void *address
, const LARGE_INTEGER
*timeout
)
2435 union tid_alert_entry
*entry
= get_tid_alert_entry( NtCurrentTeb()->ClientId
.UniqueThread
);
2440 TRACE( "%p %s\n", address
, debugstr_timeout( timeout
) );
2442 if (!entry
) return STATUS_INVALID_CID
;
2447 if (timeout
->QuadPart
== TIMEOUT_INFINITE
)
2450 end
= get_absolute_timeout( timeout
);
2457 LONGLONG timeleft
= update_timeout( end
);
2458 mach_timespec_t timespec
;
2460 timespec
.tv_sec
= timeleft
/ (ULONGLONG
)TICKSPERSEC
;
2461 timespec
.tv_nsec
= (timeleft
% TICKSPERSEC
) * 100;
2462 ret
= semaphore_timedwait( sem
, timespec
);
2465 ret
= semaphore_wait( sem
);
2469 case KERN_SUCCESS
: return STATUS_ALERTED
;
2470 case KERN_ABORTED
: continue;
2471 case KERN_OPERATION_TIMED_OUT
: return STATUS_TIMEOUT
;
2472 default: return STATUS_INVALID_HANDLE
;
2479 /***********************************************************************
2480 * NtWaitForAlertByThreadId (NTDLL.@)
2482 NTSTATUS WINAPI
NtWaitForAlertByThreadId( const void *address
, const LARGE_INTEGER
*timeout
)
2484 union tid_alert_entry
*entry
= get_tid_alert_entry( NtCurrentTeb()->ClientId
.UniqueThread
);
2487 TRACE( "%p %s\n", address
, debugstr_timeout( timeout
) );
2489 if (!entry
) return STATUS_INVALID_CID
;
2494 int *futex
= &entry
->futex
;
2500 if (timeout
->QuadPart
== TIMEOUT_INFINITE
)
2503 end
= get_absolute_timeout( timeout
);
2506 while (!InterlockedExchange( futex
, 0 ))
2510 LONGLONG timeleft
= update_timeout( end
);
2511 struct timespec timespec
;
2513 timespec
.tv_sec
= timeleft
/ (ULONGLONG
)TICKSPERSEC
;
2514 timespec
.tv_nsec
= (timeleft
% TICKSPERSEC
) * 100;
2515 ret
= futex_wait( futex
, 0, ×pec
);
2518 ret
= futex_wait( futex
, 0, NULL
);
2520 if (ret
== -1 && errno
== ETIMEDOUT
) return STATUS_TIMEOUT
;
2522 return STATUS_ALERTED
;
2526 status
= NtWaitForSingleObject( entry
->event
, FALSE
, timeout
);
2527 if (!status
) return STATUS_ALERTED
;
2533 /* Notify direct completion of async and close the wait handle if it is no longer needed.
2534 * This function is a no-op (returns status as-is) if the supplied handle is NULL.
2536 void set_async_direct_result( HANDLE
*optional_handle
, NTSTATUS status
, ULONG_PTR information
, BOOL mark_pending
)
2540 if (!*optional_handle
) return;
2542 SERVER_START_REQ( set_async_direct_result
)
2544 req
->handle
= wine_server_obj_handle( *optional_handle
);
2545 req
->status
= status
;
2546 req
->information
= information
;
2547 req
->mark_pending
= mark_pending
;
2548 ret
= wine_server_call( req
);
2549 if (ret
== STATUS_SUCCESS
)
2550 *optional_handle
= wine_server_ptr_handle( reply
->handle
);
2554 if (ret
!= STATUS_SUCCESS
)
2555 ERR( "cannot report I/O result back to server: %08x\n", ret
);