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
29 #include "wine/port.h"
35 #ifdef HAVE_SYS_SYSCALL_H
36 #include <sys/syscall.h>
38 #ifdef HAVE_SYS_TIME_H
39 # include <sys/time.h>
44 #ifdef HAVE_SYS_POLL_H
45 # include <sys/poll.h>
59 # include <mach/mach.h>
60 # include <mach/task.h>
61 # include <mach/semaphore.h>
62 # include <mach/mach_time.h>
66 #define WIN32_NO_STATUS
67 #define NONAMELESSUNION
71 #include "wine/server.h"
72 #include "wine/exception.h"
73 #include "wine/debug.h"
74 #include "unix_private.h"
76 WINE_DEFAULT_DEBUG_CHANNEL(sync
);
78 HANDLE keyed_event
= 0;
80 static const LARGE_INTEGER zero_timeout
;
82 static pthread_mutex_t addr_mutex
= PTHREAD_MUTEX_INITIALIZER
;
84 /* return a monotonic time counter, in Win32 ticks */
85 static inline ULONGLONG
monotonic_counter(void)
89 static mach_timebase_info_data_t timebase
;
91 if (!timebase
.denom
) mach_timebase_info( &timebase
);
92 #ifdef HAVE_MACH_CONTINUOUS_TIME
93 if (&mach_continuous_time
!= NULL
)
94 return mach_continuous_time() * timebase
.numer
/ timebase
.denom
/ 100;
96 return mach_absolute_time() * timebase
.numer
/ timebase
.denom
/ 100;
97 #elif defined(HAVE_CLOCK_GETTIME)
99 #ifdef CLOCK_MONOTONIC_RAW
100 if (!clock_gettime( CLOCK_MONOTONIC_RAW
, &ts
))
101 return ts
.tv_sec
* (ULONGLONG
)TICKSPERSEC
+ ts
.tv_nsec
/ 100;
103 if (!clock_gettime( CLOCK_MONOTONIC
, &ts
))
104 return ts
.tv_sec
* (ULONGLONG
)TICKSPERSEC
+ ts
.tv_nsec
/ 100;
106 gettimeofday( &now
, 0 );
107 return ticks_from_time_t( now
.tv_sec
) + now
.tv_usec
* 10 - server_start_time
;
115 #define FUTEX_WAIT_BITSET 9
116 #define FUTEX_WAKE_BITSET 10
118 static int futex_private
= 128;
120 static inline int futex_wait( const int *addr
, int val
, struct timespec
*timeout
)
122 return syscall( __NR_futex
, addr
, FUTEX_WAIT
| futex_private
, val
, timeout
, 0, 0 );
125 static inline int futex_wake( const int *addr
, int val
)
127 return syscall( __NR_futex
, addr
, FUTEX_WAKE
| futex_private
, val
, NULL
, 0, 0 );
130 static inline int futex_wait_bitset( const int *addr
, int val
, struct timespec
*timeout
, int mask
)
132 return syscall( __NR_futex
, addr
, FUTEX_WAIT_BITSET
| futex_private
, val
, timeout
, 0, mask
);
135 static inline int futex_wake_bitset( const int *addr
, int val
, int mask
)
137 return syscall( __NR_futex
, addr
, FUTEX_WAKE_BITSET
| futex_private
, val
, NULL
, 0, mask
);
140 static inline int use_futexes(void)
142 static int supported
= -1;
146 futex_wait( &supported
, 10, NULL
);
150 futex_wait( &supported
, 10, NULL
);
152 supported
= (errno
!= ENOSYS
);
157 static int *get_futex(void **ptr
)
159 if (sizeof(void *) == 8)
160 return (int *)((((ULONG_PTR
)ptr
) + 3) & ~3);
161 else if (!(((ULONG_PTR
)ptr
) & 3))
167 static void timespec_from_timeout( struct timespec
*timespec
, const LARGE_INTEGER
*timeout
)
172 if (timeout
->QuadPart
> 0)
174 NtQuerySystemTime( &now
);
175 diff
= timeout
->QuadPart
- now
.QuadPart
;
178 diff
= -timeout
->QuadPart
;
180 timespec
->tv_sec
= diff
/ TICKSPERSEC
;
181 timespec
->tv_nsec
= (diff
% TICKSPERSEC
) * 100;
187 static BOOL
compare_addr( const void *addr
, const void *cmp
, SIZE_T size
)
192 return (*(const UCHAR
*)addr
== *(const UCHAR
*)cmp
);
194 return (*(const USHORT
*)addr
== *(const USHORT
*)cmp
);
196 return (*(const ULONG
*)addr
== *(const ULONG
*)cmp
);
198 return (*(const ULONG64
*)addr
== *(const ULONG64
*)cmp
);
205 /* create a struct security_descriptor and contained information in one contiguous piece of memory */
206 NTSTATUS
alloc_object_attributes( const OBJECT_ATTRIBUTES
*attr
, struct object_attributes
**ret
,
207 data_size_t
*ret_len
)
209 unsigned int len
= sizeof(**ret
);
210 SID
*owner
= NULL
, *group
= NULL
;
211 ACL
*dacl
= NULL
, *sacl
= NULL
;
212 SECURITY_DESCRIPTOR
*sd
;
217 if (!attr
) return STATUS_SUCCESS
;
219 if (attr
->Length
!= sizeof(*attr
)) return STATUS_INVALID_PARAMETER
;
221 if ((sd
= attr
->SecurityDescriptor
))
223 len
+= sizeof(struct security_descriptor
);
224 if (sd
->Revision
!= SECURITY_DESCRIPTOR_REVISION
) return STATUS_UNKNOWN_REVISION
;
225 if (sd
->Control
& SE_SELF_RELATIVE
)
227 SECURITY_DESCRIPTOR_RELATIVE
*rel
= (SECURITY_DESCRIPTOR_RELATIVE
*)sd
;
228 if (rel
->Owner
) owner
= (PSID
)((BYTE
*)rel
+ rel
->Owner
);
229 if (rel
->Group
) group
= (PSID
)((BYTE
*)rel
+ rel
->Group
);
230 if ((sd
->Control
& SE_SACL_PRESENT
) && rel
->Sacl
) sacl
= (PSID
)((BYTE
*)rel
+ rel
->Sacl
);
231 if ((sd
->Control
& SE_DACL_PRESENT
) && rel
->Dacl
) dacl
= (PSID
)((BYTE
*)rel
+ rel
->Dacl
);
237 if (sd
->Control
& SE_SACL_PRESENT
) sacl
= sd
->Sacl
;
238 if (sd
->Control
& SE_DACL_PRESENT
) dacl
= sd
->Dacl
;
241 if (owner
) len
+= offsetof( SID
, SubAuthority
[owner
->SubAuthorityCount
] );
242 if (group
) len
+= offsetof( SID
, SubAuthority
[group
->SubAuthorityCount
] );
243 if (sacl
) len
+= sacl
->AclSize
;
244 if (dacl
) len
+= dacl
->AclSize
;
246 /* fix alignment for the Unicode name that follows the structure */
247 len
= (len
+ sizeof(WCHAR
) - 1) & ~(sizeof(WCHAR
) - 1);
250 if (attr
->ObjectName
)
252 if ((ULONG_PTR
)attr
->ObjectName
->Buffer
& (sizeof(WCHAR
) - 1)) return STATUS_DATATYPE_MISALIGNMENT
;
253 if (attr
->ObjectName
->Length
& (sizeof(WCHAR
) - 1)) return STATUS_OBJECT_NAME_INVALID
;
254 len
+= attr
->ObjectName
->Length
;
256 else if (attr
->RootDirectory
) return STATUS_OBJECT_NAME_INVALID
;
258 len
= (len
+ 3) & ~3; /* DWORD-align the entire structure */
260 if (!(*ret
= calloc( len
, 1 ))) return STATUS_NO_MEMORY
;
262 (*ret
)->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
263 (*ret
)->attributes
= attr
->Attributes
;
265 if (attr
->SecurityDescriptor
)
267 struct security_descriptor
*descr
= (struct security_descriptor
*)(*ret
+ 1);
268 unsigned char *ptr
= (unsigned char *)(descr
+ 1);
270 descr
->control
= sd
->Control
& ~SE_SELF_RELATIVE
;
271 if (owner
) descr
->owner_len
= offsetof( SID
, SubAuthority
[owner
->SubAuthorityCount
] );
272 if (group
) descr
->group_len
= offsetof( SID
, SubAuthority
[group
->SubAuthorityCount
] );
273 if (sacl
) descr
->sacl_len
= sacl
->AclSize
;
274 if (dacl
) descr
->dacl_len
= dacl
->AclSize
;
276 memcpy( ptr
, owner
, descr
->owner_len
);
277 ptr
+= descr
->owner_len
;
278 memcpy( ptr
, group
, descr
->group_len
);
279 ptr
+= descr
->group_len
;
280 memcpy( ptr
, sacl
, descr
->sacl_len
);
281 ptr
+= descr
->sacl_len
;
282 memcpy( ptr
, dacl
, descr
->dacl_len
);
283 (*ret
)->sd_len
= (sizeof(*descr
) + descr
->owner_len
+ descr
->group_len
+ descr
->sacl_len
+
284 descr
->dacl_len
+ sizeof(WCHAR
) - 1) & ~(sizeof(WCHAR
) - 1);
287 if (attr
->ObjectName
)
289 unsigned char *ptr
= (unsigned char *)(*ret
+ 1) + (*ret
)->sd_len
;
290 (*ret
)->name_len
= attr
->ObjectName
->Length
;
291 memcpy( ptr
, attr
->ObjectName
->Buffer
, (*ret
)->name_len
);
295 return STATUS_SUCCESS
;
299 static NTSTATUS
validate_open_object_attributes( const OBJECT_ATTRIBUTES
*attr
)
301 if (!attr
|| attr
->Length
!= sizeof(*attr
)) return STATUS_INVALID_PARAMETER
;
303 if (attr
->ObjectName
)
305 if ((ULONG_PTR
)attr
->ObjectName
->Buffer
& (sizeof(WCHAR
) - 1)) return STATUS_DATATYPE_MISALIGNMENT
;
306 if (attr
->ObjectName
->Length
& (sizeof(WCHAR
) - 1)) return STATUS_OBJECT_NAME_INVALID
;
308 else if (attr
->RootDirectory
) return STATUS_OBJECT_NAME_INVALID
;
310 return STATUS_SUCCESS
;
314 /******************************************************************************
315 * NtCreateSemaphore (NTDLL.@)
317 NTSTATUS WINAPI
NtCreateSemaphore( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
318 LONG initial
, LONG max
)
322 struct object_attributes
*objattr
;
325 if (max
<= 0 || initial
< 0 || initial
> max
) return STATUS_INVALID_PARAMETER
;
326 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
328 SERVER_START_REQ( create_semaphore
)
330 req
->access
= access
;
331 req
->initial
= initial
;
333 wine_server_add_data( req
, objattr
, len
);
334 ret
= wine_server_call( req
);
335 *handle
= wine_server_ptr_handle( reply
->handle
);
344 /******************************************************************************
345 * NtOpenSemaphore (NTDLL.@)
347 NTSTATUS WINAPI
NtOpenSemaphore( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
352 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
354 SERVER_START_REQ( open_semaphore
)
356 req
->access
= access
;
357 req
->attributes
= attr
->Attributes
;
358 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
359 if (attr
->ObjectName
)
360 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
361 ret
= wine_server_call( req
);
362 *handle
= wine_server_ptr_handle( reply
->handle
);
369 /******************************************************************************
370 * NtQuerySemaphore (NTDLL.@)
372 NTSTATUS WINAPI
NtQuerySemaphore( HANDLE handle
, SEMAPHORE_INFORMATION_CLASS
class,
373 void *info
, ULONG len
, ULONG
*ret_len
)
376 SEMAPHORE_BASIC_INFORMATION
*out
= info
;
378 TRACE("(%p, %u, %p, %u, %p)\n", handle
, class, info
, len
, ret_len
);
380 if (class != SemaphoreBasicInformation
)
382 FIXME("(%p,%d,%u) Unknown class\n", handle
, class, len
);
383 return STATUS_INVALID_INFO_CLASS
;
386 if (len
!= sizeof(SEMAPHORE_BASIC_INFORMATION
)) return STATUS_INFO_LENGTH_MISMATCH
;
388 SERVER_START_REQ( query_semaphore
)
390 req
->handle
= wine_server_obj_handle( handle
);
391 if (!(ret
= wine_server_call( req
)))
393 out
->CurrentCount
= reply
->current
;
394 out
->MaximumCount
= reply
->max
;
395 if (ret_len
) *ret_len
= sizeof(SEMAPHORE_BASIC_INFORMATION
);
403 /******************************************************************************
404 * NtReleaseSemaphore (NTDLL.@)
406 NTSTATUS WINAPI
NtReleaseSemaphore( HANDLE handle
, ULONG count
, ULONG
*previous
)
410 SERVER_START_REQ( release_semaphore
)
412 req
->handle
= wine_server_obj_handle( handle
);
414 if (!(ret
= wine_server_call( req
)))
416 if (previous
) *previous
= reply
->prev_count
;
424 /**************************************************************************
425 * NtCreateEvent (NTDLL.@)
427 NTSTATUS WINAPI
NtCreateEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
428 EVENT_TYPE type
, BOOLEAN state
)
432 struct object_attributes
*objattr
;
435 if (type
!= NotificationEvent
&& type
!= SynchronizationEvent
) return STATUS_INVALID_PARAMETER
;
436 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
438 SERVER_START_REQ( create_event
)
440 req
->access
= access
;
441 req
->manual_reset
= (type
== NotificationEvent
);
442 req
->initial_state
= state
;
443 wine_server_add_data( req
, objattr
, len
);
444 ret
= wine_server_call( req
);
445 *handle
= wine_server_ptr_handle( reply
->handle
);
454 /******************************************************************************
455 * NtOpenEvent (NTDLL.@)
457 NTSTATUS WINAPI
NtOpenEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
462 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
464 SERVER_START_REQ( open_event
)
466 req
->access
= access
;
467 req
->attributes
= attr
->Attributes
;
468 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
469 if (attr
->ObjectName
)
470 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
471 ret
= wine_server_call( req
);
472 *handle
= wine_server_ptr_handle( reply
->handle
);
479 /******************************************************************************
480 * NtSetEvent (NTDLL.@)
482 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, LONG
*prev_state
)
486 SERVER_START_REQ( event_op
)
488 req
->handle
= wine_server_obj_handle( handle
);
490 ret
= wine_server_call( req
);
491 if (!ret
&& prev_state
) *prev_state
= reply
->state
;
498 /******************************************************************************
499 * NtResetEvent (NTDLL.@)
501 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, LONG
*prev_state
)
505 SERVER_START_REQ( event_op
)
507 req
->handle
= wine_server_obj_handle( handle
);
508 req
->op
= RESET_EVENT
;
509 ret
= wine_server_call( req
);
510 if (!ret
&& prev_state
) *prev_state
= reply
->state
;
517 /******************************************************************************
518 * NtClearEvent (NTDLL.@)
520 NTSTATUS WINAPI
NtClearEvent( HANDLE handle
)
522 /* FIXME: same as NtResetEvent ??? */
523 return NtResetEvent( handle
, NULL
);
527 /******************************************************************************
528 * NtPulseEvent (NTDLL.@)
530 NTSTATUS WINAPI
NtPulseEvent( HANDLE handle
, LONG
*prev_state
)
534 SERVER_START_REQ( event_op
)
536 req
->handle
= wine_server_obj_handle( handle
);
537 req
->op
= PULSE_EVENT
;
538 ret
= wine_server_call( req
);
539 if (!ret
&& prev_state
) *prev_state
= reply
->state
;
546 /******************************************************************************
547 * NtQueryEvent (NTDLL.@)
549 NTSTATUS WINAPI
NtQueryEvent( HANDLE handle
, EVENT_INFORMATION_CLASS
class,
550 void *info
, ULONG len
, ULONG
*ret_len
)
553 EVENT_BASIC_INFORMATION
*out
= info
;
555 TRACE("(%p, %u, %p, %u, %p)\n", handle
, class, info
, len
, ret_len
);
557 if (class != EventBasicInformation
)
559 FIXME("(%p, %d, %d) Unknown class\n",
561 return STATUS_INVALID_INFO_CLASS
;
564 if (len
!= sizeof(EVENT_BASIC_INFORMATION
)) return STATUS_INFO_LENGTH_MISMATCH
;
566 SERVER_START_REQ( query_event
)
568 req
->handle
= wine_server_obj_handle( handle
);
569 if (!(ret
= wine_server_call( req
)))
571 out
->EventType
= reply
->manual_reset
? NotificationEvent
: SynchronizationEvent
;
572 out
->EventState
= reply
->state
;
573 if (ret_len
) *ret_len
= sizeof(EVENT_BASIC_INFORMATION
);
581 /******************************************************************************
582 * NtCreateMutant (NTDLL.@)
584 NTSTATUS WINAPI
NtCreateMutant( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
589 struct object_attributes
*objattr
;
592 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
594 SERVER_START_REQ( create_mutex
)
596 req
->access
= access
;
598 wine_server_add_data( req
, objattr
, len
);
599 ret
= wine_server_call( req
);
600 *handle
= wine_server_ptr_handle( reply
->handle
);
609 /**************************************************************************
610 * NtOpenMutant (NTDLL.@)
612 NTSTATUS WINAPI
NtOpenMutant( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
617 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
619 SERVER_START_REQ( open_mutex
)
621 req
->access
= access
;
622 req
->attributes
= attr
->Attributes
;
623 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
624 if (attr
->ObjectName
)
625 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
626 ret
= wine_server_call( req
);
627 *handle
= wine_server_ptr_handle( reply
->handle
);
634 /**************************************************************************
635 * NtReleaseMutant (NTDLL.@)
637 NTSTATUS WINAPI
NtReleaseMutant( HANDLE handle
, LONG
*prev_count
)
641 SERVER_START_REQ( release_mutex
)
643 req
->handle
= wine_server_obj_handle( handle
);
644 ret
= wine_server_call( req
);
645 if (prev_count
) *prev_count
= 1 - reply
->prev_count
;
652 /******************************************************************
653 * NtQueryMutant (NTDLL.@)
655 NTSTATUS WINAPI
NtQueryMutant( HANDLE handle
, MUTANT_INFORMATION_CLASS
class,
656 void *info
, ULONG len
, ULONG
*ret_len
)
659 MUTANT_BASIC_INFORMATION
*out
= info
;
661 TRACE("(%p, %u, %p, %u, %p)\n", handle
, class, info
, len
, ret_len
);
663 if (class != MutantBasicInformation
)
665 FIXME( "(%p, %d, %d) Unknown class\n", handle
, class, len
);
666 return STATUS_INVALID_INFO_CLASS
;
669 if (len
!= sizeof(MUTANT_BASIC_INFORMATION
)) return STATUS_INFO_LENGTH_MISMATCH
;
671 SERVER_START_REQ( query_mutex
)
673 req
->handle
= wine_server_obj_handle( handle
);
674 if (!(ret
= wine_server_call( req
)))
676 out
->CurrentCount
= 1 - reply
->count
;
677 out
->OwnedByCaller
= reply
->owned
;
678 out
->AbandonedState
= reply
->abandoned
;
679 if (ret_len
) *ret_len
= sizeof(MUTANT_BASIC_INFORMATION
);
687 /**************************************************************************
688 * NtCreateJobObject (NTDLL.@)
690 NTSTATUS WINAPI
NtCreateJobObject( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
694 struct object_attributes
*objattr
;
697 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
699 SERVER_START_REQ( create_job
)
701 req
->access
= access
;
702 wine_server_add_data( req
, objattr
, len
);
703 ret
= wine_server_call( req
);
704 *handle
= wine_server_ptr_handle( reply
->handle
);
712 /**************************************************************************
713 * NtOpenJobObject (NTDLL.@)
715 NTSTATUS WINAPI
NtOpenJobObject( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
720 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
722 SERVER_START_REQ( open_job
)
724 req
->access
= access
;
725 req
->attributes
= attr
->Attributes
;
726 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
727 if (attr
->ObjectName
)
728 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
729 ret
= wine_server_call( req
);
730 *handle
= wine_server_ptr_handle( reply
->handle
);
737 /**************************************************************************
738 * NtTerminateJobObject (NTDLL.@)
740 NTSTATUS WINAPI
NtTerminateJobObject( HANDLE handle
, NTSTATUS status
)
744 TRACE( "(%p, %d)\n", handle
, status
);
746 SERVER_START_REQ( terminate_job
)
748 req
->handle
= wine_server_obj_handle( handle
);
749 req
->status
= status
;
750 ret
= wine_server_call( req
);
758 /**************************************************************************
759 * NtQueryInformationJobObject (NTDLL.@)
761 NTSTATUS WINAPI
NtQueryInformationJobObject( HANDLE handle
, JOBOBJECTINFOCLASS
class, void *info
,
762 ULONG len
, ULONG
*ret_len
)
766 TRACE( "semi-stub: %p %u %p %u %p\n", handle
, class, info
, len
, ret_len
);
768 if (class >= MaxJobObjectInfoClass
) return STATUS_INVALID_PARAMETER
;
772 case JobObjectBasicAccountingInformation
:
774 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION
*accounting
= info
;
776 if (len
< sizeof(*accounting
)) return STATUS_INFO_LENGTH_MISMATCH
;
777 SERVER_START_REQ(get_job_info
)
779 req
->handle
= wine_server_obj_handle( handle
);
780 if (!(ret
= wine_server_call( req
)))
782 memset( accounting
, 0, sizeof(*accounting
) );
783 accounting
->TotalProcesses
= reply
->total_processes
;
784 accounting
->ActiveProcesses
= reply
->active_processes
;
788 if (ret_len
) *ret_len
= sizeof(*accounting
);
791 case JobObjectBasicProcessIdList
:
793 JOBOBJECT_BASIC_PROCESS_ID_LIST
*process
= info
;
795 if (len
< sizeof(*process
)) return STATUS_INFO_LENGTH_MISMATCH
;
796 memset( process
, 0, sizeof(*process
) );
797 if (ret_len
) *ret_len
= sizeof(*process
);
798 return STATUS_SUCCESS
;
800 case JobObjectExtendedLimitInformation
:
802 JOBOBJECT_EXTENDED_LIMIT_INFORMATION
*extended_limit
= info
;
804 if (len
< sizeof(*extended_limit
)) return STATUS_INFO_LENGTH_MISMATCH
;
805 memset( extended_limit
, 0, sizeof(*extended_limit
) );
806 if (ret_len
) *ret_len
= sizeof(*extended_limit
);
807 return STATUS_SUCCESS
;
809 case JobObjectBasicLimitInformation
:
811 JOBOBJECT_BASIC_LIMIT_INFORMATION
*basic_limit
= info
;
813 if (len
< sizeof(*basic_limit
)) return STATUS_INFO_LENGTH_MISMATCH
;
814 memset( basic_limit
, 0, sizeof(*basic_limit
) );
815 if (ret_len
) *ret_len
= sizeof(*basic_limit
);
816 return STATUS_SUCCESS
;
819 return STATUS_NOT_IMPLEMENTED
;
824 /**************************************************************************
825 * NtSetInformationJobObject (NTDLL.@)
827 NTSTATUS WINAPI
NtSetInformationJobObject( HANDLE handle
, JOBOBJECTINFOCLASS
class, void *info
, ULONG len
)
829 NTSTATUS status
= STATUS_NOT_IMPLEMENTED
;
830 JOBOBJECT_BASIC_LIMIT_INFORMATION
*basic_limit
;
831 ULONG info_size
= sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION
);
832 DWORD limit_flags
= JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS
;
834 TRACE( "(%p, %u, %p, %u)\n", handle
, class, info
, len
);
836 if (class >= MaxJobObjectInfoClass
) return STATUS_INVALID_PARAMETER
;
841 case JobObjectExtendedLimitInformation
:
842 info_size
= sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION
);
843 limit_flags
= JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS
;
845 case JobObjectBasicLimitInformation
:
846 if (len
!= info_size
) return STATUS_INVALID_PARAMETER
;
848 if (basic_limit
->LimitFlags
& ~limit_flags
) return STATUS_INVALID_PARAMETER
;
849 SERVER_START_REQ( set_job_limits
)
851 req
->handle
= wine_server_obj_handle( handle
);
852 req
->limit_flags
= basic_limit
->LimitFlags
;
853 status
= wine_server_call( req
);
857 case JobObjectAssociateCompletionPortInformation
:
858 if (len
!= sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT
)) return STATUS_INVALID_PARAMETER
;
859 SERVER_START_REQ( set_job_completion_port
)
861 JOBOBJECT_ASSOCIATE_COMPLETION_PORT
*port_info
= info
;
862 req
->job
= wine_server_obj_handle( handle
);
863 req
->port
= wine_server_obj_handle( port_info
->CompletionPort
);
864 req
->key
= wine_server_client_ptr( port_info
->CompletionKey
);
865 status
= wine_server_call( req
);
869 case JobObjectBasicUIRestrictions
:
870 status
= STATUS_SUCCESS
;
873 FIXME( "stub: %p %u %p %u\n", handle
, class, info
, len
);
879 /**************************************************************************
880 * NtIsProcessInJob (NTDLL.@)
882 NTSTATUS WINAPI
NtIsProcessInJob( HANDLE process
, HANDLE job
)
886 TRACE( "(%p %p)\n", job
, process
);
888 SERVER_START_REQ( process_in_job
)
890 req
->job
= wine_server_obj_handle( job
);
891 req
->process
= wine_server_obj_handle( process
);
892 status
= wine_server_call( req
);
899 /**************************************************************************
900 * NtAssignProcessToJobObject (NTDLL.@)
902 NTSTATUS WINAPI
NtAssignProcessToJobObject( HANDLE job
, HANDLE process
)
906 TRACE( "(%p %p)\n", job
, process
);
908 SERVER_START_REQ( assign_job
)
910 req
->job
= wine_server_obj_handle( job
);
911 req
->process
= wine_server_obj_handle( process
);
912 status
= wine_server_call( req
);
919 /**********************************************************************
920 * NtCreateDebugObject (NTDLL.@)
922 NTSTATUS WINAPI
NtCreateDebugObject( HANDLE
*handle
, ACCESS_MASK access
,
923 OBJECT_ATTRIBUTES
*attr
, ULONG flags
)
927 struct object_attributes
*objattr
;
930 if (flags
& ~DEBUG_KILL_ON_CLOSE
) return STATUS_INVALID_PARAMETER
;
931 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
933 SERVER_START_REQ( create_debug_obj
)
935 req
->access
= access
;
937 wine_server_add_data( req
, objattr
, len
);
938 ret
= wine_server_call( req
);
939 *handle
= wine_server_ptr_handle( reply
->handle
);
947 /**********************************************************************
948 * NtSetInformationDebugObject (NTDLL.@)
950 NTSTATUS WINAPI
NtSetInformationDebugObject( HANDLE handle
, DEBUGOBJECTINFOCLASS
class,
951 void *info
, ULONG len
, ULONG
*ret_len
)
956 if (class != DebugObjectKillProcessOnExitInformation
) return STATUS_INVALID_PARAMETER
;
957 if (len
!= sizeof(ULONG
))
959 if (ret_len
) *ret_len
= sizeof(ULONG
);
960 return STATUS_INFO_LENGTH_MISMATCH
;
962 flags
= *(ULONG
*)info
;
963 if (flags
& ~DEBUG_KILL_ON_CLOSE
) return STATUS_INVALID_PARAMETER
;
965 SERVER_START_REQ( set_debug_obj_info
)
967 req
->debug
= wine_server_obj_handle( handle
);
969 ret
= wine_server_call( req
);
972 if (!ret
&& ret_len
) *ret_len
= 0;
977 /* convert the server event data to an NT state change; helper for NtWaitForDebugEvent */
978 static NTSTATUS
event_data_to_state_change( const debug_event_t
*data
, DBGUI_WAIT_STATE_CHANGE
*state
)
985 case DbgReplyPending
:
986 return STATUS_PENDING
;
987 case DbgCreateThreadStateChange
:
989 DBGUI_CREATE_THREAD
*info
= &state
->StateInfo
.CreateThread
;
990 info
->HandleToThread
= wine_server_ptr_handle( data
->create_thread
.handle
);
991 info
->NewThread
.StartAddress
= wine_server_get_ptr( data
->create_thread
.start
);
992 return STATUS_SUCCESS
;
994 case DbgCreateProcessStateChange
:
996 DBGUI_CREATE_PROCESS
*info
= &state
->StateInfo
.CreateProcessInfo
;
997 info
->HandleToProcess
= wine_server_ptr_handle( data
->create_process
.process
);
998 info
->HandleToThread
= wine_server_ptr_handle( data
->create_process
.thread
);
999 info
->NewProcess
.FileHandle
= wine_server_ptr_handle( data
->create_process
.file
);
1000 info
->NewProcess
.BaseOfImage
= wine_server_get_ptr( data
->create_process
.base
);
1001 info
->NewProcess
.DebugInfoFileOffset
= data
->create_process
.dbg_offset
;
1002 info
->NewProcess
.DebugInfoSize
= data
->create_process
.dbg_size
;
1003 info
->NewProcess
.InitialThread
.StartAddress
= wine_server_get_ptr( data
->create_process
.start
);
1004 return STATUS_SUCCESS
;
1006 case DbgExitThreadStateChange
:
1007 state
->StateInfo
.ExitThread
.ExitStatus
= data
->exit
.exit_code
;
1008 return STATUS_SUCCESS
;
1009 case DbgExitProcessStateChange
:
1010 state
->StateInfo
.ExitProcess
.ExitStatus
= data
->exit
.exit_code
;
1011 return STATUS_SUCCESS
;
1012 case DbgExceptionStateChange
:
1013 case DbgBreakpointStateChange
:
1014 case DbgSingleStepStateChange
:
1016 DBGKM_EXCEPTION
*info
= &state
->StateInfo
.Exception
;
1017 info
->FirstChance
= data
->exception
.first
;
1018 info
->ExceptionRecord
.ExceptionCode
= data
->exception
.exc_code
;
1019 info
->ExceptionRecord
.ExceptionFlags
= data
->exception
.flags
;
1020 info
->ExceptionRecord
.ExceptionRecord
= wine_server_get_ptr( data
->exception
.record
);
1021 info
->ExceptionRecord
.ExceptionAddress
= wine_server_get_ptr( data
->exception
.address
);
1022 info
->ExceptionRecord
.NumberParameters
= data
->exception
.nb_params
;
1023 for (i
= 0; i
< data
->exception
.nb_params
; i
++)
1024 info
->ExceptionRecord
.ExceptionInformation
[i
] = data
->exception
.params
[i
];
1025 return STATUS_SUCCESS
;
1027 case DbgLoadDllStateChange
:
1029 DBGKM_LOAD_DLL
*info
= &state
->StateInfo
.LoadDll
;
1030 info
->FileHandle
= wine_server_ptr_handle( data
->load_dll
.handle
);
1031 info
->BaseOfDll
= wine_server_get_ptr( data
->load_dll
.base
);
1032 info
->DebugInfoFileOffset
= data
->load_dll
.dbg_offset
;
1033 info
->DebugInfoSize
= data
->load_dll
.dbg_size
;
1034 info
->NamePointer
= wine_server_get_ptr( data
->load_dll
.name
);
1035 return STATUS_SUCCESS
;
1037 case DbgUnloadDllStateChange
:
1038 state
->StateInfo
.UnloadDll
.BaseAddress
= wine_server_get_ptr( data
->unload_dll
.base
);
1039 return STATUS_SUCCESS
;
1041 return STATUS_INTERNAL_ERROR
;
1044 /**********************************************************************
1045 * NtWaitForDebugEvent (NTDLL.@)
1047 NTSTATUS WINAPI
NtWaitForDebugEvent( HANDLE handle
, BOOLEAN alertable
, LARGE_INTEGER
*timeout
,
1048 DBGUI_WAIT_STATE_CHANGE
*state
)
1056 SERVER_START_REQ( wait_debug_event
)
1058 req
->debug
= wine_server_obj_handle( handle
);
1059 wine_server_set_reply( req
, &data
, sizeof(data
) );
1060 ret
= wine_server_call( req
);
1061 if (!ret
&& !(ret
= event_data_to_state_change( &data
, state
)))
1063 state
->NewState
= data
.code
;
1064 state
->AppClientId
.UniqueProcess
= ULongToHandle( reply
->pid
);
1065 state
->AppClientId
.UniqueThread
= ULongToHandle( reply
->tid
);
1070 if (ret
!= STATUS_PENDING
) return ret
;
1071 if (!wait
) return STATUS_TIMEOUT
;
1073 ret
= NtWaitForSingleObject( handle
, alertable
, timeout
);
1074 if (ret
!= STATUS_WAIT_0
) return ret
;
1079 /**************************************************************************
1080 * NtCreateDirectoryObject (NTDLL.@)
1082 NTSTATUS WINAPI
NtCreateDirectoryObject( HANDLE
*handle
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
)
1086 struct object_attributes
*objattr
;
1089 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
1091 SERVER_START_REQ( create_directory
)
1093 req
->access
= access
;
1094 wine_server_add_data( req
, objattr
, len
);
1095 ret
= wine_server_call( req
);
1096 *handle
= wine_server_ptr_handle( reply
->handle
);
1104 /**************************************************************************
1105 * NtOpenDirectoryObject (NTDLL.@)
1107 NTSTATUS WINAPI
NtOpenDirectoryObject( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
1112 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
1114 SERVER_START_REQ( open_directory
)
1116 req
->access
= access
;
1117 req
->attributes
= attr
->Attributes
;
1118 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
1119 if (attr
->ObjectName
)
1120 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
1121 ret
= wine_server_call( req
);
1122 *handle
= wine_server_ptr_handle( reply
->handle
);
1129 /**************************************************************************
1130 * NtQueryDirectoryObject (NTDLL.@)
1132 NTSTATUS WINAPI
NtQueryDirectoryObject( HANDLE handle
, DIRECTORY_BASIC_INFORMATION
*buffer
,
1133 ULONG size
, BOOLEAN single_entry
, BOOLEAN restart
,
1134 ULONG
*context
, ULONG
*ret_size
)
1138 if (restart
) *context
= 0;
1142 if (size
<= sizeof(*buffer
) + 2 * sizeof(WCHAR
)) return STATUS_BUFFER_OVERFLOW
;
1144 SERVER_START_REQ( get_directory_entry
)
1146 req
->handle
= wine_server_obj_handle( handle
);
1147 req
->index
= *context
;
1148 wine_server_set_reply( req
, buffer
+ 1, size
- sizeof(*buffer
) - 2*sizeof(WCHAR
) );
1149 if (!(ret
= wine_server_call( req
)))
1151 buffer
->ObjectName
.Buffer
= (WCHAR
*)(buffer
+ 1);
1152 buffer
->ObjectName
.Length
= reply
->name_len
;
1153 buffer
->ObjectName
.MaximumLength
= reply
->name_len
+ sizeof(WCHAR
);
1154 buffer
->ObjectTypeName
.Buffer
= (WCHAR
*)(buffer
+ 1) + reply
->name_len
/sizeof(WCHAR
) + 1;
1155 buffer
->ObjectTypeName
.Length
= wine_server_reply_size( reply
) - reply
->name_len
;
1156 buffer
->ObjectTypeName
.MaximumLength
= buffer
->ObjectTypeName
.Length
+ sizeof(WCHAR
);
1157 /* make room for the terminating null */
1158 memmove( buffer
->ObjectTypeName
.Buffer
, buffer
->ObjectTypeName
.Buffer
- 1,
1159 buffer
->ObjectTypeName
.Length
);
1160 buffer
->ObjectName
.Buffer
[buffer
->ObjectName
.Length
/sizeof(WCHAR
)] = 0;
1161 buffer
->ObjectTypeName
.Buffer
[buffer
->ObjectTypeName
.Length
/sizeof(WCHAR
)] = 0;
1167 *ret_size
= buffer
->ObjectName
.MaximumLength
+ buffer
->ObjectTypeName
.MaximumLength
+ sizeof(*buffer
);
1171 FIXME("multiple entries not implemented\n");
1172 ret
= STATUS_NOT_IMPLEMENTED
;
1178 /**************************************************************************
1179 * NtCreateSymbolicLinkObject (NTDLL.@)
1181 NTSTATUS WINAPI
NtCreateSymbolicLinkObject( HANDLE
*handle
, ACCESS_MASK access
,
1182 OBJECT_ATTRIBUTES
*attr
, UNICODE_STRING
*target
)
1186 struct object_attributes
*objattr
;
1189 if (!target
->MaximumLength
) return STATUS_INVALID_PARAMETER
;
1190 if (!target
->Buffer
) return STATUS_ACCESS_VIOLATION
;
1191 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
1193 SERVER_START_REQ( create_symlink
)
1195 req
->access
= access
;
1196 wine_server_add_data( req
, objattr
, len
);
1197 wine_server_add_data( req
, target
->Buffer
, target
->Length
);
1198 ret
= wine_server_call( req
);
1199 *handle
= wine_server_ptr_handle( reply
->handle
);
1207 /**************************************************************************
1208 * NtOpenSymbolicLinkObject (NTDLL.@)
1210 NTSTATUS WINAPI
NtOpenSymbolicLinkObject( HANDLE
*handle
, ACCESS_MASK access
,
1211 const OBJECT_ATTRIBUTES
*attr
)
1216 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
1218 SERVER_START_REQ( open_symlink
)
1220 req
->access
= access
;
1221 req
->attributes
= attr
->Attributes
;
1222 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
1223 if (attr
->ObjectName
)
1224 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
1225 ret
= wine_server_call( req
);
1226 *handle
= wine_server_ptr_handle( reply
->handle
);
1233 /**************************************************************************
1234 * NtQuerySymbolicLinkObject (NTDLL.@)
1236 NTSTATUS WINAPI
NtQuerySymbolicLinkObject( HANDLE handle
, UNICODE_STRING
*target
, ULONG
*length
)
1240 if (!target
) return STATUS_ACCESS_VIOLATION
;
1242 SERVER_START_REQ( query_symlink
)
1244 req
->handle
= wine_server_obj_handle( handle
);
1245 if (target
->MaximumLength
>= sizeof(WCHAR
))
1246 wine_server_set_reply( req
, target
->Buffer
, target
->MaximumLength
- sizeof(WCHAR
) );
1247 if (!(ret
= wine_server_call( req
)))
1249 target
->Length
= wine_server_reply_size(reply
);
1250 target
->Buffer
[target
->Length
/ sizeof(WCHAR
)] = 0;
1251 if (length
) *length
= reply
->total
+ sizeof(WCHAR
);
1253 else if (length
&& ret
== STATUS_BUFFER_TOO_SMALL
) *length
= reply
->total
+ sizeof(WCHAR
);
1260 /**************************************************************************
1261 * NtMakeTemporaryObject (NTDLL.@)
1263 NTSTATUS WINAPI
NtMakeTemporaryObject( HANDLE handle
)
1267 TRACE("%p\n", handle
);
1269 SERVER_START_REQ( make_temporary
)
1271 req
->handle
= wine_server_obj_handle( handle
);
1272 ret
= wine_server_call( req
);
1279 /**************************************************************************
1280 * NtCreateTimer (NTDLL.@)
1282 NTSTATUS WINAPI
NtCreateTimer( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
1287 struct object_attributes
*objattr
;
1290 if (type
!= NotificationTimer
&& type
!= SynchronizationTimer
) return STATUS_INVALID_PARAMETER
;
1291 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
1293 SERVER_START_REQ( create_timer
)
1295 req
->access
= access
;
1296 req
->manual
= (type
== NotificationTimer
);
1297 wine_server_add_data( req
, objattr
, len
);
1298 ret
= wine_server_call( req
);
1299 *handle
= wine_server_ptr_handle( reply
->handle
);
1309 /**************************************************************************
1310 * NtOpenTimer (NTDLL.@)
1312 NTSTATUS WINAPI
NtOpenTimer( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
1317 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
1319 SERVER_START_REQ( open_timer
)
1321 req
->access
= access
;
1322 req
->attributes
= attr
->Attributes
;
1323 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
1324 if (attr
->ObjectName
)
1325 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
1326 ret
= wine_server_call( req
);
1327 *handle
= wine_server_ptr_handle( reply
->handle
);
1334 /**************************************************************************
1335 * NtSetTimer (NTDLL.@)
1337 NTSTATUS WINAPI
NtSetTimer( HANDLE handle
, const LARGE_INTEGER
*when
, PTIMER_APC_ROUTINE callback
,
1338 void *arg
, BOOLEAN resume
, ULONG period
, BOOLEAN
*state
)
1340 NTSTATUS ret
= STATUS_SUCCESS
;
1342 TRACE( "(%p,%p,%p,%p,%08x,0x%08x,%p)\n", handle
, when
, callback
, arg
, resume
, period
, state
);
1344 SERVER_START_REQ( set_timer
)
1346 req
->handle
= wine_server_obj_handle( handle
);
1347 req
->period
= period
;
1348 req
->expire
= when
->QuadPart
;
1349 req
->callback
= wine_server_client_ptr( callback
);
1350 req
->arg
= wine_server_client_ptr( arg
);
1351 ret
= wine_server_call( req
);
1352 if (state
) *state
= reply
->signaled
;
1356 /* set error but can still succeed */
1357 if (resume
&& ret
== STATUS_SUCCESS
) return STATUS_TIMER_RESUME_IGNORED
;
1362 /**************************************************************************
1363 * NtCancelTimer (NTDLL.@)
1365 NTSTATUS WINAPI
NtCancelTimer( HANDLE handle
, BOOLEAN
*state
)
1369 SERVER_START_REQ( cancel_timer
)
1371 req
->handle
= wine_server_obj_handle( handle
);
1372 ret
= wine_server_call( req
);
1373 if (state
) *state
= reply
->signaled
;
1380 /******************************************************************************
1381 * NtQueryTimer (NTDLL.@)
1383 NTSTATUS WINAPI
NtQueryTimer( HANDLE handle
, TIMER_INFORMATION_CLASS
class,
1384 void *info
, ULONG len
, ULONG
*ret_len
)
1386 TIMER_BASIC_INFORMATION
*basic_info
= info
;
1390 TRACE( "(%p,%d,%p,0x%08x,%p)\n", handle
, class, info
, len
, ret_len
);
1394 case TimerBasicInformation
:
1395 if (len
< sizeof(TIMER_BASIC_INFORMATION
)) return STATUS_INFO_LENGTH_MISMATCH
;
1397 SERVER_START_REQ( get_timer_info
)
1399 req
->handle
= wine_server_obj_handle( handle
);
1400 ret
= wine_server_call(req
);
1401 /* convert server time to absolute NTDLL time */
1402 basic_info
->RemainingTime
.QuadPart
= reply
->when
;
1403 basic_info
->TimerState
= reply
->signaled
;
1407 /* convert into relative time */
1408 if (basic_info
->RemainingTime
.QuadPart
> 0) NtQuerySystemTime( &now
);
1411 NtQueryPerformanceCounter( &now
, NULL
);
1412 basic_info
->RemainingTime
.QuadPart
= -basic_info
->RemainingTime
.QuadPart
;
1415 if (now
.QuadPart
> basic_info
->RemainingTime
.QuadPart
)
1416 basic_info
->RemainingTime
.QuadPart
= 0;
1418 basic_info
->RemainingTime
.QuadPart
-= now
.QuadPart
;
1420 if (ret_len
) *ret_len
= sizeof(TIMER_BASIC_INFORMATION
);
1424 FIXME( "Unhandled class %d\n", class );
1425 return STATUS_INVALID_INFO_CLASS
;
1429 /******************************************************************
1430 * NtWaitForMultipleObjects (NTDLL.@)
1432 NTSTATUS WINAPI
NtWaitForMultipleObjects( DWORD count
, const HANDLE
*handles
, BOOLEAN wait_any
,
1433 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1435 select_op_t select_op
;
1436 UINT i
, flags
= SELECT_INTERRUPTIBLE
;
1438 if (!count
|| count
> MAXIMUM_WAIT_OBJECTS
) return STATUS_INVALID_PARAMETER_1
;
1440 if (alertable
) flags
|= SELECT_ALERTABLE
;
1441 select_op
.wait
.op
= wait_any
? SELECT_WAIT
: SELECT_WAIT_ALL
;
1442 for (i
= 0; i
< count
; i
++) select_op
.wait
.handles
[i
] = wine_server_obj_handle( handles
[i
] );
1443 return server_wait( &select_op
, offsetof( select_op_t
, wait
.handles
[count
] ), flags
, timeout
);
1447 /******************************************************************
1448 * NtWaitForSingleObject (NTDLL.@)
1450 NTSTATUS WINAPI
NtWaitForSingleObject( HANDLE handle
, BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1452 return NtWaitForMultipleObjects( 1, &handle
, FALSE
, alertable
, timeout
);
1456 /******************************************************************
1457 * NtSignalAndWaitForSingleObject (NTDLL.@)
1459 NTSTATUS WINAPI
NtSignalAndWaitForSingleObject( HANDLE signal
, HANDLE wait
,
1460 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1462 select_op_t select_op
;
1463 UINT flags
= SELECT_INTERRUPTIBLE
;
1465 if (!signal
) return STATUS_INVALID_HANDLE
;
1467 if (alertable
) flags
|= SELECT_ALERTABLE
;
1468 select_op
.signal_and_wait
.op
= SELECT_SIGNAL_AND_WAIT
;
1469 select_op
.signal_and_wait
.wait
= wine_server_obj_handle( wait
);
1470 select_op
.signal_and_wait
.signal
= wine_server_obj_handle( signal
);
1471 return server_wait( &select_op
, sizeof(select_op
.signal_and_wait
), flags
, timeout
);
1475 /******************************************************************
1476 * NtYieldExecution (NTDLL.@)
1478 NTSTATUS WINAPI
NtYieldExecution(void)
1480 #ifdef HAVE_SCHED_YIELD
1482 return STATUS_SUCCESS
;
1484 return STATUS_NO_YIELD_PERFORMED
;
1489 /******************************************************************
1490 * NtDelayExecution (NTDLL.@)
1492 NTSTATUS WINAPI
NtDelayExecution( BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1494 /* if alertable, we need to query the server */
1495 if (alertable
) return server_wait( NULL
, 0, SELECT_INTERRUPTIBLE
| SELECT_ALERTABLE
, timeout
);
1497 if (!timeout
|| timeout
->QuadPart
== TIMEOUT_INFINITE
) /* sleep forever */
1499 for (;;) select( 0, NULL
, NULL
, NULL
, NULL
);
1504 timeout_t when
, diff
;
1506 if ((when
= timeout
->QuadPart
) < 0)
1508 NtQuerySystemTime( &now
);
1509 when
= now
.QuadPart
- when
;
1512 /* Note that we yield after establishing the desired timeout */
1514 if (!when
) return STATUS_SUCCESS
;
1519 NtQuerySystemTime( &now
);
1520 diff
= (when
- now
.QuadPart
+ 9) / 10;
1521 if (diff
<= 0) break;
1522 tv
.tv_sec
= diff
/ 1000000;
1523 tv
.tv_usec
= diff
% 1000000;
1524 if (select( 0, NULL
, NULL
, NULL
, &tv
) != -1) break;
1527 return STATUS_SUCCESS
;
1531 /******************************************************************************
1532 * NtQueryPerformanceCounter (NTDLL.@)
1534 NTSTATUS WINAPI
NtQueryPerformanceCounter( LARGE_INTEGER
*counter
, LARGE_INTEGER
*frequency
)
1536 counter
->QuadPart
= monotonic_counter();
1537 if (frequency
) frequency
->QuadPart
= TICKSPERSEC
;
1538 return STATUS_SUCCESS
;
1542 /***********************************************************************
1543 * NtQuerySystemTime (NTDLL.@)
1545 NTSTATUS WINAPI
NtQuerySystemTime( LARGE_INTEGER
*time
)
1547 #ifdef HAVE_CLOCK_GETTIME
1549 static clockid_t clock_id
= CLOCK_MONOTONIC
; /* placeholder */
1551 if (clock_id
== CLOCK_MONOTONIC
)
1553 #ifdef CLOCK_REALTIME_COARSE
1554 struct timespec res
;
1556 /* Use CLOCK_REALTIME_COARSE if it has 1 ms or better resolution */
1557 if (!clock_getres( CLOCK_REALTIME_COARSE
, &res
) && res
.tv_sec
== 0 && res
.tv_nsec
<= 1000000)
1558 clock_id
= CLOCK_REALTIME_COARSE
;
1560 #endif /* CLOCK_REALTIME_COARSE */
1561 clock_id
= CLOCK_REALTIME
;
1564 if (!clock_gettime( clock_id
, &ts
))
1566 time
->QuadPart
= ticks_from_time_t( ts
.tv_sec
) + (ts
.tv_nsec
+ 50) / 100;
1569 #endif /* HAVE_CLOCK_GETTIME */
1573 gettimeofday( &now
, 0 );
1574 time
->QuadPart
= ticks_from_time_t( now
.tv_sec
) + now
.tv_usec
* 10;
1576 return STATUS_SUCCESS
;
1580 /***********************************************************************
1581 * NtSetSystemTime (NTDLL.@)
1583 NTSTATUS WINAPI
NtSetSystemTime( const LARGE_INTEGER
*new, LARGE_INTEGER
*old
)
1588 NtQuerySystemTime( &now
);
1589 if (old
) *old
= now
;
1590 diff
= new->QuadPart
- now
.QuadPart
;
1591 if (diff
> -TICKSPERSEC
/ 2 && diff
< TICKSPERSEC
/ 2) return STATUS_SUCCESS
;
1592 ERR( "not allowed: difference %d ms\n", (int)(diff
/ 10000) );
1593 return STATUS_PRIVILEGE_NOT_HELD
;
1597 /***********************************************************************
1598 * NtQueryTimerResolution (NTDLL.@)
1600 NTSTATUS WINAPI
NtQueryTimerResolution( ULONG
*min_res
, ULONG
*max_res
, ULONG
*current_res
)
1602 FIXME( "(%p,%p,%p), stub!\n", min_res
, max_res
, current_res
);
1603 return STATUS_NOT_IMPLEMENTED
;
1607 /***********************************************************************
1608 * NtSetTimerResolution (NTDLL.@)
1610 NTSTATUS WINAPI
NtSetTimerResolution( ULONG res
, BOOLEAN set
, ULONG
*current_res
)
1612 FIXME( "(%u,%u,%p), stub!\n", res
, set
, current_res
);
1613 return STATUS_NOT_IMPLEMENTED
;
1617 /******************************************************************************
1618 * NtSetIntervalProfile (NTDLL.@)
1620 NTSTATUS WINAPI
NtSetIntervalProfile( ULONG interval
, KPROFILE_SOURCE source
)
1622 FIXME( "%u,%d\n", interval
, source
);
1623 return STATUS_SUCCESS
;
1627 /******************************************************************************
1628 * NtGetTickCount (NTDLL.@)
1630 ULONG WINAPI
NtGetTickCount(void)
1632 /* note: we ignore TickCountMultiplier */
1633 return user_shared_data
->u
.TickCount
.LowPart
;
1637 /******************************************************************************
1638 * RtlGetSystemTimePrecise (NTDLL.@)
1640 LONGLONG WINAPI
RtlGetSystemTimePrecise(void)
1643 #ifdef HAVE_CLOCK_GETTIME
1646 if (!clock_gettime( CLOCK_REALTIME
, &ts
))
1647 return ticks_from_time_t( ts
.tv_sec
) + (ts
.tv_nsec
+ 50) / 100;
1649 gettimeofday( &now
, 0 );
1650 return ticks_from_time_t( now
.tv_sec
) + now
.tv_usec
* 10;
1654 /******************************************************************************
1655 * NtCreateKeyedEvent (NTDLL.@)
1657 NTSTATUS WINAPI
NtCreateKeyedEvent( HANDLE
*handle
, ACCESS_MASK access
,
1658 const OBJECT_ATTRIBUTES
*attr
, ULONG flags
)
1662 struct object_attributes
*objattr
;
1665 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
1667 SERVER_START_REQ( create_keyed_event
)
1669 req
->access
= access
;
1670 wine_server_add_data( req
, objattr
, len
);
1671 ret
= wine_server_call( req
);
1672 *handle
= wine_server_ptr_handle( reply
->handle
);
1681 /******************************************************************************
1682 * NtOpenKeyedEvent (NTDLL.@)
1684 NTSTATUS WINAPI
NtOpenKeyedEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
1689 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
1691 SERVER_START_REQ( open_keyed_event
)
1693 req
->access
= access
;
1694 req
->attributes
= attr
->Attributes
;
1695 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
1696 if (attr
->ObjectName
)
1697 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
1698 ret
= wine_server_call( req
);
1699 *handle
= wine_server_ptr_handle( reply
->handle
);
1705 /******************************************************************************
1706 * NtWaitForKeyedEvent (NTDLL.@)
1708 NTSTATUS WINAPI
NtWaitForKeyedEvent( HANDLE handle
, const void *key
,
1709 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1711 select_op_t select_op
;
1712 UINT flags
= SELECT_INTERRUPTIBLE
;
1714 if (!handle
) handle
= keyed_event
;
1715 if ((ULONG_PTR
)key
& 1) return STATUS_INVALID_PARAMETER_1
;
1716 if (alertable
) flags
|= SELECT_ALERTABLE
;
1717 select_op
.keyed_event
.op
= SELECT_KEYED_EVENT_WAIT
;
1718 select_op
.keyed_event
.handle
= wine_server_obj_handle( handle
);
1719 select_op
.keyed_event
.key
= wine_server_client_ptr( key
);
1720 return server_wait( &select_op
, sizeof(select_op
.keyed_event
), flags
, timeout
);
1724 /******************************************************************************
1725 * NtReleaseKeyedEvent (NTDLL.@)
1727 NTSTATUS WINAPI
NtReleaseKeyedEvent( HANDLE handle
, const void *key
,
1728 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1730 select_op_t select_op
;
1731 UINT flags
= SELECT_INTERRUPTIBLE
;
1733 if (!handle
) handle
= keyed_event
;
1734 if ((ULONG_PTR
)key
& 1) return STATUS_INVALID_PARAMETER_1
;
1735 if (alertable
) flags
|= SELECT_ALERTABLE
;
1736 select_op
.keyed_event
.op
= SELECT_KEYED_EVENT_RELEASE
;
1737 select_op
.keyed_event
.handle
= wine_server_obj_handle( handle
);
1738 select_op
.keyed_event
.key
= wine_server_client_ptr( key
);
1739 return server_wait( &select_op
, sizeof(select_op
.keyed_event
), flags
, timeout
);
1743 /***********************************************************************
1744 * NtCreateIoCompletion (NTDLL.@)
1746 NTSTATUS WINAPI
NtCreateIoCompletion( HANDLE
*handle
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
1751 struct object_attributes
*objattr
;
1753 TRACE( "(%p, %x, %p, %d)\n", handle
, access
, attr
, threads
);
1756 if ((status
= alloc_object_attributes( attr
, &objattr
, &len
))) return status
;
1758 SERVER_START_REQ( create_completion
)
1760 req
->access
= access
;
1761 req
->concurrent
= threads
;
1762 wine_server_add_data( req
, objattr
, len
);
1763 if (!(status
= wine_server_call( req
))) *handle
= wine_server_ptr_handle( reply
->handle
);
1772 /***********************************************************************
1773 * NtOpenIoCompletion (NTDLL.@)
1775 NTSTATUS WINAPI
NtOpenIoCompletion( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
1780 if ((status
= validate_open_object_attributes( attr
))) return status
;
1782 SERVER_START_REQ( open_completion
)
1784 req
->access
= access
;
1785 req
->attributes
= attr
->Attributes
;
1786 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
1787 if (attr
->ObjectName
)
1788 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
1789 status
= wine_server_call( req
);
1790 *handle
= wine_server_ptr_handle( reply
->handle
);
1797 /***********************************************************************
1798 * NtSetIoCompletion (NTDLL.@)
1800 NTSTATUS WINAPI
NtSetIoCompletion( HANDLE handle
, ULONG_PTR key
, ULONG_PTR value
,
1801 NTSTATUS status
, SIZE_T count
)
1805 TRACE( "(%p, %lx, %lx, %x, %lx)\n", handle
, key
, value
, status
, count
);
1807 SERVER_START_REQ( add_completion
)
1809 req
->handle
= wine_server_obj_handle( handle
);
1811 req
->cvalue
= value
;
1812 req
->status
= status
;
1813 req
->information
= count
;
1814 ret
= wine_server_call( req
);
1821 /***********************************************************************
1822 * NtRemoveIoCompletion (NTDLL.@)
1824 NTSTATUS WINAPI
NtRemoveIoCompletion( HANDLE handle
, ULONG_PTR
*key
, ULONG_PTR
*value
,
1825 IO_STATUS_BLOCK
*io
, LARGE_INTEGER
*timeout
)
1829 TRACE( "(%p, %p, %p, %p, %p)\n", handle
, key
, value
, io
, timeout
);
1833 SERVER_START_REQ( remove_completion
)
1835 req
->handle
= wine_server_obj_handle( handle
);
1836 if (!(status
= wine_server_call( req
)))
1839 *value
= reply
->cvalue
;
1840 io
->Information
= reply
->information
;
1841 io
->u
.Status
= reply
->status
;
1845 if (status
!= STATUS_PENDING
) return status
;
1846 status
= NtWaitForSingleObject( handle
, FALSE
, timeout
);
1847 if (status
!= WAIT_OBJECT_0
) return status
;
1852 /***********************************************************************
1853 * NtRemoveIoCompletionEx (NTDLL.@)
1855 NTSTATUS WINAPI
NtRemoveIoCompletionEx( HANDLE handle
, FILE_IO_COMPLETION_INFORMATION
*info
, ULONG count
,
1856 ULONG
*written
, LARGE_INTEGER
*timeout
, BOOLEAN alertable
)
1861 TRACE( "%p %p %u %p %p %u\n", handle
, info
, count
, written
, timeout
, alertable
);
1867 SERVER_START_REQ( remove_completion
)
1869 req
->handle
= wine_server_obj_handle( handle
);
1870 if (!(status
= wine_server_call( req
)))
1872 info
[i
].CompletionKey
= reply
->ckey
;
1873 info
[i
].CompletionValue
= reply
->cvalue
;
1874 info
[i
].IoStatusBlock
.Information
= reply
->information
;
1875 info
[i
].IoStatusBlock
.u
.Status
= reply
->status
;
1879 if (status
!= STATUS_SUCCESS
) break;
1882 if (i
|| status
!= STATUS_PENDING
)
1884 if (status
== STATUS_PENDING
) status
= STATUS_SUCCESS
;
1887 status
= NtWaitForSingleObject( handle
, alertable
, timeout
);
1888 if (status
!= WAIT_OBJECT_0
) break;
1890 *written
= i
? i
: 1;
1895 /***********************************************************************
1896 * NtQueryIoCompletion (NTDLL.@)
1898 NTSTATUS WINAPI
NtQueryIoCompletion( HANDLE handle
, IO_COMPLETION_INFORMATION_CLASS
class,
1899 void *buffer
, ULONG len
, ULONG
*ret_len
)
1903 TRACE( "(%p, %d, %p, 0x%x, %p)\n", handle
, class, buffer
, len
, ret_len
);
1905 if (!buffer
) return STATUS_INVALID_PARAMETER
;
1909 case IoCompletionBasicInformation
:
1911 ULONG
*info
= buffer
;
1912 if (ret_len
) *ret_len
= sizeof(*info
);
1913 if (len
== sizeof(*info
))
1915 SERVER_START_REQ( query_completion
)
1917 req
->handle
= wine_server_obj_handle( handle
);
1918 if (!(status
= wine_server_call( req
))) *info
= reply
->depth
;
1922 else status
= STATUS_INFO_LENGTH_MISMATCH
;
1926 return STATUS_INVALID_PARAMETER
;
1932 /***********************************************************************
1933 * NtCreateSection (NTDLL.@)
1935 NTSTATUS WINAPI
NtCreateSection( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
1936 const LARGE_INTEGER
*size
, ULONG protect
,
1937 ULONG sec_flags
, HANDLE file
)
1940 unsigned int file_access
;
1942 struct object_attributes
*objattr
;
1946 switch (protect
& 0xff)
1949 case PAGE_EXECUTE_READ
:
1950 case PAGE_WRITECOPY
:
1951 case PAGE_EXECUTE_WRITECOPY
:
1952 file_access
= FILE_READ_DATA
;
1954 case PAGE_READWRITE
:
1955 case PAGE_EXECUTE_READWRITE
:
1956 if (sec_flags
& SEC_IMAGE
) file_access
= FILE_READ_DATA
;
1957 else file_access
= FILE_READ_DATA
| FILE_WRITE_DATA
;
1964 return STATUS_INVALID_PAGE_PROTECTION
;
1967 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
1969 SERVER_START_REQ( create_mapping
)
1971 req
->access
= access
;
1972 req
->flags
= sec_flags
;
1973 req
->file_handle
= wine_server_obj_handle( file
);
1974 req
->file_access
= file_access
;
1975 req
->size
= size
? size
->QuadPart
: 0;
1976 wine_server_add_data( req
, objattr
, len
);
1977 ret
= wine_server_call( req
);
1978 *handle
= wine_server_ptr_handle( reply
->handle
);
1987 /***********************************************************************
1988 * NtOpenSection (NTDLL.@)
1990 NTSTATUS WINAPI
NtOpenSection( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
1995 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
1997 SERVER_START_REQ( open_mapping
)
1999 req
->access
= access
;
2000 req
->attributes
= attr
->Attributes
;
2001 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
2002 if (attr
->ObjectName
)
2003 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
2004 ret
= wine_server_call( req
);
2005 *handle
= wine_server_ptr_handle( reply
->handle
);
2012 /***********************************************************************
2013 * NtCreatePort (NTDLL.@)
2015 NTSTATUS WINAPI
NtCreatePort( HANDLE
*handle
, OBJECT_ATTRIBUTES
*attr
, ULONG info_len
,
2016 ULONG data_len
, ULONG
*reserved
)
2018 FIXME( "(%p,%p,%u,%u,%p),stub!\n", handle
, attr
, info_len
, data_len
, reserved
);
2019 return STATUS_NOT_IMPLEMENTED
;
2023 /***********************************************************************
2024 * NtConnectPort (NTDLL.@)
2026 NTSTATUS WINAPI
NtConnectPort( HANDLE
*handle
, UNICODE_STRING
*name
, SECURITY_QUALITY_OF_SERVICE
*qos
,
2027 LPC_SECTION_WRITE
*write
, LPC_SECTION_READ
*read
, ULONG
*max_len
,
2028 void *info
, ULONG
*info_len
)
2030 FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p),stub!\n", handle
, debugstr_us(name
), qos
,
2031 write
, read
, max_len
, info
, info_len
);
2032 if (info
&& info_len
) TRACE("msg = %s\n", debugstr_an( info
, *info_len
));
2033 return STATUS_NOT_IMPLEMENTED
;
2037 /***********************************************************************
2038 * NtSecureConnectPort (NTDLL.@)
2040 NTSTATUS WINAPI
NtSecureConnectPort( HANDLE
*handle
, UNICODE_STRING
*name
, SECURITY_QUALITY_OF_SERVICE
*qos
,
2041 LPC_SECTION_WRITE
*write
, PSID sid
, LPC_SECTION_READ
*read
,
2042 ULONG
*max_len
, void *info
, ULONG
*info_len
)
2044 FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p,%p),stub!\n", handle
, debugstr_us(name
), qos
,
2045 write
, sid
, read
, max_len
, info
, info_len
);
2046 return STATUS_NOT_IMPLEMENTED
;
2050 /***********************************************************************
2051 * NtListenPort (NTDLL.@)
2053 NTSTATUS WINAPI
NtListenPort( HANDLE handle
, LPC_MESSAGE
*msg
)
2055 FIXME("(%p,%p),stub!\n", handle
, msg
);
2056 return STATUS_NOT_IMPLEMENTED
;
2060 /***********************************************************************
2061 * NtAcceptConnectPort (NTDLL.@)
2063 NTSTATUS WINAPI
NtAcceptConnectPort( HANDLE
*handle
, ULONG id
, LPC_MESSAGE
*msg
, BOOLEAN accept
,
2064 LPC_SECTION_WRITE
*write
, LPC_SECTION_READ
*read
)
2066 FIXME("(%p,%u,%p,%d,%p,%p),stub!\n", handle
, id
, msg
, accept
, write
, read
);
2067 return STATUS_NOT_IMPLEMENTED
;
2071 /***********************************************************************
2072 * NtCompleteConnectPort (NTDLL.@)
2074 NTSTATUS WINAPI
NtCompleteConnectPort( HANDLE handle
)
2076 FIXME( "(%p),stub!\n", handle
);
2077 return STATUS_NOT_IMPLEMENTED
;
2081 /***********************************************************************
2082 * NtRegisterThreadTerminatePort (NTDLL.@)
2084 NTSTATUS WINAPI
NtRegisterThreadTerminatePort( HANDLE handle
)
2086 FIXME( "(%p),stub!\n", handle
);
2087 return STATUS_NOT_IMPLEMENTED
;
2091 /***********************************************************************
2092 * NtRequestWaitReplyPort (NTDLL.@)
2094 NTSTATUS WINAPI
NtRequestWaitReplyPort( HANDLE handle
, LPC_MESSAGE
*msg_in
, LPC_MESSAGE
*msg_out
)
2096 FIXME( "(%p,%p,%p),stub!\n", handle
, msg_in
, msg_out
);
2098 TRACE("datasize %u msgsize %u type %u ranges %u client %p/%p msgid %lu size %lu data %s\n",
2099 msg_in
->DataSize
, msg_in
->MessageSize
, msg_in
->MessageType
, msg_in
->VirtualRangesOffset
,
2100 msg_in
->ClientId
.UniqueProcess
, msg_in
->ClientId
.UniqueThread
, msg_in
->MessageId
,
2101 msg_in
->SectionSize
, debugstr_an( (const char *)msg_in
->Data
, msg_in
->DataSize
));
2102 return STATUS_NOT_IMPLEMENTED
;
2106 /***********************************************************************
2107 * NtReplyWaitReceivePort (NTDLL.@)
2109 NTSTATUS WINAPI
NtReplyWaitReceivePort( HANDLE handle
, ULONG
*id
, LPC_MESSAGE
*reply
, LPC_MESSAGE
*msg
)
2111 FIXME("(%p,%p,%p,%p),stub!\n", handle
, id
, reply
, msg
);
2112 return STATUS_NOT_IMPLEMENTED
;
2116 #define MAX_ATOM_LEN 255
2117 #define IS_INTATOM(x) (((ULONG_PTR)(x) >> 16) == 0)
2119 static NTSTATUS
is_integral_atom( const WCHAR
*atomstr
, ULONG len
, RTL_ATOM
*ret_atom
)
2123 if ((ULONG_PTR
)atomstr
>> 16)
2125 const WCHAR
* ptr
= atomstr
;
2126 if (!len
) return STATUS_OBJECT_NAME_INVALID
;
2131 while (ptr
< atomstr
+ len
&& *ptr
>= '0' && *ptr
<= '9')
2133 atom
= atom
* 10 + *ptr
++ - '0';
2135 if (ptr
> atomstr
+ 1 && ptr
== atomstr
+ len
) goto done
;
2137 if (len
> MAX_ATOM_LEN
) return STATUS_INVALID_PARAMETER
;
2138 return STATUS_MORE_ENTRIES
;
2140 else atom
= LOWORD( atomstr
);
2142 if (!atom
|| atom
>= MAXINTATOM
) return STATUS_INVALID_PARAMETER
;
2144 return STATUS_SUCCESS
;
2147 static ULONG
integral_atom_name( WCHAR
*buffer
, ULONG len
, RTL_ATOM atom
)
2150 int ret
= sprintf( tmp
, "#%u", atom
);
2152 len
/= sizeof(WCHAR
);
2155 if (len
<= ret
) ret
= len
- 1;
2156 ascii_to_unicode( buffer
, tmp
, ret
);
2159 return ret
* sizeof(WCHAR
);
2163 /***********************************************************************
2164 * NtAddAtom (NTDLL.@)
2166 NTSTATUS WINAPI
NtAddAtom( const WCHAR
*name
, ULONG length
, RTL_ATOM
*atom
)
2168 NTSTATUS status
= is_integral_atom( name
, length
/ sizeof(WCHAR
), atom
);
2170 if (status
== STATUS_MORE_ENTRIES
)
2172 SERVER_START_REQ( add_atom
)
2174 wine_server_add_data( req
, name
, length
);
2175 status
= wine_server_call( req
);
2176 *atom
= reply
->atom
;
2180 TRACE( "%s -> %x\n", debugstr_wn(name
, length
/sizeof(WCHAR
)), status
== STATUS_SUCCESS
? *atom
: 0 );
2185 /***********************************************************************
2186 * NtDeleteAtom (NTDLL.@)
2188 NTSTATUS WINAPI
NtDeleteAtom( RTL_ATOM atom
)
2192 SERVER_START_REQ( delete_atom
)
2195 status
= wine_server_call( req
);
2202 /***********************************************************************
2203 * NtFindAtom (NTDLL.@)
2205 NTSTATUS WINAPI
NtFindAtom( const WCHAR
*name
, ULONG length
, RTL_ATOM
*atom
)
2207 NTSTATUS status
= is_integral_atom( name
, length
/ sizeof(WCHAR
), atom
);
2209 if (status
== STATUS_MORE_ENTRIES
)
2211 SERVER_START_REQ( find_atom
)
2213 wine_server_add_data( req
, name
, length
);
2214 status
= wine_server_call( req
);
2215 *atom
= reply
->atom
;
2219 TRACE( "%s -> %x\n", debugstr_wn(name
, length
/sizeof(WCHAR
)), status
== STATUS_SUCCESS
? *atom
: 0 );
2224 /***********************************************************************
2225 * NtQueryInformationAtom (NTDLL.@)
2227 NTSTATUS WINAPI
NtQueryInformationAtom( RTL_ATOM atom
, ATOM_INFORMATION_CLASS
class,
2228 void *ptr
, ULONG size
, ULONG
*retsize
)
2234 case AtomBasicInformation
:
2237 ATOM_BASIC_INFORMATION
*abi
= ptr
;
2239 if (size
< sizeof(ATOM_BASIC_INFORMATION
)) return STATUS_INVALID_PARAMETER
;
2240 name_len
= size
- sizeof(ATOM_BASIC_INFORMATION
);
2242 if (atom
< MAXINTATOM
)
2246 abi
->NameLength
= integral_atom_name( abi
->Name
, name_len
, atom
);
2247 status
= name_len
? STATUS_SUCCESS
: STATUS_BUFFER_TOO_SMALL
;
2248 abi
->ReferenceCount
= 1;
2251 else status
= STATUS_INVALID_PARAMETER
;
2255 SERVER_START_REQ( get_atom_information
)
2258 if (name_len
) wine_server_set_reply( req
, abi
->Name
, name_len
);
2259 status
= wine_server_call( req
);
2260 if (status
== STATUS_SUCCESS
)
2262 name_len
= wine_server_reply_size( reply
);
2265 abi
->NameLength
= name_len
;
2266 abi
->Name
[name_len
/ sizeof(WCHAR
)] = 0;
2270 name_len
= reply
->total
;
2271 abi
->NameLength
= name_len
;
2272 status
= STATUS_BUFFER_TOO_SMALL
;
2274 abi
->ReferenceCount
= reply
->count
;
2275 abi
->Pinned
= reply
->pinned
;
2281 TRACE( "%x -> %s (%u)\n", atom
, debugstr_wn(abi
->Name
, abi
->NameLength
/ sizeof(WCHAR
)), status
);
2282 if (retsize
) *retsize
= sizeof(ATOM_BASIC_INFORMATION
) + name_len
;
2287 FIXME( "Unsupported class %u\n", class );
2288 status
= STATUS_INVALID_INFO_CLASS
;
2297 NTSTATUS CDECL
fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION
*crit
, int timeout
)
2300 struct timespec timespec
;
2302 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2304 timespec
.tv_sec
= timeout
;
2305 timespec
.tv_nsec
= 0;
2306 while ((val
= InterlockedCompareExchange( (int *)&crit
->LockSemaphore
, 0, 1 )) != 1)
2308 /* note: this may wait longer than specified in case of signals or */
2309 /* multiple wake-ups, but that shouldn't be a problem */
2310 if (futex_wait( (int *)&crit
->LockSemaphore
, val
, ×pec
) == -1 && errno
== ETIMEDOUT
)
2311 return STATUS_TIMEOUT
;
2313 return STATUS_WAIT_0
;
2316 NTSTATUS CDECL
fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION
*crit
)
2318 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2320 *(int *)&crit
->LockSemaphore
= 1;
2321 futex_wake( (int *)&crit
->LockSemaphore
, 1 );
2322 return STATUS_SUCCESS
;
2325 NTSTATUS CDECL
fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION
*crit
)
2327 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2328 return STATUS_SUCCESS
;
2331 #elif defined(__APPLE__)
2333 static inline semaphore_t
get_mach_semaphore( RTL_CRITICAL_SECTION
*crit
)
2335 semaphore_t ret
= *(int *)&crit
->LockSemaphore
;
2339 if (semaphore_create( mach_task_self(), &sem
, SYNC_POLICY_FIFO
, 0 )) return 0;
2340 if (!(ret
= InterlockedCompareExchange( (int *)&crit
->LockSemaphore
, sem
, 0 )))
2343 semaphore_destroy( mach_task_self(), sem
); /* somebody beat us to it */
2348 NTSTATUS CDECL
fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION
*crit
, int timeout
)
2350 mach_timespec_t timespec
;
2351 semaphore_t sem
= get_mach_semaphore( crit
);
2353 timespec
.tv_sec
= timeout
;
2354 timespec
.tv_nsec
= 0;
2357 switch( semaphore_timedwait( sem
, timespec
))
2360 return STATUS_WAIT_0
;
2362 continue; /* got a signal, restart */
2363 case KERN_OPERATION_TIMED_OUT
:
2364 return STATUS_TIMEOUT
;
2366 return STATUS_INVALID_HANDLE
;
2371 NTSTATUS CDECL
fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION
*crit
)
2373 semaphore_t sem
= get_mach_semaphore( crit
);
2374 semaphore_signal( sem
);
2375 return STATUS_SUCCESS
;
2378 NTSTATUS CDECL
fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION
*crit
)
2380 semaphore_destroy( mach_task_self(), *(int *)&crit
->LockSemaphore
);
2381 return STATUS_SUCCESS
;
2384 #else /* __APPLE__ */
2386 NTSTATUS CDECL
fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION
*crit
, int timeout
)
2388 return STATUS_NOT_IMPLEMENTED
;
2391 NTSTATUS CDECL
fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION
*crit
)
2393 return STATUS_NOT_IMPLEMENTED
;
2396 NTSTATUS CDECL
fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION
*crit
)
2398 return STATUS_NOT_IMPLEMENTED
;
2406 /* Futex-based SRW lock implementation:
2408 * Since we can rely on the kernel to release all threads and don't need to
2409 * worry about NtReleaseKeyedEvent(), we can simplify the layout a bit. The
2410 * layout looks like this:
2412 * 31 - Exclusive lock bit, set if the resource is owned exclusively.
2413 * 30-16 - Number of exclusive waiters. Unlike the fallback implementation,
2414 * this does not include the thread owning the lock, or shared threads
2415 * waiting on the lock.
2416 * 15 - Does this lock have any shared waiters? We use this as an
2417 * optimization to avoid unnecessary FUTEX_WAKE_BITSET calls when
2418 * releasing an exclusive lock.
2419 * 14-0 - Number of shared owners. Unlike the fallback implementation, this
2420 * does not include the number of shared threads waiting on the lock.
2421 * Thus the state [1, x, >=1] will never occur.
2424 #define SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT 0x80000000
2425 #define SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK 0x7fff0000
2426 #define SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC 0x00010000
2427 #define SRWLOCK_FUTEX_SHARED_WAITERS_BIT 0x00008000
2428 #define SRWLOCK_FUTEX_SHARED_OWNERS_MASK 0x00007fff
2429 #define SRWLOCK_FUTEX_SHARED_OWNERS_INC 0x00000001
2431 /* Futex bitmasks; these are independent from the bits in the lock itself. */
2432 #define SRWLOCK_FUTEX_BITSET_EXCLUSIVE 1
2433 #define SRWLOCK_FUTEX_BITSET_SHARED 2
2435 NTSTATUS CDECL
fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK
*lock
)
2437 int old
, new, *futex
;
2440 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2442 if (!(futex
= get_futex( &lock
->Ptr
)))
2443 return STATUS_NOT_IMPLEMENTED
;
2449 if (!(old
& SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
)
2450 && !(old
& SRWLOCK_FUTEX_SHARED_OWNERS_MASK
))
2452 /* Not locked exclusive or shared. We can try to grab it. */
2453 new = old
| SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
;
2454 ret
= STATUS_SUCCESS
;
2459 ret
= STATUS_TIMEOUT
;
2461 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2466 NTSTATUS CDECL
fast_RtlAcquireSRWLockExclusive( RTL_SRWLOCK
*lock
)
2468 int old
, new, *futex
;
2471 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2473 if (!(futex
= get_futex( &lock
->Ptr
)))
2474 return STATUS_NOT_IMPLEMENTED
;
2476 /* Atomically increment the exclusive waiter count. */
2480 new = old
+ SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC
;
2481 assert(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
);
2482 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2490 if (!(old
& SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
)
2491 && !(old
& SRWLOCK_FUTEX_SHARED_OWNERS_MASK
))
2493 /* Not locked exclusive or shared. We can try to grab it. */
2494 new = old
| SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
;
2495 assert(old
& SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
);
2496 new -= SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC
;
2504 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2507 return STATUS_SUCCESS
;
2509 futex_wait_bitset( futex
, new, NULL
, SRWLOCK_FUTEX_BITSET_EXCLUSIVE
);
2512 return STATUS_SUCCESS
;
2515 NTSTATUS CDECL
fast_RtlTryAcquireSRWLockShared( RTL_SRWLOCK
*lock
)
2517 int new, old
, *futex
;
2520 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2522 if (!(futex
= get_futex( &lock
->Ptr
)))
2523 return STATUS_NOT_IMPLEMENTED
;
2529 if (!(old
& SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
)
2530 && !(old
& SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
))
2532 /* Not locked exclusive, and no exclusive waiters. We can try to
2534 new = old
+ SRWLOCK_FUTEX_SHARED_OWNERS_INC
;
2535 assert(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK
);
2536 ret
= STATUS_SUCCESS
;
2541 ret
= STATUS_TIMEOUT
;
2543 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2548 NTSTATUS CDECL
fast_RtlAcquireSRWLockShared( RTL_SRWLOCK
*lock
)
2550 int old
, new, *futex
;
2553 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2555 if (!(futex
= get_futex( &lock
->Ptr
)))
2556 return STATUS_NOT_IMPLEMENTED
;
2564 if (!(old
& SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
)
2565 && !(old
& SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
))
2567 /* Not locked exclusive, and no exclusive waiters. We can try
2569 new = old
+ SRWLOCK_FUTEX_SHARED_OWNERS_INC
;
2570 assert(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK
);
2575 new = old
| SRWLOCK_FUTEX_SHARED_WAITERS_BIT
;
2578 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2581 return STATUS_SUCCESS
;
2583 futex_wait_bitset( futex
, new, NULL
, SRWLOCK_FUTEX_BITSET_SHARED
);
2586 return STATUS_SUCCESS
;
2589 NTSTATUS CDECL
fast_RtlReleaseSRWLockExclusive( RTL_SRWLOCK
*lock
)
2591 int old
, new, *futex
;
2593 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2595 if (!(futex
= get_futex( &lock
->Ptr
)))
2596 return STATUS_NOT_IMPLEMENTED
;
2602 if (!(old
& SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
))
2604 ERR("Lock %p is not owned exclusive! (%#x)\n", lock
, *futex
);
2605 return STATUS_RESOURCE_NOT_OWNED
;
2608 new = old
& ~SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
;
2610 if (!(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
))
2611 new &= ~SRWLOCK_FUTEX_SHARED_WAITERS_BIT
;
2612 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2614 if (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
)
2615 futex_wake_bitset( futex
, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE
);
2616 else if (old
& SRWLOCK_FUTEX_SHARED_WAITERS_BIT
)
2617 futex_wake_bitset( futex
, INT_MAX
, SRWLOCK_FUTEX_BITSET_SHARED
);
2619 return STATUS_SUCCESS
;
2622 NTSTATUS CDECL
fast_RtlReleaseSRWLockShared( RTL_SRWLOCK
*lock
)
2624 int old
, new, *futex
;
2626 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2628 if (!(futex
= get_futex( &lock
->Ptr
)))
2629 return STATUS_NOT_IMPLEMENTED
;
2635 if (old
& SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
)
2637 ERR("Lock %p is owned exclusive! (%#x)\n", lock
, *futex
);
2638 return STATUS_RESOURCE_NOT_OWNED
;
2640 else if (!(old
& SRWLOCK_FUTEX_SHARED_OWNERS_MASK
))
2642 ERR("Lock %p is not owned shared! (%#x)\n", lock
, *futex
);
2643 return STATUS_RESOURCE_NOT_OWNED
;
2646 new = old
- SRWLOCK_FUTEX_SHARED_OWNERS_INC
;
2647 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2649 /* Optimization: only bother waking if there are actually exclusive waiters. */
2650 if (!(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK
) && (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
))
2651 futex_wake_bitset( futex
, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE
);
2653 return STATUS_SUCCESS
;
2656 NTSTATUS CDECL
fast_wait_cv( RTL_CONDITION_VARIABLE
*variable
, const void *value
, const LARGE_INTEGER
*timeout
)
2658 const char *value_ptr
;
2659 int aligned_value
, *futex
;
2660 struct timespec timespec
;
2664 return STATUS_NOT_IMPLEMENTED
;
2666 if (!(futex
= get_futex( &variable
->Ptr
)))
2667 return STATUS_NOT_IMPLEMENTED
;
2669 value_ptr
= (const char *)&value
;
2670 value_ptr
+= ((ULONG_PTR
)futex
) - ((ULONG_PTR
)&variable
->Ptr
);
2671 aligned_value
= *(int *)value_ptr
;
2673 if (timeout
&& timeout
->QuadPart
!= TIMEOUT_INFINITE
)
2675 timespec_from_timeout( ×pec
, timeout
);
2676 ret
= futex_wait( futex
, aligned_value
, ×pec
);
2679 ret
= futex_wait( futex
, aligned_value
, NULL
);
2681 if (ret
== -1 && errno
== ETIMEDOUT
)
2682 return STATUS_TIMEOUT
;
2683 return STATUS_WAIT_0
;
2686 NTSTATUS CDECL
fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE
*variable
, int count
)
2690 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2692 if (!(futex
= get_futex( &variable
->Ptr
)))
2693 return STATUS_NOT_IMPLEMENTED
;
2695 InterlockedIncrement( futex
);
2696 futex_wake( futex
, count
);
2697 return STATUS_SUCCESS
;
2701 /* We can't map addresses to futex directly, because an application can wait on
2702 * 8 bytes, and we can't pass all 8 as the compare value to futex(). Instead we
2703 * map all addresses to a small fixed table of futexes. This may result in
2704 * spurious wakes, but the application is already expected to handle those. */
2706 static int addr_futex_table
[256];
2708 static inline int *hash_addr( const void *addr
)
2710 ULONG_PTR val
= (ULONG_PTR
)addr
;
2712 return &addr_futex_table
[(val
>> 2) & 255];
2715 static inline NTSTATUS
fast_wait_addr( const void *addr
, const void *cmp
, SIZE_T size
,
2716 const LARGE_INTEGER
*timeout
)
2720 struct timespec timespec
;
2724 return STATUS_NOT_IMPLEMENTED
;
2726 futex
= hash_addr( addr
);
2728 /* We must read the previous value of the futex before checking the value
2729 * of the address being waited on. That way, if we receive a wake between
2730 * now and waiting on the futex, we know that val will have changed.
2731 * Use an atomic load so that memory accesses are ordered between this read
2732 * and the increment below. */
2733 val
= InterlockedCompareExchange( futex
, 0, 0 );
2734 if (!compare_addr( addr
, cmp
, size
))
2735 return STATUS_SUCCESS
;
2739 timespec_from_timeout( ×pec
, timeout
);
2740 ret
= futex_wait( futex
, val
, ×pec
);
2743 ret
= futex_wait( futex
, val
, NULL
);
2745 if (ret
== -1 && errno
== ETIMEDOUT
)
2746 return STATUS_TIMEOUT
;
2747 return STATUS_SUCCESS
;
2750 static inline NTSTATUS
fast_wake_addr( const void *addr
)
2755 return STATUS_NOT_IMPLEMENTED
;
2757 futex
= hash_addr( addr
);
2759 InterlockedIncrement( futex
);
2761 futex_wake( futex
, INT_MAX
);
2762 return STATUS_SUCCESS
;
2767 NTSTATUS CDECL
fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK
*lock
)
2769 return STATUS_NOT_IMPLEMENTED
;
2772 NTSTATUS CDECL
fast_RtlAcquireSRWLockExclusive( RTL_SRWLOCK
*lock
)
2774 return STATUS_NOT_IMPLEMENTED
;
2777 NTSTATUS CDECL
fast_RtlTryAcquireSRWLockShared( RTL_SRWLOCK
*lock
)
2779 return STATUS_NOT_IMPLEMENTED
;
2782 NTSTATUS CDECL
fast_RtlAcquireSRWLockShared( RTL_SRWLOCK
*lock
)
2784 return STATUS_NOT_IMPLEMENTED
;
2787 NTSTATUS CDECL
fast_RtlReleaseSRWLockExclusive( RTL_SRWLOCK
*lock
)
2789 return STATUS_NOT_IMPLEMENTED
;
2792 NTSTATUS CDECL
fast_RtlReleaseSRWLockShared( RTL_SRWLOCK
*lock
)
2794 return STATUS_NOT_IMPLEMENTED
;
2797 NTSTATUS CDECL
fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE
*variable
, int count
)
2799 return STATUS_NOT_IMPLEMENTED
;
2802 NTSTATUS CDECL
fast_wait_cv( RTL_CONDITION_VARIABLE
*variable
, const void *value
, const LARGE_INTEGER
*timeout
)
2804 return STATUS_NOT_IMPLEMENTED
;
2807 static inline NTSTATUS
fast_wait_addr( const void *addr
, const void *cmp
, SIZE_T size
,
2808 const LARGE_INTEGER
*timeout
)
2810 return STATUS_NOT_IMPLEMENTED
;
2813 static inline NTSTATUS
fast_wake_addr( const void *addr
)
2815 return STATUS_NOT_IMPLEMENTED
;
2821 /***********************************************************************
2822 * RtlWaitOnAddress (NTDLL.@)
2824 NTSTATUS WINAPI
RtlWaitOnAddress( const void *addr
, const void *cmp
, SIZE_T size
,
2825 const LARGE_INTEGER
*timeout
)
2827 select_op_t select_op
;
2829 timeout_t abs_timeout
= timeout
? timeout
->QuadPart
: TIMEOUT_INFINITE
;
2831 if (size
!= 1 && size
!= 2 && size
!= 4 && size
!= 8)
2832 return STATUS_INVALID_PARAMETER
;
2834 if ((ret
= fast_wait_addr( addr
, cmp
, size
, timeout
)) != STATUS_NOT_IMPLEMENTED
)
2837 mutex_lock( &addr_mutex
);
2838 if (!compare_addr( addr
, cmp
, size
))
2840 mutex_unlock( &addr_mutex
);
2841 return STATUS_SUCCESS
;
2844 if (abs_timeout
< 0)
2848 NtQueryPerformanceCounter( &now
, NULL
);
2849 abs_timeout
-= now
.QuadPart
;
2852 select_op
.keyed_event
.op
= SELECT_KEYED_EVENT_WAIT
;
2853 select_op
.keyed_event
.handle
= wine_server_obj_handle( keyed_event
);
2854 select_op
.keyed_event
.key
= wine_server_client_ptr( addr
);
2856 return server_select( &select_op
, sizeof(select_op
.keyed_event
), SELECT_INTERRUPTIBLE
,
2857 abs_timeout
, NULL
, &addr_mutex
, NULL
);
2860 /***********************************************************************
2861 * RtlWakeAddressAll (NTDLL.@)
2863 void WINAPI
RtlWakeAddressAll( const void *addr
)
2865 if (fast_wake_addr( addr
) != STATUS_NOT_IMPLEMENTED
) return;
2867 mutex_lock( &addr_mutex
);
2868 while (NtReleaseKeyedEvent( 0, addr
, 0, &zero_timeout
) == STATUS_SUCCESS
) {}
2869 mutex_unlock( &addr_mutex
);
2872 /***********************************************************************
2873 * RtlWakeAddressSingle (NTDLL.@)
2875 void WINAPI
RtlWakeAddressSingle( const void *addr
)
2877 if (fast_wake_addr( addr
) != STATUS_NOT_IMPLEMENTED
) return;
2879 mutex_lock( &addr_mutex
);
2880 NtReleaseKeyedEvent( 0, addr
, 0, &zero_timeout
);
2881 mutex_unlock( &addr_mutex
);