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 TRACE( "(%p,%p,%p)\n", min_res
, max_res
, current_res
);
1603 *max_res
= *current_res
= 10000; /* See NtSetTimerResolution() */
1605 return STATUS_SUCCESS
;
1609 /***********************************************************************
1610 * NtSetTimerResolution (NTDLL.@)
1612 NTSTATUS WINAPI
NtSetTimerResolution( ULONG res
, BOOLEAN set
, ULONG
*current_res
)
1614 static BOOL has_request
= FALSE
;
1616 TRACE( "(%u,%u,%p), semi-stub!\n", res
, set
, current_res
);
1618 /* Wine has no support for anything other that 1 ms and does not keep of
1619 * track resolution requests anyway.
1620 * Fortunately NtSetTimerResolution() should ignore requests to lower the
1621 * timer resolution. So by claiming that 'some other process' requested the
1622 * max resolution already, there no need to actually change it.
1624 *current_res
= 10000;
1626 /* Just keep track of whether this process requested a specific timer
1629 if (!has_request
&& !set
)
1630 return STATUS_TIMER_RESOLUTION_NOT_SET
;
1633 return STATUS_SUCCESS
;
1637 /******************************************************************************
1638 * NtSetIntervalProfile (NTDLL.@)
1640 NTSTATUS WINAPI
NtSetIntervalProfile( ULONG interval
, KPROFILE_SOURCE source
)
1642 FIXME( "%u,%d\n", interval
, source
);
1643 return STATUS_SUCCESS
;
1647 /******************************************************************************
1648 * NtGetTickCount (NTDLL.@)
1650 ULONG WINAPI
NtGetTickCount(void)
1652 /* note: we ignore TickCountMultiplier */
1653 return user_shared_data
->u
.TickCount
.LowPart
;
1657 /******************************************************************************
1658 * RtlGetSystemTimePrecise (NTDLL.@)
1660 LONGLONG WINAPI
RtlGetSystemTimePrecise(void)
1663 #ifdef HAVE_CLOCK_GETTIME
1666 if (!clock_gettime( CLOCK_REALTIME
, &ts
))
1667 return ticks_from_time_t( ts
.tv_sec
) + (ts
.tv_nsec
+ 50) / 100;
1669 gettimeofday( &now
, 0 );
1670 return ticks_from_time_t( now
.tv_sec
) + now
.tv_usec
* 10;
1674 /******************************************************************************
1675 * NtCreateKeyedEvent (NTDLL.@)
1677 NTSTATUS WINAPI
NtCreateKeyedEvent( HANDLE
*handle
, ACCESS_MASK access
,
1678 const OBJECT_ATTRIBUTES
*attr
, ULONG flags
)
1682 struct object_attributes
*objattr
;
1685 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
1687 SERVER_START_REQ( create_keyed_event
)
1689 req
->access
= access
;
1690 wine_server_add_data( req
, objattr
, len
);
1691 ret
= wine_server_call( req
);
1692 *handle
= wine_server_ptr_handle( reply
->handle
);
1701 /******************************************************************************
1702 * NtOpenKeyedEvent (NTDLL.@)
1704 NTSTATUS WINAPI
NtOpenKeyedEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
1709 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
1711 SERVER_START_REQ( open_keyed_event
)
1713 req
->access
= access
;
1714 req
->attributes
= attr
->Attributes
;
1715 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
1716 if (attr
->ObjectName
)
1717 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
1718 ret
= wine_server_call( req
);
1719 *handle
= wine_server_ptr_handle( reply
->handle
);
1725 /******************************************************************************
1726 * NtWaitForKeyedEvent (NTDLL.@)
1728 NTSTATUS WINAPI
NtWaitForKeyedEvent( HANDLE handle
, const void *key
,
1729 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1731 select_op_t select_op
;
1732 UINT flags
= SELECT_INTERRUPTIBLE
;
1734 if (!handle
) handle
= keyed_event
;
1735 if ((ULONG_PTR
)key
& 1) return STATUS_INVALID_PARAMETER_1
;
1736 if (alertable
) flags
|= SELECT_ALERTABLE
;
1737 select_op
.keyed_event
.op
= SELECT_KEYED_EVENT_WAIT
;
1738 select_op
.keyed_event
.handle
= wine_server_obj_handle( handle
);
1739 select_op
.keyed_event
.key
= wine_server_client_ptr( key
);
1740 return server_wait( &select_op
, sizeof(select_op
.keyed_event
), flags
, timeout
);
1744 /******************************************************************************
1745 * NtReleaseKeyedEvent (NTDLL.@)
1747 NTSTATUS WINAPI
NtReleaseKeyedEvent( HANDLE handle
, const void *key
,
1748 BOOLEAN alertable
, const LARGE_INTEGER
*timeout
)
1750 select_op_t select_op
;
1751 UINT flags
= SELECT_INTERRUPTIBLE
;
1753 if (!handle
) handle
= keyed_event
;
1754 if ((ULONG_PTR
)key
& 1) return STATUS_INVALID_PARAMETER_1
;
1755 if (alertable
) flags
|= SELECT_ALERTABLE
;
1756 select_op
.keyed_event
.op
= SELECT_KEYED_EVENT_RELEASE
;
1757 select_op
.keyed_event
.handle
= wine_server_obj_handle( handle
);
1758 select_op
.keyed_event
.key
= wine_server_client_ptr( key
);
1759 return server_wait( &select_op
, sizeof(select_op
.keyed_event
), flags
, timeout
);
1763 /***********************************************************************
1764 * NtCreateIoCompletion (NTDLL.@)
1766 NTSTATUS WINAPI
NtCreateIoCompletion( HANDLE
*handle
, ACCESS_MASK access
, OBJECT_ATTRIBUTES
*attr
,
1771 struct object_attributes
*objattr
;
1773 TRACE( "(%p, %x, %p, %d)\n", handle
, access
, attr
, threads
);
1776 if ((status
= alloc_object_attributes( attr
, &objattr
, &len
))) return status
;
1778 SERVER_START_REQ( create_completion
)
1780 req
->access
= access
;
1781 req
->concurrent
= threads
;
1782 wine_server_add_data( req
, objattr
, len
);
1783 if (!(status
= wine_server_call( req
))) *handle
= wine_server_ptr_handle( reply
->handle
);
1792 /***********************************************************************
1793 * NtOpenIoCompletion (NTDLL.@)
1795 NTSTATUS WINAPI
NtOpenIoCompletion( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
1800 if ((status
= validate_open_object_attributes( attr
))) return status
;
1802 SERVER_START_REQ( open_completion
)
1804 req
->access
= access
;
1805 req
->attributes
= attr
->Attributes
;
1806 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
1807 if (attr
->ObjectName
)
1808 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
1809 status
= wine_server_call( req
);
1810 *handle
= wine_server_ptr_handle( reply
->handle
);
1817 /***********************************************************************
1818 * NtSetIoCompletion (NTDLL.@)
1820 NTSTATUS WINAPI
NtSetIoCompletion( HANDLE handle
, ULONG_PTR key
, ULONG_PTR value
,
1821 NTSTATUS status
, SIZE_T count
)
1825 TRACE( "(%p, %lx, %lx, %x, %lx)\n", handle
, key
, value
, status
, count
);
1827 SERVER_START_REQ( add_completion
)
1829 req
->handle
= wine_server_obj_handle( handle
);
1831 req
->cvalue
= value
;
1832 req
->status
= status
;
1833 req
->information
= count
;
1834 ret
= wine_server_call( req
);
1841 /***********************************************************************
1842 * NtRemoveIoCompletion (NTDLL.@)
1844 NTSTATUS WINAPI
NtRemoveIoCompletion( HANDLE handle
, ULONG_PTR
*key
, ULONG_PTR
*value
,
1845 IO_STATUS_BLOCK
*io
, LARGE_INTEGER
*timeout
)
1849 TRACE( "(%p, %p, %p, %p, %p)\n", handle
, key
, value
, io
, timeout
);
1853 SERVER_START_REQ( remove_completion
)
1855 req
->handle
= wine_server_obj_handle( handle
);
1856 if (!(status
= wine_server_call( req
)))
1859 *value
= reply
->cvalue
;
1860 io
->Information
= reply
->information
;
1861 io
->u
.Status
= reply
->status
;
1865 if (status
!= STATUS_PENDING
) return status
;
1866 status
= NtWaitForSingleObject( handle
, FALSE
, timeout
);
1867 if (status
!= WAIT_OBJECT_0
) return status
;
1872 /***********************************************************************
1873 * NtRemoveIoCompletionEx (NTDLL.@)
1875 NTSTATUS WINAPI
NtRemoveIoCompletionEx( HANDLE handle
, FILE_IO_COMPLETION_INFORMATION
*info
, ULONG count
,
1876 ULONG
*written
, LARGE_INTEGER
*timeout
, BOOLEAN alertable
)
1881 TRACE( "%p %p %u %p %p %u\n", handle
, info
, count
, written
, timeout
, alertable
);
1887 SERVER_START_REQ( remove_completion
)
1889 req
->handle
= wine_server_obj_handle( handle
);
1890 if (!(status
= wine_server_call( req
)))
1892 info
[i
].CompletionKey
= reply
->ckey
;
1893 info
[i
].CompletionValue
= reply
->cvalue
;
1894 info
[i
].IoStatusBlock
.Information
= reply
->information
;
1895 info
[i
].IoStatusBlock
.u
.Status
= reply
->status
;
1899 if (status
!= STATUS_SUCCESS
) break;
1902 if (i
|| status
!= STATUS_PENDING
)
1904 if (status
== STATUS_PENDING
) status
= STATUS_SUCCESS
;
1907 status
= NtWaitForSingleObject( handle
, alertable
, timeout
);
1908 if (status
!= WAIT_OBJECT_0
) break;
1910 *written
= i
? i
: 1;
1915 /***********************************************************************
1916 * NtQueryIoCompletion (NTDLL.@)
1918 NTSTATUS WINAPI
NtQueryIoCompletion( HANDLE handle
, IO_COMPLETION_INFORMATION_CLASS
class,
1919 void *buffer
, ULONG len
, ULONG
*ret_len
)
1923 TRACE( "(%p, %d, %p, 0x%x, %p)\n", handle
, class, buffer
, len
, ret_len
);
1925 if (!buffer
) return STATUS_INVALID_PARAMETER
;
1929 case IoCompletionBasicInformation
:
1931 ULONG
*info
= buffer
;
1932 if (ret_len
) *ret_len
= sizeof(*info
);
1933 if (len
== sizeof(*info
))
1935 SERVER_START_REQ( query_completion
)
1937 req
->handle
= wine_server_obj_handle( handle
);
1938 if (!(status
= wine_server_call( req
))) *info
= reply
->depth
;
1942 else status
= STATUS_INFO_LENGTH_MISMATCH
;
1946 return STATUS_INVALID_PARAMETER
;
1952 /***********************************************************************
1953 * NtCreateSection (NTDLL.@)
1955 NTSTATUS WINAPI
NtCreateSection( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
1956 const LARGE_INTEGER
*size
, ULONG protect
,
1957 ULONG sec_flags
, HANDLE file
)
1960 unsigned int file_access
;
1962 struct object_attributes
*objattr
;
1966 switch (protect
& 0xff)
1969 case PAGE_EXECUTE_READ
:
1970 case PAGE_WRITECOPY
:
1971 case PAGE_EXECUTE_WRITECOPY
:
1972 file_access
= FILE_READ_DATA
;
1974 case PAGE_READWRITE
:
1975 case PAGE_EXECUTE_READWRITE
:
1976 if (sec_flags
& SEC_IMAGE
) file_access
= FILE_READ_DATA
;
1977 else file_access
= FILE_READ_DATA
| FILE_WRITE_DATA
;
1984 return STATUS_INVALID_PAGE_PROTECTION
;
1987 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
1989 SERVER_START_REQ( create_mapping
)
1991 req
->access
= access
;
1992 req
->flags
= sec_flags
;
1993 req
->file_handle
= wine_server_obj_handle( file
);
1994 req
->file_access
= file_access
;
1995 req
->size
= size
? size
->QuadPart
: 0;
1996 wine_server_add_data( req
, objattr
, len
);
1997 ret
= wine_server_call( req
);
1998 *handle
= wine_server_ptr_handle( reply
->handle
);
2007 /***********************************************************************
2008 * NtOpenSection (NTDLL.@)
2010 NTSTATUS WINAPI
NtOpenSection( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
2015 if ((ret
= validate_open_object_attributes( attr
))) return ret
;
2017 SERVER_START_REQ( open_mapping
)
2019 req
->access
= access
;
2020 req
->attributes
= attr
->Attributes
;
2021 req
->rootdir
= wine_server_obj_handle( attr
->RootDirectory
);
2022 if (attr
->ObjectName
)
2023 wine_server_add_data( req
, attr
->ObjectName
->Buffer
, attr
->ObjectName
->Length
);
2024 ret
= wine_server_call( req
);
2025 *handle
= wine_server_ptr_handle( reply
->handle
);
2032 /***********************************************************************
2033 * NtCreatePort (NTDLL.@)
2035 NTSTATUS WINAPI
NtCreatePort( HANDLE
*handle
, OBJECT_ATTRIBUTES
*attr
, ULONG info_len
,
2036 ULONG data_len
, ULONG
*reserved
)
2038 FIXME( "(%p,%p,%u,%u,%p),stub!\n", handle
, attr
, info_len
, data_len
, reserved
);
2039 return STATUS_NOT_IMPLEMENTED
;
2043 /***********************************************************************
2044 * NtConnectPort (NTDLL.@)
2046 NTSTATUS WINAPI
NtConnectPort( HANDLE
*handle
, UNICODE_STRING
*name
, SECURITY_QUALITY_OF_SERVICE
*qos
,
2047 LPC_SECTION_WRITE
*write
, LPC_SECTION_READ
*read
, ULONG
*max_len
,
2048 void *info
, ULONG
*info_len
)
2050 FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p),stub!\n", handle
, debugstr_us(name
), qos
,
2051 write
, read
, max_len
, info
, info_len
);
2052 if (info
&& info_len
) TRACE("msg = %s\n", debugstr_an( info
, *info_len
));
2053 return STATUS_NOT_IMPLEMENTED
;
2057 /***********************************************************************
2058 * NtSecureConnectPort (NTDLL.@)
2060 NTSTATUS WINAPI
NtSecureConnectPort( HANDLE
*handle
, UNICODE_STRING
*name
, SECURITY_QUALITY_OF_SERVICE
*qos
,
2061 LPC_SECTION_WRITE
*write
, PSID sid
, LPC_SECTION_READ
*read
,
2062 ULONG
*max_len
, void *info
, ULONG
*info_len
)
2064 FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p,%p),stub!\n", handle
, debugstr_us(name
), qos
,
2065 write
, sid
, read
, max_len
, info
, info_len
);
2066 return STATUS_NOT_IMPLEMENTED
;
2070 /***********************************************************************
2071 * NtListenPort (NTDLL.@)
2073 NTSTATUS WINAPI
NtListenPort( HANDLE handle
, LPC_MESSAGE
*msg
)
2075 FIXME("(%p,%p),stub!\n", handle
, msg
);
2076 return STATUS_NOT_IMPLEMENTED
;
2080 /***********************************************************************
2081 * NtAcceptConnectPort (NTDLL.@)
2083 NTSTATUS WINAPI
NtAcceptConnectPort( HANDLE
*handle
, ULONG id
, LPC_MESSAGE
*msg
, BOOLEAN accept
,
2084 LPC_SECTION_WRITE
*write
, LPC_SECTION_READ
*read
)
2086 FIXME("(%p,%u,%p,%d,%p,%p),stub!\n", handle
, id
, msg
, accept
, write
, read
);
2087 return STATUS_NOT_IMPLEMENTED
;
2091 /***********************************************************************
2092 * NtCompleteConnectPort (NTDLL.@)
2094 NTSTATUS WINAPI
NtCompleteConnectPort( HANDLE handle
)
2096 FIXME( "(%p),stub!\n", handle
);
2097 return STATUS_NOT_IMPLEMENTED
;
2101 /***********************************************************************
2102 * NtRegisterThreadTerminatePort (NTDLL.@)
2104 NTSTATUS WINAPI
NtRegisterThreadTerminatePort( HANDLE handle
)
2106 FIXME( "(%p),stub!\n", handle
);
2107 return STATUS_NOT_IMPLEMENTED
;
2111 /***********************************************************************
2112 * NtRequestWaitReplyPort (NTDLL.@)
2114 NTSTATUS WINAPI
NtRequestWaitReplyPort( HANDLE handle
, LPC_MESSAGE
*msg_in
, LPC_MESSAGE
*msg_out
)
2116 FIXME( "(%p,%p,%p),stub!\n", handle
, msg_in
, msg_out
);
2118 TRACE("datasize %u msgsize %u type %u ranges %u client %p/%p msgid %lu size %lu data %s\n",
2119 msg_in
->DataSize
, msg_in
->MessageSize
, msg_in
->MessageType
, msg_in
->VirtualRangesOffset
,
2120 msg_in
->ClientId
.UniqueProcess
, msg_in
->ClientId
.UniqueThread
, msg_in
->MessageId
,
2121 msg_in
->SectionSize
, debugstr_an( (const char *)msg_in
->Data
, msg_in
->DataSize
));
2122 return STATUS_NOT_IMPLEMENTED
;
2126 /***********************************************************************
2127 * NtReplyWaitReceivePort (NTDLL.@)
2129 NTSTATUS WINAPI
NtReplyWaitReceivePort( HANDLE handle
, ULONG
*id
, LPC_MESSAGE
*reply
, LPC_MESSAGE
*msg
)
2131 FIXME("(%p,%p,%p,%p),stub!\n", handle
, id
, reply
, msg
);
2132 return STATUS_NOT_IMPLEMENTED
;
2136 #define MAX_ATOM_LEN 255
2137 #define IS_INTATOM(x) (((ULONG_PTR)(x) >> 16) == 0)
2139 static NTSTATUS
is_integral_atom( const WCHAR
*atomstr
, ULONG len
, RTL_ATOM
*ret_atom
)
2143 if ((ULONG_PTR
)atomstr
>> 16)
2145 const WCHAR
* ptr
= atomstr
;
2146 if (!len
) return STATUS_OBJECT_NAME_INVALID
;
2151 while (ptr
< atomstr
+ len
&& *ptr
>= '0' && *ptr
<= '9')
2153 atom
= atom
* 10 + *ptr
++ - '0';
2155 if (ptr
> atomstr
+ 1 && ptr
== atomstr
+ len
) goto done
;
2157 if (len
> MAX_ATOM_LEN
) return STATUS_INVALID_PARAMETER
;
2158 return STATUS_MORE_ENTRIES
;
2160 else atom
= LOWORD( atomstr
);
2162 if (!atom
|| atom
>= MAXINTATOM
) return STATUS_INVALID_PARAMETER
;
2164 return STATUS_SUCCESS
;
2167 static ULONG
integral_atom_name( WCHAR
*buffer
, ULONG len
, RTL_ATOM atom
)
2170 int ret
= sprintf( tmp
, "#%u", atom
);
2172 len
/= sizeof(WCHAR
);
2175 if (len
<= ret
) ret
= len
- 1;
2176 ascii_to_unicode( buffer
, tmp
, ret
);
2179 return ret
* sizeof(WCHAR
);
2183 /***********************************************************************
2184 * NtAddAtom (NTDLL.@)
2186 NTSTATUS WINAPI
NtAddAtom( const WCHAR
*name
, ULONG length
, RTL_ATOM
*atom
)
2188 NTSTATUS status
= is_integral_atom( name
, length
/ sizeof(WCHAR
), atom
);
2190 if (status
== STATUS_MORE_ENTRIES
)
2192 SERVER_START_REQ( add_atom
)
2194 wine_server_add_data( req
, name
, length
);
2195 status
= wine_server_call( req
);
2196 *atom
= reply
->atom
;
2200 TRACE( "%s -> %x\n", debugstr_wn(name
, length
/sizeof(WCHAR
)), status
== STATUS_SUCCESS
? *atom
: 0 );
2205 /***********************************************************************
2206 * NtDeleteAtom (NTDLL.@)
2208 NTSTATUS WINAPI
NtDeleteAtom( RTL_ATOM atom
)
2212 SERVER_START_REQ( delete_atom
)
2215 status
= wine_server_call( req
);
2222 /***********************************************************************
2223 * NtFindAtom (NTDLL.@)
2225 NTSTATUS WINAPI
NtFindAtom( const WCHAR
*name
, ULONG length
, RTL_ATOM
*atom
)
2227 NTSTATUS status
= is_integral_atom( name
, length
/ sizeof(WCHAR
), atom
);
2229 if (status
== STATUS_MORE_ENTRIES
)
2231 SERVER_START_REQ( find_atom
)
2233 wine_server_add_data( req
, name
, length
);
2234 status
= wine_server_call( req
);
2235 *atom
= reply
->atom
;
2239 TRACE( "%s -> %x\n", debugstr_wn(name
, length
/sizeof(WCHAR
)), status
== STATUS_SUCCESS
? *atom
: 0 );
2244 /***********************************************************************
2245 * NtQueryInformationAtom (NTDLL.@)
2247 NTSTATUS WINAPI
NtQueryInformationAtom( RTL_ATOM atom
, ATOM_INFORMATION_CLASS
class,
2248 void *ptr
, ULONG size
, ULONG
*retsize
)
2254 case AtomBasicInformation
:
2257 ATOM_BASIC_INFORMATION
*abi
= ptr
;
2259 if (size
< sizeof(ATOM_BASIC_INFORMATION
)) return STATUS_INVALID_PARAMETER
;
2260 name_len
= size
- sizeof(ATOM_BASIC_INFORMATION
);
2262 if (atom
< MAXINTATOM
)
2266 abi
->NameLength
= integral_atom_name( abi
->Name
, name_len
, atom
);
2267 status
= name_len
? STATUS_SUCCESS
: STATUS_BUFFER_TOO_SMALL
;
2268 abi
->ReferenceCount
= 1;
2271 else status
= STATUS_INVALID_PARAMETER
;
2275 SERVER_START_REQ( get_atom_information
)
2278 if (name_len
) wine_server_set_reply( req
, abi
->Name
, name_len
);
2279 status
= wine_server_call( req
);
2280 if (status
== STATUS_SUCCESS
)
2282 name_len
= wine_server_reply_size( reply
);
2285 abi
->NameLength
= name_len
;
2286 abi
->Name
[name_len
/ sizeof(WCHAR
)] = 0;
2290 name_len
= reply
->total
;
2291 abi
->NameLength
= name_len
;
2292 status
= STATUS_BUFFER_TOO_SMALL
;
2294 abi
->ReferenceCount
= reply
->count
;
2295 abi
->Pinned
= reply
->pinned
;
2301 TRACE( "%x -> %s (%u)\n", atom
, debugstr_wn(abi
->Name
, abi
->NameLength
/ sizeof(WCHAR
)), status
);
2302 if (retsize
) *retsize
= sizeof(ATOM_BASIC_INFORMATION
) + name_len
;
2307 FIXME( "Unsupported class %u\n", class );
2308 status
= STATUS_INVALID_INFO_CLASS
;
2317 NTSTATUS CDECL
fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION
*crit
, int timeout
)
2320 struct timespec timespec
;
2322 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2324 timespec
.tv_sec
= timeout
;
2325 timespec
.tv_nsec
= 0;
2326 while ((val
= InterlockedCompareExchange( (int *)&crit
->LockSemaphore
, 0, 1 )) != 1)
2328 /* note: this may wait longer than specified in case of signals or */
2329 /* multiple wake-ups, but that shouldn't be a problem */
2330 if (futex_wait( (int *)&crit
->LockSemaphore
, val
, ×pec
) == -1 && errno
== ETIMEDOUT
)
2331 return STATUS_TIMEOUT
;
2333 return STATUS_WAIT_0
;
2336 NTSTATUS CDECL
fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION
*crit
)
2338 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2340 *(int *)&crit
->LockSemaphore
= 1;
2341 futex_wake( (int *)&crit
->LockSemaphore
, 1 );
2342 return STATUS_SUCCESS
;
2345 NTSTATUS CDECL
fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION
*crit
)
2347 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2348 return STATUS_SUCCESS
;
2351 #elif defined(__APPLE__)
2353 static inline semaphore_t
get_mach_semaphore( RTL_CRITICAL_SECTION
*crit
)
2355 semaphore_t ret
= *(int *)&crit
->LockSemaphore
;
2359 if (semaphore_create( mach_task_self(), &sem
, SYNC_POLICY_FIFO
, 0 )) return 0;
2360 if (!(ret
= InterlockedCompareExchange( (int *)&crit
->LockSemaphore
, sem
, 0 )))
2363 semaphore_destroy( mach_task_self(), sem
); /* somebody beat us to it */
2368 NTSTATUS CDECL
fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION
*crit
, int timeout
)
2370 mach_timespec_t timespec
;
2371 semaphore_t sem
= get_mach_semaphore( crit
);
2373 timespec
.tv_sec
= timeout
;
2374 timespec
.tv_nsec
= 0;
2377 switch( semaphore_timedwait( sem
, timespec
))
2380 return STATUS_WAIT_0
;
2382 continue; /* got a signal, restart */
2383 case KERN_OPERATION_TIMED_OUT
:
2384 return STATUS_TIMEOUT
;
2386 return STATUS_INVALID_HANDLE
;
2391 NTSTATUS CDECL
fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION
*crit
)
2393 semaphore_t sem
= get_mach_semaphore( crit
);
2394 semaphore_signal( sem
);
2395 return STATUS_SUCCESS
;
2398 NTSTATUS CDECL
fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION
*crit
)
2400 semaphore_destroy( mach_task_self(), *(int *)&crit
->LockSemaphore
);
2401 return STATUS_SUCCESS
;
2404 #else /* __APPLE__ */
2406 NTSTATUS CDECL
fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION
*crit
, int timeout
)
2408 return STATUS_NOT_IMPLEMENTED
;
2411 NTSTATUS CDECL
fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION
*crit
)
2413 return STATUS_NOT_IMPLEMENTED
;
2416 NTSTATUS CDECL
fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION
*crit
)
2418 return STATUS_NOT_IMPLEMENTED
;
2426 /* Futex-based SRW lock implementation:
2428 * Since we can rely on the kernel to release all threads and don't need to
2429 * worry about NtReleaseKeyedEvent(), we can simplify the layout a bit. The
2430 * layout looks like this:
2432 * 31 - Exclusive lock bit, set if the resource is owned exclusively.
2433 * 30-16 - Number of exclusive waiters. Unlike the fallback implementation,
2434 * this does not include the thread owning the lock, or shared threads
2435 * waiting on the lock.
2436 * 15 - Does this lock have any shared waiters? We use this as an
2437 * optimization to avoid unnecessary FUTEX_WAKE_BITSET calls when
2438 * releasing an exclusive lock.
2439 * 14-0 - Number of shared owners. Unlike the fallback implementation, this
2440 * does not include the number of shared threads waiting on the lock.
2441 * Thus the state [1, x, >=1] will never occur.
2444 #define SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT 0x80000000
2445 #define SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK 0x7fff0000
2446 #define SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC 0x00010000
2447 #define SRWLOCK_FUTEX_SHARED_WAITERS_BIT 0x00008000
2448 #define SRWLOCK_FUTEX_SHARED_OWNERS_MASK 0x00007fff
2449 #define SRWLOCK_FUTEX_SHARED_OWNERS_INC 0x00000001
2451 /* Futex bitmasks; these are independent from the bits in the lock itself. */
2452 #define SRWLOCK_FUTEX_BITSET_EXCLUSIVE 1
2453 #define SRWLOCK_FUTEX_BITSET_SHARED 2
2455 NTSTATUS CDECL
fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK
*lock
)
2457 int old
, new, *futex
;
2460 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2462 if (!(futex
= get_futex( &lock
->Ptr
)))
2463 return STATUS_NOT_IMPLEMENTED
;
2469 if (!(old
& SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
)
2470 && !(old
& SRWLOCK_FUTEX_SHARED_OWNERS_MASK
))
2472 /* Not locked exclusive or shared. We can try to grab it. */
2473 new = old
| SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
;
2474 ret
= STATUS_SUCCESS
;
2479 ret
= STATUS_TIMEOUT
;
2481 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2486 NTSTATUS CDECL
fast_RtlAcquireSRWLockExclusive( RTL_SRWLOCK
*lock
)
2488 int old
, new, *futex
;
2491 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2493 if (!(futex
= get_futex( &lock
->Ptr
)))
2494 return STATUS_NOT_IMPLEMENTED
;
2496 /* Atomically increment the exclusive waiter count. */
2500 new = old
+ SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC
;
2501 assert(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
);
2502 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2510 if (!(old
& SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
)
2511 && !(old
& SRWLOCK_FUTEX_SHARED_OWNERS_MASK
))
2513 /* Not locked exclusive or shared. We can try to grab it. */
2514 new = old
| SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
;
2515 assert(old
& SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
);
2516 new -= SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC
;
2524 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2527 return STATUS_SUCCESS
;
2529 futex_wait_bitset( futex
, new, NULL
, SRWLOCK_FUTEX_BITSET_EXCLUSIVE
);
2532 return STATUS_SUCCESS
;
2535 NTSTATUS CDECL
fast_RtlTryAcquireSRWLockShared( RTL_SRWLOCK
*lock
)
2537 int new, old
, *futex
;
2540 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2542 if (!(futex
= get_futex( &lock
->Ptr
)))
2543 return STATUS_NOT_IMPLEMENTED
;
2549 if (!(old
& SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
)
2550 && !(old
& SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
))
2552 /* Not locked exclusive, and no exclusive waiters. We can try to
2554 new = old
+ SRWLOCK_FUTEX_SHARED_OWNERS_INC
;
2555 assert(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK
);
2556 ret
= STATUS_SUCCESS
;
2561 ret
= STATUS_TIMEOUT
;
2563 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2568 NTSTATUS CDECL
fast_RtlAcquireSRWLockShared( RTL_SRWLOCK
*lock
)
2570 int old
, new, *futex
;
2573 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2575 if (!(futex
= get_futex( &lock
->Ptr
)))
2576 return STATUS_NOT_IMPLEMENTED
;
2584 if (!(old
& SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
)
2585 && !(old
& SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
))
2587 /* Not locked exclusive, and no exclusive waiters. We can try
2589 new = old
+ SRWLOCK_FUTEX_SHARED_OWNERS_INC
;
2590 assert(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK
);
2595 new = old
| SRWLOCK_FUTEX_SHARED_WAITERS_BIT
;
2598 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2601 return STATUS_SUCCESS
;
2603 futex_wait_bitset( futex
, new, NULL
, SRWLOCK_FUTEX_BITSET_SHARED
);
2606 return STATUS_SUCCESS
;
2609 NTSTATUS CDECL
fast_RtlReleaseSRWLockExclusive( RTL_SRWLOCK
*lock
)
2611 int old
, new, *futex
;
2613 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2615 if (!(futex
= get_futex( &lock
->Ptr
)))
2616 return STATUS_NOT_IMPLEMENTED
;
2622 if (!(old
& SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
))
2624 ERR("Lock %p is not owned exclusive! (%#x)\n", lock
, *futex
);
2625 return STATUS_RESOURCE_NOT_OWNED
;
2628 new = old
& ~SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
;
2630 if (!(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
))
2631 new &= ~SRWLOCK_FUTEX_SHARED_WAITERS_BIT
;
2632 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2634 if (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
)
2635 futex_wake_bitset( futex
, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE
);
2636 else if (old
& SRWLOCK_FUTEX_SHARED_WAITERS_BIT
)
2637 futex_wake_bitset( futex
, INT_MAX
, SRWLOCK_FUTEX_BITSET_SHARED
);
2639 return STATUS_SUCCESS
;
2642 NTSTATUS CDECL
fast_RtlReleaseSRWLockShared( RTL_SRWLOCK
*lock
)
2644 int old
, new, *futex
;
2646 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2648 if (!(futex
= get_futex( &lock
->Ptr
)))
2649 return STATUS_NOT_IMPLEMENTED
;
2655 if (old
& SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT
)
2657 ERR("Lock %p is owned exclusive! (%#x)\n", lock
, *futex
);
2658 return STATUS_RESOURCE_NOT_OWNED
;
2660 else if (!(old
& SRWLOCK_FUTEX_SHARED_OWNERS_MASK
))
2662 ERR("Lock %p is not owned shared! (%#x)\n", lock
, *futex
);
2663 return STATUS_RESOURCE_NOT_OWNED
;
2666 new = old
- SRWLOCK_FUTEX_SHARED_OWNERS_INC
;
2667 } while (InterlockedCompareExchange( futex
, new, old
) != old
);
2669 /* Optimization: only bother waking if there are actually exclusive waiters. */
2670 if (!(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK
) && (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK
))
2671 futex_wake_bitset( futex
, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE
);
2673 return STATUS_SUCCESS
;
2676 NTSTATUS CDECL
fast_wait_cv( RTL_CONDITION_VARIABLE
*variable
, const void *value
, const LARGE_INTEGER
*timeout
)
2678 const char *value_ptr
;
2679 int aligned_value
, *futex
;
2680 struct timespec timespec
;
2684 return STATUS_NOT_IMPLEMENTED
;
2686 if (!(futex
= get_futex( &variable
->Ptr
)))
2687 return STATUS_NOT_IMPLEMENTED
;
2689 value_ptr
= (const char *)&value
;
2690 value_ptr
+= ((ULONG_PTR
)futex
) - ((ULONG_PTR
)&variable
->Ptr
);
2691 aligned_value
= *(int *)value_ptr
;
2693 if (timeout
&& timeout
->QuadPart
!= TIMEOUT_INFINITE
)
2695 timespec_from_timeout( ×pec
, timeout
);
2696 ret
= futex_wait( futex
, aligned_value
, ×pec
);
2699 ret
= futex_wait( futex
, aligned_value
, NULL
);
2701 if (ret
== -1 && errno
== ETIMEDOUT
)
2702 return STATUS_TIMEOUT
;
2703 return STATUS_WAIT_0
;
2706 NTSTATUS CDECL
fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE
*variable
, int count
)
2710 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED
;
2712 if (!(futex
= get_futex( &variable
->Ptr
)))
2713 return STATUS_NOT_IMPLEMENTED
;
2715 InterlockedIncrement( futex
);
2716 futex_wake( futex
, count
);
2717 return STATUS_SUCCESS
;
2721 /* We can't map addresses to futex directly, because an application can wait on
2722 * 8 bytes, and we can't pass all 8 as the compare value to futex(). Instead we
2723 * map all addresses to a small fixed table of futexes. This may result in
2724 * spurious wakes, but the application is already expected to handle those. */
2726 static int addr_futex_table
[256];
2728 static inline int *hash_addr( const void *addr
)
2730 ULONG_PTR val
= (ULONG_PTR
)addr
;
2732 return &addr_futex_table
[(val
>> 2) & 255];
2735 static inline NTSTATUS
fast_wait_addr( const void *addr
, const void *cmp
, SIZE_T size
,
2736 const LARGE_INTEGER
*timeout
)
2740 struct timespec timespec
;
2744 return STATUS_NOT_IMPLEMENTED
;
2746 futex
= hash_addr( addr
);
2748 /* We must read the previous value of the futex before checking the value
2749 * of the address being waited on. That way, if we receive a wake between
2750 * now and waiting on the futex, we know that val will have changed.
2751 * Use an atomic load so that memory accesses are ordered between this read
2752 * and the increment below. */
2753 val
= InterlockedCompareExchange( futex
, 0, 0 );
2754 if (!compare_addr( addr
, cmp
, size
))
2755 return STATUS_SUCCESS
;
2759 timespec_from_timeout( ×pec
, timeout
);
2760 ret
= futex_wait( futex
, val
, ×pec
);
2763 ret
= futex_wait( futex
, val
, NULL
);
2765 if (ret
== -1 && errno
== ETIMEDOUT
)
2766 return STATUS_TIMEOUT
;
2767 return STATUS_SUCCESS
;
2770 static inline NTSTATUS
fast_wake_addr( const void *addr
)
2775 return STATUS_NOT_IMPLEMENTED
;
2777 futex
= hash_addr( addr
);
2779 InterlockedIncrement( futex
);
2781 futex_wake( futex
, INT_MAX
);
2782 return STATUS_SUCCESS
;
2787 NTSTATUS CDECL
fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK
*lock
)
2789 return STATUS_NOT_IMPLEMENTED
;
2792 NTSTATUS CDECL
fast_RtlAcquireSRWLockExclusive( RTL_SRWLOCK
*lock
)
2794 return STATUS_NOT_IMPLEMENTED
;
2797 NTSTATUS CDECL
fast_RtlTryAcquireSRWLockShared( RTL_SRWLOCK
*lock
)
2799 return STATUS_NOT_IMPLEMENTED
;
2802 NTSTATUS CDECL
fast_RtlAcquireSRWLockShared( RTL_SRWLOCK
*lock
)
2804 return STATUS_NOT_IMPLEMENTED
;
2807 NTSTATUS CDECL
fast_RtlReleaseSRWLockExclusive( RTL_SRWLOCK
*lock
)
2809 return STATUS_NOT_IMPLEMENTED
;
2812 NTSTATUS CDECL
fast_RtlReleaseSRWLockShared( RTL_SRWLOCK
*lock
)
2814 return STATUS_NOT_IMPLEMENTED
;
2817 NTSTATUS CDECL
fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE
*variable
, int count
)
2819 return STATUS_NOT_IMPLEMENTED
;
2822 NTSTATUS CDECL
fast_wait_cv( RTL_CONDITION_VARIABLE
*variable
, const void *value
, const LARGE_INTEGER
*timeout
)
2824 return STATUS_NOT_IMPLEMENTED
;
2827 static inline NTSTATUS
fast_wait_addr( const void *addr
, const void *cmp
, SIZE_T size
,
2828 const LARGE_INTEGER
*timeout
)
2830 return STATUS_NOT_IMPLEMENTED
;
2833 static inline NTSTATUS
fast_wake_addr( const void *addr
)
2835 return STATUS_NOT_IMPLEMENTED
;
2841 /***********************************************************************
2842 * RtlWaitOnAddress (NTDLL.@)
2844 NTSTATUS WINAPI
RtlWaitOnAddress( const void *addr
, const void *cmp
, SIZE_T size
,
2845 const LARGE_INTEGER
*timeout
)
2847 select_op_t select_op
;
2849 timeout_t abs_timeout
= timeout
? timeout
->QuadPart
: TIMEOUT_INFINITE
;
2851 if (size
!= 1 && size
!= 2 && size
!= 4 && size
!= 8)
2852 return STATUS_INVALID_PARAMETER
;
2854 if ((ret
= fast_wait_addr( addr
, cmp
, size
, timeout
)) != STATUS_NOT_IMPLEMENTED
)
2857 mutex_lock( &addr_mutex
);
2858 if (!compare_addr( addr
, cmp
, size
))
2860 mutex_unlock( &addr_mutex
);
2861 return STATUS_SUCCESS
;
2864 if (abs_timeout
< 0)
2868 NtQueryPerformanceCounter( &now
, NULL
);
2869 abs_timeout
-= now
.QuadPart
;
2872 select_op
.keyed_event
.op
= SELECT_KEYED_EVENT_WAIT
;
2873 select_op
.keyed_event
.handle
= wine_server_obj_handle( keyed_event
);
2874 select_op
.keyed_event
.key
= wine_server_client_ptr( addr
);
2876 return server_select( &select_op
, sizeof(select_op
.keyed_event
), SELECT_INTERRUPTIBLE
,
2877 abs_timeout
, NULL
, &addr_mutex
, NULL
);
2880 /***********************************************************************
2881 * RtlWakeAddressAll (NTDLL.@)
2883 void WINAPI
RtlWakeAddressAll( const void *addr
)
2885 if (fast_wake_addr( addr
) != STATUS_NOT_IMPLEMENTED
) return;
2887 mutex_lock( &addr_mutex
);
2888 while (NtReleaseKeyedEvent( 0, addr
, 0, &zero_timeout
) == STATUS_SUCCESS
) {}
2889 mutex_unlock( &addr_mutex
);
2892 /***********************************************************************
2893 * RtlWakeAddressSingle (NTDLL.@)
2895 void WINAPI
RtlWakeAddressSingle( const void *addr
)
2897 if (fast_wake_addr( addr
) != STATUS_NOT_IMPLEMENTED
) return;
2899 mutex_lock( &addr_mutex
);
2900 NtReleaseKeyedEvent( 0, addr
, 0, &zero_timeout
);
2901 mutex_unlock( &addr_mutex
);