ntdll: Improve the Nt{Query,Set}TimerResolution() stubs.
[wine.git] / dlls / ntdll / unix / sync.c
bloba13e53a437b53e6b92ca184de990ee24de760ff4
1 /*
2 * Process synchronisation
4 * Copyright 1996, 1997, 1998 Marcus Meissner
5 * Copyright 1997, 1999 Alexandre Julliard
6 * Copyright 1999, 2000 Juergen Schmied
7 * Copyright 2003 Eric Pouech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #if 0
25 #pragma makedep unix
26 #endif
28 #include "config.h"
29 #include "wine/port.h"
31 #include <assert.h>
32 #include <errno.h>
33 #include <limits.h>
34 #include <signal.h>
35 #ifdef HAVE_SYS_SYSCALL_H
36 #include <sys/syscall.h>
37 #endif
38 #ifdef HAVE_SYS_TIME_H
39 # include <sys/time.h>
40 #endif
41 #ifdef HAVE_POLL_H
42 #include <poll.h>
43 #endif
44 #ifdef HAVE_SYS_POLL_H
45 # include <sys/poll.h>
46 #endif
47 #ifdef HAVE_UNISTD_H
48 # include <unistd.h>
49 #endif
50 #ifdef HAVE_SCHED_H
51 # include <sched.h>
52 #endif
53 #include <string.h>
54 #include <stdarg.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <time.h>
58 #ifdef __APPLE__
59 # include <mach/mach.h>
60 # include <mach/task.h>
61 # include <mach/semaphore.h>
62 # include <mach/mach_time.h>
63 #endif
65 #include "ntstatus.h"
66 #define WIN32_NO_STATUS
67 #define NONAMELESSUNION
68 #include "windef.h"
69 #include "winternl.h"
70 #include "ddk/wdm.h"
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)
87 struct timeval now;
88 #ifdef __APPLE__
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;
95 #endif
96 return mach_absolute_time() * timebase.numer / timebase.denom / 100;
97 #elif defined(HAVE_CLOCK_GETTIME)
98 struct timespec ts;
99 #ifdef CLOCK_MONOTONIC_RAW
100 if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts ))
101 return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
102 #endif
103 if (!clock_gettime( CLOCK_MONOTONIC, &ts ))
104 return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
105 #endif
106 gettimeofday( &now, 0 );
107 return ticks_from_time_t( now.tv_sec ) + now.tv_usec * 10 - server_start_time;
111 #ifdef __linux__
113 #define FUTEX_WAIT 0
114 #define FUTEX_WAKE 1
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;
144 if (supported == -1)
146 futex_wait( &supported, 10, NULL );
147 if (errno == ENOSYS)
149 futex_private = 0;
150 futex_wait( &supported, 10, NULL );
152 supported = (errno != ENOSYS);
154 return supported;
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))
162 return (int *)ptr;
163 else
164 return NULL;
167 static void timespec_from_timeout( struct timespec *timespec, const LARGE_INTEGER *timeout )
169 LARGE_INTEGER now;
170 timeout_t diff;
172 if (timeout->QuadPart > 0)
174 NtQuerySystemTime( &now );
175 diff = timeout->QuadPart - now.QuadPart;
177 else
178 diff = -timeout->QuadPart;
180 timespec->tv_sec = diff / TICKSPERSEC;
181 timespec->tv_nsec = (diff % TICKSPERSEC) * 100;
184 #endif
187 static BOOL compare_addr( const void *addr, const void *cmp, SIZE_T size )
189 switch (size)
191 case 1:
192 return (*(const UCHAR *)addr == *(const UCHAR *)cmp);
193 case 2:
194 return (*(const USHORT *)addr == *(const USHORT *)cmp);
195 case 4:
196 return (*(const ULONG *)addr == *(const ULONG *)cmp);
197 case 8:
198 return (*(const ULONG64 *)addr == *(const ULONG64 *)cmp);
201 return FALSE;
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;
214 *ret = NULL;
215 *ret_len = 0;
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);
233 else
235 owner = sd->Owner;
236 group = sd->Group;
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 );
294 *ret_len = 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 )
320 NTSTATUS ret;
321 data_size_t len;
322 struct object_attributes *objattr;
324 *handle = 0;
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;
332 req->max = max;
333 wine_server_add_data( req, objattr, len );
334 ret = wine_server_call( req );
335 *handle = wine_server_ptr_handle( reply->handle );
337 SERVER_END_REQ;
339 free( objattr );
340 return ret;
344 /******************************************************************************
345 * NtOpenSemaphore (NTDLL.@)
347 NTSTATUS WINAPI NtOpenSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
349 NTSTATUS ret;
351 *handle = 0;
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 );
364 SERVER_END_REQ;
365 return ret;
369 /******************************************************************************
370 * NtQuerySemaphore (NTDLL.@)
372 NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS class,
373 void *info, ULONG len, ULONG *ret_len )
375 NTSTATUS ret;
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);
398 SERVER_END_REQ;
399 return ret;
403 /******************************************************************************
404 * NtReleaseSemaphore (NTDLL.@)
406 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, ULONG *previous )
408 NTSTATUS ret;
410 SERVER_START_REQ( release_semaphore )
412 req->handle = wine_server_obj_handle( handle );
413 req->count = count;
414 if (!(ret = wine_server_call( req )))
416 if (previous) *previous = reply->prev_count;
419 SERVER_END_REQ;
420 return ret;
424 /**************************************************************************
425 * NtCreateEvent (NTDLL.@)
427 NTSTATUS WINAPI NtCreateEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
428 EVENT_TYPE type, BOOLEAN state )
430 NTSTATUS ret;
431 data_size_t len;
432 struct object_attributes *objattr;
434 *handle = 0;
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 );
447 SERVER_END_REQ;
449 free( objattr );
450 return ret;
454 /******************************************************************************
455 * NtOpenEvent (NTDLL.@)
457 NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
459 NTSTATUS ret;
461 *handle = 0;
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 );
474 SERVER_END_REQ;
475 return ret;
479 /******************************************************************************
480 * NtSetEvent (NTDLL.@)
482 NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state )
484 NTSTATUS ret;
486 SERVER_START_REQ( event_op )
488 req->handle = wine_server_obj_handle( handle );
489 req->op = SET_EVENT;
490 ret = wine_server_call( req );
491 if (!ret && prev_state) *prev_state = reply->state;
493 SERVER_END_REQ;
494 return ret;
498 /******************************************************************************
499 * NtResetEvent (NTDLL.@)
501 NTSTATUS WINAPI NtResetEvent( HANDLE handle, LONG *prev_state )
503 NTSTATUS ret;
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;
512 SERVER_END_REQ;
513 return ret;
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 )
532 NTSTATUS ret;
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;
541 SERVER_END_REQ;
542 return ret;
546 /******************************************************************************
547 * NtQueryEvent (NTDLL.@)
549 NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class,
550 void *info, ULONG len, ULONG *ret_len )
552 NTSTATUS ret;
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",
560 handle, class, len);
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);
576 SERVER_END_REQ;
577 return ret;
581 /******************************************************************************
582 * NtCreateMutant (NTDLL.@)
584 NTSTATUS WINAPI NtCreateMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
585 BOOLEAN owned )
587 NTSTATUS ret;
588 data_size_t len;
589 struct object_attributes *objattr;
591 *handle = 0;
592 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
594 SERVER_START_REQ( create_mutex )
596 req->access = access;
597 req->owned = owned;
598 wine_server_add_data( req, objattr, len );
599 ret = wine_server_call( req );
600 *handle = wine_server_ptr_handle( reply->handle );
602 SERVER_END_REQ;
604 free( objattr );
605 return ret;
609 /**************************************************************************
610 * NtOpenMutant (NTDLL.@)
612 NTSTATUS WINAPI NtOpenMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
614 NTSTATUS ret;
616 *handle = 0;
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 );
629 SERVER_END_REQ;
630 return ret;
634 /**************************************************************************
635 * NtReleaseMutant (NTDLL.@)
637 NTSTATUS WINAPI NtReleaseMutant( HANDLE handle, LONG *prev_count )
639 NTSTATUS ret;
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;
647 SERVER_END_REQ;
648 return ret;
652 /******************************************************************
653 * NtQueryMutant (NTDLL.@)
655 NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class,
656 void *info, ULONG len, ULONG *ret_len )
658 NTSTATUS ret;
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);
682 SERVER_END_REQ;
683 return ret;
687 /**************************************************************************
688 * NtCreateJobObject (NTDLL.@)
690 NTSTATUS WINAPI NtCreateJobObject( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
692 NTSTATUS ret;
693 data_size_t len;
694 struct object_attributes *objattr;
696 *handle = 0;
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 );
706 SERVER_END_REQ;
707 free( objattr );
708 return ret;
712 /**************************************************************************
713 * NtOpenJobObject (NTDLL.@)
715 NTSTATUS WINAPI NtOpenJobObject( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
717 NTSTATUS ret;
719 *handle = 0;
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 );
732 SERVER_END_REQ;
733 return ret;
737 /**************************************************************************
738 * NtTerminateJobObject (NTDLL.@)
740 NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status )
742 NTSTATUS ret;
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 );
752 SERVER_END_REQ;
754 return ret;
758 /**************************************************************************
759 * NtQueryInformationJobObject (NTDLL.@)
761 NTSTATUS WINAPI NtQueryInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, void *info,
762 ULONG len, ULONG *ret_len )
764 NTSTATUS ret;
766 TRACE( "semi-stub: %p %u %p %u %p\n", handle, class, info, len, ret_len );
768 if (class >= MaxJobObjectInfoClass) return STATUS_INVALID_PARAMETER;
770 switch (class)
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;
787 SERVER_END_REQ;
788 if (ret_len) *ret_len = sizeof(*accounting);
789 return ret;
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;
818 default:
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;
838 switch (class)
841 case JobObjectExtendedLimitInformation:
842 info_size = sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION);
843 limit_flags = JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS;
844 /* fall through */
845 case JobObjectBasicLimitInformation:
846 if (len != info_size) return STATUS_INVALID_PARAMETER;
847 basic_limit = info;
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 );
855 SERVER_END_REQ;
856 break;
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 );
867 SERVER_END_REQ;
868 break;
869 case JobObjectBasicUIRestrictions:
870 status = STATUS_SUCCESS;
871 /* fall through */
872 default:
873 FIXME( "stub: %p %u %p %u\n", handle, class, info, len );
875 return status;
879 /**************************************************************************
880 * NtIsProcessInJob (NTDLL.@)
882 NTSTATUS WINAPI NtIsProcessInJob( HANDLE process, HANDLE job )
884 NTSTATUS status;
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 );
894 SERVER_END_REQ;
895 return status;
899 /**************************************************************************
900 * NtAssignProcessToJobObject (NTDLL.@)
902 NTSTATUS WINAPI NtAssignProcessToJobObject( HANDLE job, HANDLE process )
904 NTSTATUS status;
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 );
914 SERVER_END_REQ;
915 return status;
919 /**********************************************************************
920 * NtCreateDebugObject (NTDLL.@)
922 NTSTATUS WINAPI NtCreateDebugObject( HANDLE *handle, ACCESS_MASK access,
923 OBJECT_ATTRIBUTES *attr, ULONG flags )
925 NTSTATUS ret;
926 data_size_t len;
927 struct object_attributes *objattr;
929 *handle = 0;
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;
936 req->flags = flags;
937 wine_server_add_data( req, objattr, len );
938 ret = wine_server_call( req );
939 *handle = wine_server_ptr_handle( reply->handle );
941 SERVER_END_REQ;
942 free( objattr );
943 return ret;
947 /**********************************************************************
948 * NtSetInformationDebugObject (NTDLL.@)
950 NTSTATUS WINAPI NtSetInformationDebugObject( HANDLE handle, DEBUGOBJECTINFOCLASS class,
951 void *info, ULONG len, ULONG *ret_len )
953 NTSTATUS ret;
954 ULONG flags;
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 );
968 req->flags = flags;
969 ret = wine_server_call( req );
971 SERVER_END_REQ;
972 if (!ret && ret_len) *ret_len = 0;
973 return ret;
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 )
980 int i;
982 switch (data->code)
984 case DbgIdle:
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 )
1050 debug_event_t data;
1051 NTSTATUS ret;
1052 BOOL wait = TRUE;
1054 for (;;)
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 );
1068 SERVER_END_REQ;
1070 if (ret != STATUS_PENDING) return ret;
1071 if (!wait) return STATUS_TIMEOUT;
1072 wait = FALSE;
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 )
1084 NTSTATUS ret;
1085 data_size_t len;
1086 struct object_attributes *objattr;
1088 *handle = 0;
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 );
1098 SERVER_END_REQ;
1099 free( objattr );
1100 return ret;
1104 /**************************************************************************
1105 * NtOpenDirectoryObject (NTDLL.@)
1107 NTSTATUS WINAPI NtOpenDirectoryObject( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1109 NTSTATUS ret;
1111 *handle = 0;
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 );
1124 SERVER_END_REQ;
1125 return ret;
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 )
1136 NTSTATUS ret;
1138 if (restart) *context = 0;
1140 if (single_entry)
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;
1162 (*context)++;
1165 SERVER_END_REQ;
1166 if (ret_size)
1167 *ret_size = buffer->ObjectName.MaximumLength + buffer->ObjectTypeName.MaximumLength + sizeof(*buffer);
1169 else
1171 FIXME("multiple entries not implemented\n");
1172 ret = STATUS_NOT_IMPLEMENTED;
1174 return ret;
1178 /**************************************************************************
1179 * NtCreateSymbolicLinkObject (NTDLL.@)
1181 NTSTATUS WINAPI NtCreateSymbolicLinkObject( HANDLE *handle, ACCESS_MASK access,
1182 OBJECT_ATTRIBUTES *attr, UNICODE_STRING *target )
1184 NTSTATUS ret;
1185 data_size_t len;
1186 struct object_attributes *objattr;
1188 *handle = 0;
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 );
1201 SERVER_END_REQ;
1202 free( objattr );
1203 return ret;
1207 /**************************************************************************
1208 * NtOpenSymbolicLinkObject (NTDLL.@)
1210 NTSTATUS WINAPI NtOpenSymbolicLinkObject( HANDLE *handle, ACCESS_MASK access,
1211 const OBJECT_ATTRIBUTES *attr )
1213 NTSTATUS ret;
1215 *handle = 0;
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 );
1228 SERVER_END_REQ;
1229 return ret;
1233 /**************************************************************************
1234 * NtQuerySymbolicLinkObject (NTDLL.@)
1236 NTSTATUS WINAPI NtQuerySymbolicLinkObject( HANDLE handle, UNICODE_STRING *target, ULONG *length )
1238 NTSTATUS ret;
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);
1255 SERVER_END_REQ;
1256 return ret;
1260 /**************************************************************************
1261 * NtMakeTemporaryObject (NTDLL.@)
1263 NTSTATUS WINAPI NtMakeTemporaryObject( HANDLE handle )
1265 NTSTATUS ret;
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 );
1274 SERVER_END_REQ;
1275 return ret;
1279 /**************************************************************************
1280 * NtCreateTimer (NTDLL.@)
1282 NTSTATUS WINAPI NtCreateTimer( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
1283 TIMER_TYPE type )
1285 NTSTATUS ret;
1286 data_size_t len;
1287 struct object_attributes *objattr;
1289 *handle = 0;
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 );
1301 SERVER_END_REQ;
1303 free( objattr );
1304 return ret;
1309 /**************************************************************************
1310 * NtOpenTimer (NTDLL.@)
1312 NTSTATUS WINAPI NtOpenTimer( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1314 NTSTATUS ret;
1316 *handle = 0;
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 );
1329 SERVER_END_REQ;
1330 return ret;
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;
1354 SERVER_END_REQ;
1356 /* set error but can still succeed */
1357 if (resume && ret == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
1358 return ret;
1362 /**************************************************************************
1363 * NtCancelTimer (NTDLL.@)
1365 NTSTATUS WINAPI NtCancelTimer( HANDLE handle, BOOLEAN *state )
1367 NTSTATUS ret;
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;
1375 SERVER_END_REQ;
1376 return ret;
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;
1387 NTSTATUS ret;
1388 LARGE_INTEGER now;
1390 TRACE( "(%p,%d,%p,0x%08x,%p)\n", handle, class, info, len, ret_len );
1392 switch (class)
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;
1405 SERVER_END_REQ;
1407 /* convert into relative time */
1408 if (basic_info->RemainingTime.QuadPart > 0) NtQuerySystemTime( &now );
1409 else
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;
1417 else
1418 basic_info->RemainingTime.QuadPart -= now.QuadPart;
1420 if (ret_len) *ret_len = sizeof(TIMER_BASIC_INFORMATION);
1421 return ret;
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
1481 sched_yield();
1482 return STATUS_SUCCESS;
1483 #else
1484 return STATUS_NO_YIELD_PERFORMED;
1485 #endif
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 );
1501 else
1503 LARGE_INTEGER now;
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 */
1513 NtYieldExecution();
1514 if (!when) return STATUS_SUCCESS;
1516 for (;;)
1518 struct timeval tv;
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
1548 struct timespec ts;
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;
1559 else
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;
1568 else
1569 #endif /* HAVE_CLOCK_GETTIME */
1571 struct timeval now;
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 )
1585 LARGE_INTEGER now;
1586 LONGLONG diff;
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() */
1604 *min_res = 156250;
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
1627 * resolution.
1629 if (!has_request && !set)
1630 return STATUS_TIMER_RESOLUTION_NOT_SET;
1631 has_request = 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)
1662 struct timeval now;
1663 #ifdef HAVE_CLOCK_GETTIME
1664 struct timespec ts;
1666 if (!clock_gettime( CLOCK_REALTIME, &ts ))
1667 return ticks_from_time_t( ts.tv_sec ) + (ts.tv_nsec + 50) / 100;
1668 #endif
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 )
1680 NTSTATUS ret;
1681 data_size_t len;
1682 struct object_attributes *objattr;
1684 *handle = 0;
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 );
1694 SERVER_END_REQ;
1696 free( objattr );
1697 return ret;
1701 /******************************************************************************
1702 * NtOpenKeyedEvent (NTDLL.@)
1704 NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1706 NTSTATUS ret;
1708 *handle = 0;
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 );
1721 SERVER_END_REQ;
1722 return ret;
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,
1767 ULONG threads )
1769 NTSTATUS status;
1770 data_size_t len;
1771 struct object_attributes *objattr;
1773 TRACE( "(%p, %x, %p, %d)\n", handle, access, attr, threads );
1775 *handle = 0;
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 );
1785 SERVER_END_REQ;
1787 free( objattr );
1788 return status;
1792 /***********************************************************************
1793 * NtOpenIoCompletion (NTDLL.@)
1795 NTSTATUS WINAPI NtOpenIoCompletion( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1797 NTSTATUS status;
1799 *handle = 0;
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 );
1812 SERVER_END_REQ;
1813 return status;
1817 /***********************************************************************
1818 * NtSetIoCompletion (NTDLL.@)
1820 NTSTATUS WINAPI NtSetIoCompletion( HANDLE handle, ULONG_PTR key, ULONG_PTR value,
1821 NTSTATUS status, SIZE_T count )
1823 NTSTATUS ret;
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 );
1830 req->ckey = key;
1831 req->cvalue = value;
1832 req->status = status;
1833 req->information = count;
1834 ret = wine_server_call( req );
1836 SERVER_END_REQ;
1837 return ret;
1841 /***********************************************************************
1842 * NtRemoveIoCompletion (NTDLL.@)
1844 NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR *value,
1845 IO_STATUS_BLOCK *io, LARGE_INTEGER *timeout )
1847 NTSTATUS status;
1849 TRACE( "(%p, %p, %p, %p, %p)\n", handle, key, value, io, timeout );
1851 for (;;)
1853 SERVER_START_REQ( remove_completion )
1855 req->handle = wine_server_obj_handle( handle );
1856 if (!(status = wine_server_call( req )))
1858 *key = reply->ckey;
1859 *value = reply->cvalue;
1860 io->Information = reply->information;
1861 io->u.Status = reply->status;
1864 SERVER_END_REQ;
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 )
1878 NTSTATUS status;
1879 ULONG i = 0;
1881 TRACE( "%p %p %u %p %p %u\n", handle, info, count, written, timeout, alertable );
1883 for (;;)
1885 while (i < count)
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;
1898 SERVER_END_REQ;
1899 if (status != STATUS_SUCCESS) break;
1900 ++i;
1902 if (i || status != STATUS_PENDING)
1904 if (status == STATUS_PENDING) status = STATUS_SUCCESS;
1905 break;
1907 status = NtWaitForSingleObject( handle, alertable, timeout );
1908 if (status != WAIT_OBJECT_0) break;
1910 *written = i ? i : 1;
1911 return status;
1915 /***********************************************************************
1916 * NtQueryIoCompletion (NTDLL.@)
1918 NTSTATUS WINAPI NtQueryIoCompletion( HANDLE handle, IO_COMPLETION_INFORMATION_CLASS class,
1919 void *buffer, ULONG len, ULONG *ret_len )
1921 NTSTATUS status;
1923 TRACE( "(%p, %d, %p, 0x%x, %p)\n", handle, class, buffer, len, ret_len );
1925 if (!buffer) return STATUS_INVALID_PARAMETER;
1927 switch (class)
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;
1940 SERVER_END_REQ;
1942 else status = STATUS_INFO_LENGTH_MISMATCH;
1943 break;
1945 default:
1946 return STATUS_INVALID_PARAMETER;
1948 return status;
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 )
1959 NTSTATUS ret;
1960 unsigned int file_access;
1961 data_size_t len;
1962 struct object_attributes *objattr;
1964 *handle = 0;
1966 switch (protect & 0xff)
1968 case PAGE_READONLY:
1969 case PAGE_EXECUTE_READ:
1970 case PAGE_WRITECOPY:
1971 case PAGE_EXECUTE_WRITECOPY:
1972 file_access = FILE_READ_DATA;
1973 break;
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;
1978 break;
1979 case PAGE_EXECUTE:
1980 case PAGE_NOACCESS:
1981 file_access = 0;
1982 break;
1983 default:
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 );
2000 SERVER_END_REQ;
2002 free( objattr );
2003 return ret;
2007 /***********************************************************************
2008 * NtOpenSection (NTDLL.@)
2010 NTSTATUS WINAPI NtOpenSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
2012 NTSTATUS ret;
2014 *handle = 0;
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 );
2027 SERVER_END_REQ;
2028 return ret;
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 );
2117 if (msg_in)
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 )
2141 RTL_ATOM atom;
2143 if ((ULONG_PTR)atomstr >> 16)
2145 const WCHAR* ptr = atomstr;
2146 if (!len) return STATUS_OBJECT_NAME_INVALID;
2148 if (*ptr++ == '#')
2150 atom = 0;
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 );
2161 done:
2162 if (!atom || atom >= MAXINTATOM) return STATUS_INVALID_PARAMETER;
2163 *ret_atom = atom;
2164 return STATUS_SUCCESS;
2167 static ULONG integral_atom_name( WCHAR *buffer, ULONG len, RTL_ATOM atom )
2169 char tmp[16];
2170 int ret = sprintf( tmp, "#%u", atom );
2172 len /= sizeof(WCHAR);
2173 if (len)
2175 if (len <= ret) ret = len - 1;
2176 ascii_to_unicode( buffer, tmp, ret );
2177 buffer[ret] = 0;
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;
2198 SERVER_END_REQ;
2200 TRACE( "%s -> %x\n", debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
2201 return status;
2205 /***********************************************************************
2206 * NtDeleteAtom (NTDLL.@)
2208 NTSTATUS WINAPI NtDeleteAtom( RTL_ATOM atom )
2210 NTSTATUS status;
2212 SERVER_START_REQ( delete_atom )
2214 req->atom = atom;
2215 status = wine_server_call( req );
2217 SERVER_END_REQ;
2218 return status;
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;
2237 SERVER_END_REQ;
2239 TRACE( "%s -> %x\n", debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
2240 return status;
2244 /***********************************************************************
2245 * NtQueryInformationAtom (NTDLL.@)
2247 NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS class,
2248 void *ptr, ULONG size, ULONG *retsize )
2250 NTSTATUS status;
2252 switch (class)
2254 case AtomBasicInformation:
2256 ULONG name_len;
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)
2264 if (atom)
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;
2269 abi->Pinned = 1;
2271 else status = STATUS_INVALID_PARAMETER;
2273 else
2275 SERVER_START_REQ( get_atom_information )
2277 req->atom = atom;
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 );
2283 if (name_len)
2285 abi->NameLength = name_len;
2286 abi->Name[name_len / sizeof(WCHAR)] = 0;
2288 else
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;
2297 else name_len = 0;
2299 SERVER_END_REQ;
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;
2303 break;
2306 default:
2307 FIXME( "Unsupported class %u\n", class );
2308 status = STATUS_INVALID_INFO_CLASS;
2309 break;
2311 return status;
2315 #ifdef __linux__
2317 NTSTATUS CDECL fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit, int timeout )
2319 int val;
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, &timespec ) == -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;
2356 if (!ret)
2358 semaphore_t sem;
2359 if (semaphore_create( mach_task_self(), &sem, SYNC_POLICY_FIFO, 0 )) return 0;
2360 if (!(ret = InterlockedCompareExchange( (int *)&crit->LockSemaphore, sem, 0 )))
2361 ret = sem;
2362 else
2363 semaphore_destroy( mach_task_self(), sem ); /* somebody beat us to it */
2365 return ret;
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;
2375 for (;;)
2377 switch( semaphore_timedwait( sem, timespec ))
2379 case KERN_SUCCESS:
2380 return STATUS_WAIT_0;
2381 case KERN_ABORTED:
2382 continue; /* got a signal, restart */
2383 case KERN_OPERATION_TIMED_OUT:
2384 return STATUS_TIMEOUT;
2385 default:
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;
2421 #endif
2424 #ifdef __linux__
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;
2458 NTSTATUS ret;
2460 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2462 if (!(futex = get_futex( &lock->Ptr )))
2463 return STATUS_NOT_IMPLEMENTED;
2467 old = *futex;
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;
2476 else
2478 new = old;
2479 ret = STATUS_TIMEOUT;
2481 } while (InterlockedCompareExchange( futex, new, old ) != old);
2483 return ret;
2486 NTSTATUS CDECL fast_RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
2488 int old, new, *futex;
2489 BOOLEAN wait;
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. */
2499 old = *futex;
2500 new = old + SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC;
2501 assert(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK);
2502 } while (InterlockedCompareExchange( futex, new, old ) != old);
2504 for (;;)
2508 old = *futex;
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;
2517 wait = FALSE;
2519 else
2521 new = old;
2522 wait = TRUE;
2524 } while (InterlockedCompareExchange( futex, new, old ) != old);
2526 if (!wait)
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;
2538 NTSTATUS ret;
2540 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2542 if (!(futex = get_futex( &lock->Ptr )))
2543 return STATUS_NOT_IMPLEMENTED;
2547 old = *futex;
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
2553 * grab it. */
2554 new = old + SRWLOCK_FUTEX_SHARED_OWNERS_INC;
2555 assert(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK);
2556 ret = STATUS_SUCCESS;
2558 else
2560 new = old;
2561 ret = STATUS_TIMEOUT;
2563 } while (InterlockedCompareExchange( futex, new, old ) != old);
2565 return ret;
2568 NTSTATUS CDECL fast_RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
2570 int old, new, *futex;
2571 BOOLEAN wait;
2573 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2575 if (!(futex = get_futex( &lock->Ptr )))
2576 return STATUS_NOT_IMPLEMENTED;
2578 for (;;)
2582 old = *futex;
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
2588 * to grab it. */
2589 new = old + SRWLOCK_FUTEX_SHARED_OWNERS_INC;
2590 assert(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK);
2591 wait = FALSE;
2593 else
2595 new = old | SRWLOCK_FUTEX_SHARED_WAITERS_BIT;
2596 wait = TRUE;
2598 } while (InterlockedCompareExchange( futex, new, old ) != old);
2600 if (!wait)
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;
2620 old = *futex;
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;
2653 old = *futex;
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;
2681 int ret;
2683 if (!use_futexes())
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( &timespec, timeout );
2696 ret = futex_wait( futex, aligned_value, &timespec );
2698 else
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 )
2708 int *futex;
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 )
2738 int *futex;
2739 int val;
2740 struct timespec timespec;
2741 int ret;
2743 if (!use_futexes())
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;
2757 if (timeout)
2759 timespec_from_timeout( &timespec, timeout );
2760 ret = futex_wait( futex, val, &timespec );
2762 else
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 )
2772 int *futex;
2774 if (!use_futexes())
2775 return STATUS_NOT_IMPLEMENTED;
2777 futex = hash_addr( addr );
2779 InterlockedIncrement( futex );
2781 futex_wake( futex, INT_MAX );
2782 return STATUS_SUCCESS;
2785 #else
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;
2838 #endif
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;
2848 NTSTATUS ret;
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)
2855 return ret;
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)
2866 LARGE_INTEGER now;
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 );