ntdll: Always clear the returned handle in Nt object functions.
[wine.git] / dlls / ntdll / unix / sync.c
blob7bdce91e0344ace56f1e2a980b9b2b1f162bd54a
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 FIXME( "(%p,%p,%p), stub!\n", min_res, max_res, current_res );
1603 return STATUS_NOT_IMPLEMENTED;
1607 /***********************************************************************
1608 * NtSetTimerResolution (NTDLL.@)
1610 NTSTATUS WINAPI NtSetTimerResolution( ULONG res, BOOLEAN set, ULONG *current_res )
1612 FIXME( "(%u,%u,%p), stub!\n", res, set, current_res );
1613 return STATUS_NOT_IMPLEMENTED;
1617 /******************************************************************************
1618 * NtSetIntervalProfile (NTDLL.@)
1620 NTSTATUS WINAPI NtSetIntervalProfile( ULONG interval, KPROFILE_SOURCE source )
1622 FIXME( "%u,%d\n", interval, source );
1623 return STATUS_SUCCESS;
1627 /******************************************************************************
1628 * NtGetTickCount (NTDLL.@)
1630 ULONG WINAPI NtGetTickCount(void)
1632 /* note: we ignore TickCountMultiplier */
1633 return user_shared_data->u.TickCount.LowPart;
1637 /******************************************************************************
1638 * RtlGetSystemTimePrecise (NTDLL.@)
1640 LONGLONG WINAPI RtlGetSystemTimePrecise(void)
1642 struct timeval now;
1643 #ifdef HAVE_CLOCK_GETTIME
1644 struct timespec ts;
1646 if (!clock_gettime( CLOCK_REALTIME, &ts ))
1647 return ticks_from_time_t( ts.tv_sec ) + (ts.tv_nsec + 50) / 100;
1648 #endif
1649 gettimeofday( &now, 0 );
1650 return ticks_from_time_t( now.tv_sec ) + now.tv_usec * 10;
1654 /******************************************************************************
1655 * NtCreateKeyedEvent (NTDLL.@)
1657 NTSTATUS WINAPI NtCreateKeyedEvent( HANDLE *handle, ACCESS_MASK access,
1658 const OBJECT_ATTRIBUTES *attr, ULONG flags )
1660 NTSTATUS ret;
1661 data_size_t len;
1662 struct object_attributes *objattr;
1664 *handle = 0;
1665 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1667 SERVER_START_REQ( create_keyed_event )
1669 req->access = access;
1670 wine_server_add_data( req, objattr, len );
1671 ret = wine_server_call( req );
1672 *handle = wine_server_ptr_handle( reply->handle );
1674 SERVER_END_REQ;
1676 free( objattr );
1677 return ret;
1681 /******************************************************************************
1682 * NtOpenKeyedEvent (NTDLL.@)
1684 NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1686 NTSTATUS ret;
1688 *handle = 0;
1689 if ((ret = validate_open_object_attributes( attr ))) return ret;
1691 SERVER_START_REQ( open_keyed_event )
1693 req->access = access;
1694 req->attributes = attr->Attributes;
1695 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1696 if (attr->ObjectName)
1697 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1698 ret = wine_server_call( req );
1699 *handle = wine_server_ptr_handle( reply->handle );
1701 SERVER_END_REQ;
1702 return ret;
1705 /******************************************************************************
1706 * NtWaitForKeyedEvent (NTDLL.@)
1708 NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
1709 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1711 select_op_t select_op;
1712 UINT flags = SELECT_INTERRUPTIBLE;
1714 if (!handle) handle = keyed_event;
1715 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1716 if (alertable) flags |= SELECT_ALERTABLE;
1717 select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT;
1718 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1719 select_op.keyed_event.key = wine_server_client_ptr( key );
1720 return server_wait( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1724 /******************************************************************************
1725 * NtReleaseKeyedEvent (NTDLL.@)
1727 NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key,
1728 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1730 select_op_t select_op;
1731 UINT flags = SELECT_INTERRUPTIBLE;
1733 if (!handle) handle = keyed_event;
1734 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1735 if (alertable) flags |= SELECT_ALERTABLE;
1736 select_op.keyed_event.op = SELECT_KEYED_EVENT_RELEASE;
1737 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1738 select_op.keyed_event.key = wine_server_client_ptr( key );
1739 return server_wait( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1743 /***********************************************************************
1744 * NtCreateIoCompletion (NTDLL.@)
1746 NTSTATUS WINAPI NtCreateIoCompletion( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
1747 ULONG threads )
1749 NTSTATUS status;
1750 data_size_t len;
1751 struct object_attributes *objattr;
1753 TRACE( "(%p, %x, %p, %d)\n", handle, access, attr, threads );
1755 *handle = 0;
1756 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
1758 SERVER_START_REQ( create_completion )
1760 req->access = access;
1761 req->concurrent = threads;
1762 wine_server_add_data( req, objattr, len );
1763 if (!(status = wine_server_call( req ))) *handle = wine_server_ptr_handle( reply->handle );
1765 SERVER_END_REQ;
1767 free( objattr );
1768 return status;
1772 /***********************************************************************
1773 * NtOpenIoCompletion (NTDLL.@)
1775 NTSTATUS WINAPI NtOpenIoCompletion( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1777 NTSTATUS status;
1779 *handle = 0;
1780 if ((status = validate_open_object_attributes( attr ))) return status;
1782 SERVER_START_REQ( open_completion )
1784 req->access = access;
1785 req->attributes = attr->Attributes;
1786 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1787 if (attr->ObjectName)
1788 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1789 status = wine_server_call( req );
1790 *handle = wine_server_ptr_handle( reply->handle );
1792 SERVER_END_REQ;
1793 return status;
1797 /***********************************************************************
1798 * NtSetIoCompletion (NTDLL.@)
1800 NTSTATUS WINAPI NtSetIoCompletion( HANDLE handle, ULONG_PTR key, ULONG_PTR value,
1801 NTSTATUS status, SIZE_T count )
1803 NTSTATUS ret;
1805 TRACE( "(%p, %lx, %lx, %x, %lx)\n", handle, key, value, status, count );
1807 SERVER_START_REQ( add_completion )
1809 req->handle = wine_server_obj_handle( handle );
1810 req->ckey = key;
1811 req->cvalue = value;
1812 req->status = status;
1813 req->information = count;
1814 ret = wine_server_call( req );
1816 SERVER_END_REQ;
1817 return ret;
1821 /***********************************************************************
1822 * NtRemoveIoCompletion (NTDLL.@)
1824 NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR *value,
1825 IO_STATUS_BLOCK *io, LARGE_INTEGER *timeout )
1827 NTSTATUS status;
1829 TRACE( "(%p, %p, %p, %p, %p)\n", handle, key, value, io, timeout );
1831 for (;;)
1833 SERVER_START_REQ( remove_completion )
1835 req->handle = wine_server_obj_handle( handle );
1836 if (!(status = wine_server_call( req )))
1838 *key = reply->ckey;
1839 *value = reply->cvalue;
1840 io->Information = reply->information;
1841 io->u.Status = reply->status;
1844 SERVER_END_REQ;
1845 if (status != STATUS_PENDING) return status;
1846 status = NtWaitForSingleObject( handle, FALSE, timeout );
1847 if (status != WAIT_OBJECT_0) return status;
1852 /***********************************************************************
1853 * NtRemoveIoCompletionEx (NTDLL.@)
1855 NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORMATION *info, ULONG count,
1856 ULONG *written, LARGE_INTEGER *timeout, BOOLEAN alertable )
1858 NTSTATUS status;
1859 ULONG i = 0;
1861 TRACE( "%p %p %u %p %p %u\n", handle, info, count, written, timeout, alertable );
1863 for (;;)
1865 while (i < count)
1867 SERVER_START_REQ( remove_completion )
1869 req->handle = wine_server_obj_handle( handle );
1870 if (!(status = wine_server_call( req )))
1872 info[i].CompletionKey = reply->ckey;
1873 info[i].CompletionValue = reply->cvalue;
1874 info[i].IoStatusBlock.Information = reply->information;
1875 info[i].IoStatusBlock.u.Status = reply->status;
1878 SERVER_END_REQ;
1879 if (status != STATUS_SUCCESS) break;
1880 ++i;
1882 if (i || status != STATUS_PENDING)
1884 if (status == STATUS_PENDING) status = STATUS_SUCCESS;
1885 break;
1887 status = NtWaitForSingleObject( handle, alertable, timeout );
1888 if (status != WAIT_OBJECT_0) break;
1890 *written = i ? i : 1;
1891 return status;
1895 /***********************************************************************
1896 * NtQueryIoCompletion (NTDLL.@)
1898 NTSTATUS WINAPI NtQueryIoCompletion( HANDLE handle, IO_COMPLETION_INFORMATION_CLASS class,
1899 void *buffer, ULONG len, ULONG *ret_len )
1901 NTSTATUS status;
1903 TRACE( "(%p, %d, %p, 0x%x, %p)\n", handle, class, buffer, len, ret_len );
1905 if (!buffer) return STATUS_INVALID_PARAMETER;
1907 switch (class)
1909 case IoCompletionBasicInformation:
1911 ULONG *info = buffer;
1912 if (ret_len) *ret_len = sizeof(*info);
1913 if (len == sizeof(*info))
1915 SERVER_START_REQ( query_completion )
1917 req->handle = wine_server_obj_handle( handle );
1918 if (!(status = wine_server_call( req ))) *info = reply->depth;
1920 SERVER_END_REQ;
1922 else status = STATUS_INFO_LENGTH_MISMATCH;
1923 break;
1925 default:
1926 return STATUS_INVALID_PARAMETER;
1928 return status;
1932 /***********************************************************************
1933 * NtCreateSection (NTDLL.@)
1935 NTSTATUS WINAPI NtCreateSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
1936 const LARGE_INTEGER *size, ULONG protect,
1937 ULONG sec_flags, HANDLE file )
1939 NTSTATUS ret;
1940 unsigned int file_access;
1941 data_size_t len;
1942 struct object_attributes *objattr;
1944 *handle = 0;
1946 switch (protect & 0xff)
1948 case PAGE_READONLY:
1949 case PAGE_EXECUTE_READ:
1950 case PAGE_WRITECOPY:
1951 case PAGE_EXECUTE_WRITECOPY:
1952 file_access = FILE_READ_DATA;
1953 break;
1954 case PAGE_READWRITE:
1955 case PAGE_EXECUTE_READWRITE:
1956 if (sec_flags & SEC_IMAGE) file_access = FILE_READ_DATA;
1957 else file_access = FILE_READ_DATA | FILE_WRITE_DATA;
1958 break;
1959 case PAGE_EXECUTE:
1960 case PAGE_NOACCESS:
1961 file_access = 0;
1962 break;
1963 default:
1964 return STATUS_INVALID_PAGE_PROTECTION;
1967 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1969 SERVER_START_REQ( create_mapping )
1971 req->access = access;
1972 req->flags = sec_flags;
1973 req->file_handle = wine_server_obj_handle( file );
1974 req->file_access = file_access;
1975 req->size = size ? size->QuadPart : 0;
1976 wine_server_add_data( req, objattr, len );
1977 ret = wine_server_call( req );
1978 *handle = wine_server_ptr_handle( reply->handle );
1980 SERVER_END_REQ;
1982 free( objattr );
1983 return ret;
1987 /***********************************************************************
1988 * NtOpenSection (NTDLL.@)
1990 NTSTATUS WINAPI NtOpenSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1992 NTSTATUS ret;
1994 *handle = 0;
1995 if ((ret = validate_open_object_attributes( attr ))) return ret;
1997 SERVER_START_REQ( open_mapping )
1999 req->access = access;
2000 req->attributes = attr->Attributes;
2001 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
2002 if (attr->ObjectName)
2003 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
2004 ret = wine_server_call( req );
2005 *handle = wine_server_ptr_handle( reply->handle );
2007 SERVER_END_REQ;
2008 return ret;
2012 /***********************************************************************
2013 * NtCreatePort (NTDLL.@)
2015 NTSTATUS WINAPI NtCreatePort( HANDLE *handle, OBJECT_ATTRIBUTES *attr, ULONG info_len,
2016 ULONG data_len, ULONG *reserved )
2018 FIXME( "(%p,%p,%u,%u,%p),stub!\n", handle, attr, info_len, data_len, reserved );
2019 return STATUS_NOT_IMPLEMENTED;
2023 /***********************************************************************
2024 * NtConnectPort (NTDLL.@)
2026 NTSTATUS WINAPI NtConnectPort( HANDLE *handle, UNICODE_STRING *name, SECURITY_QUALITY_OF_SERVICE *qos,
2027 LPC_SECTION_WRITE *write, LPC_SECTION_READ *read, ULONG *max_len,
2028 void *info, ULONG *info_len )
2030 FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p),stub!\n", handle, debugstr_us(name), qos,
2031 write, read, max_len, info, info_len );
2032 if (info && info_len) TRACE("msg = %s\n", debugstr_an( info, *info_len ));
2033 return STATUS_NOT_IMPLEMENTED;
2037 /***********************************************************************
2038 * NtSecureConnectPort (NTDLL.@)
2040 NTSTATUS WINAPI NtSecureConnectPort( HANDLE *handle, UNICODE_STRING *name, SECURITY_QUALITY_OF_SERVICE *qos,
2041 LPC_SECTION_WRITE *write, PSID sid, LPC_SECTION_READ *read,
2042 ULONG *max_len, void *info, ULONG *info_len )
2044 FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p,%p),stub!\n", handle, debugstr_us(name), qos,
2045 write, sid, read, max_len, info, info_len );
2046 return STATUS_NOT_IMPLEMENTED;
2050 /***********************************************************************
2051 * NtListenPort (NTDLL.@)
2053 NTSTATUS WINAPI NtListenPort( HANDLE handle, LPC_MESSAGE *msg )
2055 FIXME("(%p,%p),stub!\n", handle, msg );
2056 return STATUS_NOT_IMPLEMENTED;
2060 /***********************************************************************
2061 * NtAcceptConnectPort (NTDLL.@)
2063 NTSTATUS WINAPI NtAcceptConnectPort( HANDLE *handle, ULONG id, LPC_MESSAGE *msg, BOOLEAN accept,
2064 LPC_SECTION_WRITE *write, LPC_SECTION_READ *read )
2066 FIXME("(%p,%u,%p,%d,%p,%p),stub!\n", handle, id, msg, accept, write, read );
2067 return STATUS_NOT_IMPLEMENTED;
2071 /***********************************************************************
2072 * NtCompleteConnectPort (NTDLL.@)
2074 NTSTATUS WINAPI NtCompleteConnectPort( HANDLE handle )
2076 FIXME( "(%p),stub!\n", handle );
2077 return STATUS_NOT_IMPLEMENTED;
2081 /***********************************************************************
2082 * NtRegisterThreadTerminatePort (NTDLL.@)
2084 NTSTATUS WINAPI NtRegisterThreadTerminatePort( HANDLE handle )
2086 FIXME( "(%p),stub!\n", handle );
2087 return STATUS_NOT_IMPLEMENTED;
2091 /***********************************************************************
2092 * NtRequestWaitReplyPort (NTDLL.@)
2094 NTSTATUS WINAPI NtRequestWaitReplyPort( HANDLE handle, LPC_MESSAGE *msg_in, LPC_MESSAGE *msg_out )
2096 FIXME( "(%p,%p,%p),stub!\n", handle, msg_in, msg_out );
2097 if (msg_in)
2098 TRACE("datasize %u msgsize %u type %u ranges %u client %p/%p msgid %lu size %lu data %s\n",
2099 msg_in->DataSize, msg_in->MessageSize, msg_in->MessageType, msg_in->VirtualRangesOffset,
2100 msg_in->ClientId.UniqueProcess, msg_in->ClientId.UniqueThread, msg_in->MessageId,
2101 msg_in->SectionSize, debugstr_an( (const char *)msg_in->Data, msg_in->DataSize ));
2102 return STATUS_NOT_IMPLEMENTED;
2106 /***********************************************************************
2107 * NtReplyWaitReceivePort (NTDLL.@)
2109 NTSTATUS WINAPI NtReplyWaitReceivePort( HANDLE handle, ULONG *id, LPC_MESSAGE *reply, LPC_MESSAGE *msg )
2111 FIXME("(%p,%p,%p,%p),stub!\n", handle, id, reply, msg );
2112 return STATUS_NOT_IMPLEMENTED;
2116 #define MAX_ATOM_LEN 255
2117 #define IS_INTATOM(x) (((ULONG_PTR)(x) >> 16) == 0)
2119 static NTSTATUS is_integral_atom( const WCHAR *atomstr, ULONG len, RTL_ATOM *ret_atom )
2121 RTL_ATOM atom;
2123 if ((ULONG_PTR)atomstr >> 16)
2125 const WCHAR* ptr = atomstr;
2126 if (!len) return STATUS_OBJECT_NAME_INVALID;
2128 if (*ptr++ == '#')
2130 atom = 0;
2131 while (ptr < atomstr + len && *ptr >= '0' && *ptr <= '9')
2133 atom = atom * 10 + *ptr++ - '0';
2135 if (ptr > atomstr + 1 && ptr == atomstr + len) goto done;
2137 if (len > MAX_ATOM_LEN) return STATUS_INVALID_PARAMETER;
2138 return STATUS_MORE_ENTRIES;
2140 else atom = LOWORD( atomstr );
2141 done:
2142 if (!atom || atom >= MAXINTATOM) return STATUS_INVALID_PARAMETER;
2143 *ret_atom = atom;
2144 return STATUS_SUCCESS;
2147 static ULONG integral_atom_name( WCHAR *buffer, ULONG len, RTL_ATOM atom )
2149 char tmp[16];
2150 int ret = sprintf( tmp, "#%u", atom );
2152 len /= sizeof(WCHAR);
2153 if (len)
2155 if (len <= ret) ret = len - 1;
2156 ascii_to_unicode( buffer, tmp, ret );
2157 buffer[ret] = 0;
2159 return ret * sizeof(WCHAR);
2163 /***********************************************************************
2164 * NtAddAtom (NTDLL.@)
2166 NTSTATUS WINAPI NtAddAtom( const WCHAR *name, ULONG length, RTL_ATOM *atom )
2168 NTSTATUS status = is_integral_atom( name, length / sizeof(WCHAR), atom );
2170 if (status == STATUS_MORE_ENTRIES)
2172 SERVER_START_REQ( add_atom )
2174 wine_server_add_data( req, name, length );
2175 status = wine_server_call( req );
2176 *atom = reply->atom;
2178 SERVER_END_REQ;
2180 TRACE( "%s -> %x\n", debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
2181 return status;
2185 /***********************************************************************
2186 * NtDeleteAtom (NTDLL.@)
2188 NTSTATUS WINAPI NtDeleteAtom( RTL_ATOM atom )
2190 NTSTATUS status;
2192 SERVER_START_REQ( delete_atom )
2194 req->atom = atom;
2195 status = wine_server_call( req );
2197 SERVER_END_REQ;
2198 return status;
2202 /***********************************************************************
2203 * NtFindAtom (NTDLL.@)
2205 NTSTATUS WINAPI NtFindAtom( const WCHAR *name, ULONG length, RTL_ATOM *atom )
2207 NTSTATUS status = is_integral_atom( name, length / sizeof(WCHAR), atom );
2209 if (status == STATUS_MORE_ENTRIES)
2211 SERVER_START_REQ( find_atom )
2213 wine_server_add_data( req, name, length );
2214 status = wine_server_call( req );
2215 *atom = reply->atom;
2217 SERVER_END_REQ;
2219 TRACE( "%s -> %x\n", debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
2220 return status;
2224 /***********************************************************************
2225 * NtQueryInformationAtom (NTDLL.@)
2227 NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS class,
2228 void *ptr, ULONG size, ULONG *retsize )
2230 NTSTATUS status;
2232 switch (class)
2234 case AtomBasicInformation:
2236 ULONG name_len;
2237 ATOM_BASIC_INFORMATION *abi = ptr;
2239 if (size < sizeof(ATOM_BASIC_INFORMATION)) return STATUS_INVALID_PARAMETER;
2240 name_len = size - sizeof(ATOM_BASIC_INFORMATION);
2242 if (atom < MAXINTATOM)
2244 if (atom)
2246 abi->NameLength = integral_atom_name( abi->Name, name_len, atom );
2247 status = name_len ? STATUS_SUCCESS : STATUS_BUFFER_TOO_SMALL;
2248 abi->ReferenceCount = 1;
2249 abi->Pinned = 1;
2251 else status = STATUS_INVALID_PARAMETER;
2253 else
2255 SERVER_START_REQ( get_atom_information )
2257 req->atom = atom;
2258 if (name_len) wine_server_set_reply( req, abi->Name, name_len );
2259 status = wine_server_call( req );
2260 if (status == STATUS_SUCCESS)
2262 name_len = wine_server_reply_size( reply );
2263 if (name_len)
2265 abi->NameLength = name_len;
2266 abi->Name[name_len / sizeof(WCHAR)] = 0;
2268 else
2270 name_len = reply->total;
2271 abi->NameLength = name_len;
2272 status = STATUS_BUFFER_TOO_SMALL;
2274 abi->ReferenceCount = reply->count;
2275 abi->Pinned = reply->pinned;
2277 else name_len = 0;
2279 SERVER_END_REQ;
2281 TRACE( "%x -> %s (%u)\n", atom, debugstr_wn(abi->Name, abi->NameLength / sizeof(WCHAR)), status );
2282 if (retsize) *retsize = sizeof(ATOM_BASIC_INFORMATION) + name_len;
2283 break;
2286 default:
2287 FIXME( "Unsupported class %u\n", class );
2288 status = STATUS_INVALID_INFO_CLASS;
2289 break;
2291 return status;
2295 #ifdef __linux__
2297 NTSTATUS CDECL fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit, int timeout )
2299 int val;
2300 struct timespec timespec;
2302 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2304 timespec.tv_sec = timeout;
2305 timespec.tv_nsec = 0;
2306 while ((val = InterlockedCompareExchange( (int *)&crit->LockSemaphore, 0, 1 )) != 1)
2308 /* note: this may wait longer than specified in case of signals or */
2309 /* multiple wake-ups, but that shouldn't be a problem */
2310 if (futex_wait( (int *)&crit->LockSemaphore, val, &timespec ) == -1 && errno == ETIMEDOUT)
2311 return STATUS_TIMEOUT;
2313 return STATUS_WAIT_0;
2316 NTSTATUS CDECL fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit )
2318 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2320 *(int *)&crit->LockSemaphore = 1;
2321 futex_wake( (int *)&crit->LockSemaphore, 1 );
2322 return STATUS_SUCCESS;
2325 NTSTATUS CDECL fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit )
2327 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2328 return STATUS_SUCCESS;
2331 #elif defined(__APPLE__)
2333 static inline semaphore_t get_mach_semaphore( RTL_CRITICAL_SECTION *crit )
2335 semaphore_t ret = *(int *)&crit->LockSemaphore;
2336 if (!ret)
2338 semaphore_t sem;
2339 if (semaphore_create( mach_task_self(), &sem, SYNC_POLICY_FIFO, 0 )) return 0;
2340 if (!(ret = InterlockedCompareExchange( (int *)&crit->LockSemaphore, sem, 0 )))
2341 ret = sem;
2342 else
2343 semaphore_destroy( mach_task_self(), sem ); /* somebody beat us to it */
2345 return ret;
2348 NTSTATUS CDECL fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit, int timeout )
2350 mach_timespec_t timespec;
2351 semaphore_t sem = get_mach_semaphore( crit );
2353 timespec.tv_sec = timeout;
2354 timespec.tv_nsec = 0;
2355 for (;;)
2357 switch( semaphore_timedwait( sem, timespec ))
2359 case KERN_SUCCESS:
2360 return STATUS_WAIT_0;
2361 case KERN_ABORTED:
2362 continue; /* got a signal, restart */
2363 case KERN_OPERATION_TIMED_OUT:
2364 return STATUS_TIMEOUT;
2365 default:
2366 return STATUS_INVALID_HANDLE;
2371 NTSTATUS CDECL fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit )
2373 semaphore_t sem = get_mach_semaphore( crit );
2374 semaphore_signal( sem );
2375 return STATUS_SUCCESS;
2378 NTSTATUS CDECL fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit )
2380 semaphore_destroy( mach_task_self(), *(int *)&crit->LockSemaphore );
2381 return STATUS_SUCCESS;
2384 #else /* __APPLE__ */
2386 NTSTATUS CDECL fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit, int timeout )
2388 return STATUS_NOT_IMPLEMENTED;
2391 NTSTATUS CDECL fast_RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit )
2393 return STATUS_NOT_IMPLEMENTED;
2396 NTSTATUS CDECL fast_RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit )
2398 return STATUS_NOT_IMPLEMENTED;
2401 #endif
2404 #ifdef __linux__
2406 /* Futex-based SRW lock implementation:
2408 * Since we can rely on the kernel to release all threads and don't need to
2409 * worry about NtReleaseKeyedEvent(), we can simplify the layout a bit. The
2410 * layout looks like this:
2412 * 31 - Exclusive lock bit, set if the resource is owned exclusively.
2413 * 30-16 - Number of exclusive waiters. Unlike the fallback implementation,
2414 * this does not include the thread owning the lock, or shared threads
2415 * waiting on the lock.
2416 * 15 - Does this lock have any shared waiters? We use this as an
2417 * optimization to avoid unnecessary FUTEX_WAKE_BITSET calls when
2418 * releasing an exclusive lock.
2419 * 14-0 - Number of shared owners. Unlike the fallback implementation, this
2420 * does not include the number of shared threads waiting on the lock.
2421 * Thus the state [1, x, >=1] will never occur.
2424 #define SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT 0x80000000
2425 #define SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK 0x7fff0000
2426 #define SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC 0x00010000
2427 #define SRWLOCK_FUTEX_SHARED_WAITERS_BIT 0x00008000
2428 #define SRWLOCK_FUTEX_SHARED_OWNERS_MASK 0x00007fff
2429 #define SRWLOCK_FUTEX_SHARED_OWNERS_INC 0x00000001
2431 /* Futex bitmasks; these are independent from the bits in the lock itself. */
2432 #define SRWLOCK_FUTEX_BITSET_EXCLUSIVE 1
2433 #define SRWLOCK_FUTEX_BITSET_SHARED 2
2435 NTSTATUS CDECL fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
2437 int old, new, *futex;
2438 NTSTATUS ret;
2440 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2442 if (!(futex = get_futex( &lock->Ptr )))
2443 return STATUS_NOT_IMPLEMENTED;
2447 old = *futex;
2449 if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
2450 && !(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK))
2452 /* Not locked exclusive or shared. We can try to grab it. */
2453 new = old | SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT;
2454 ret = STATUS_SUCCESS;
2456 else
2458 new = old;
2459 ret = STATUS_TIMEOUT;
2461 } while (InterlockedCompareExchange( futex, new, old ) != old);
2463 return ret;
2466 NTSTATUS CDECL fast_RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
2468 int old, new, *futex;
2469 BOOLEAN wait;
2471 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2473 if (!(futex = get_futex( &lock->Ptr )))
2474 return STATUS_NOT_IMPLEMENTED;
2476 /* Atomically increment the exclusive waiter count. */
2479 old = *futex;
2480 new = old + SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC;
2481 assert(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK);
2482 } while (InterlockedCompareExchange( futex, new, old ) != old);
2484 for (;;)
2488 old = *futex;
2490 if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
2491 && !(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK))
2493 /* Not locked exclusive or shared. We can try to grab it. */
2494 new = old | SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT;
2495 assert(old & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK);
2496 new -= SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_INC;
2497 wait = FALSE;
2499 else
2501 new = old;
2502 wait = TRUE;
2504 } while (InterlockedCompareExchange( futex, new, old ) != old);
2506 if (!wait)
2507 return STATUS_SUCCESS;
2509 futex_wait_bitset( futex, new, NULL, SRWLOCK_FUTEX_BITSET_EXCLUSIVE );
2512 return STATUS_SUCCESS;
2515 NTSTATUS CDECL fast_RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock )
2517 int new, old, *futex;
2518 NTSTATUS ret;
2520 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2522 if (!(futex = get_futex( &lock->Ptr )))
2523 return STATUS_NOT_IMPLEMENTED;
2527 old = *futex;
2529 if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
2530 && !(old & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
2532 /* Not locked exclusive, and no exclusive waiters. We can try to
2533 * grab it. */
2534 new = old + SRWLOCK_FUTEX_SHARED_OWNERS_INC;
2535 assert(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK);
2536 ret = STATUS_SUCCESS;
2538 else
2540 new = old;
2541 ret = STATUS_TIMEOUT;
2543 } while (InterlockedCompareExchange( futex, new, old ) != old);
2545 return ret;
2548 NTSTATUS CDECL fast_RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
2550 int old, new, *futex;
2551 BOOLEAN wait;
2553 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2555 if (!(futex = get_futex( &lock->Ptr )))
2556 return STATUS_NOT_IMPLEMENTED;
2558 for (;;)
2562 old = *futex;
2564 if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
2565 && !(old & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
2567 /* Not locked exclusive, and no exclusive waiters. We can try
2568 * to grab it. */
2569 new = old + SRWLOCK_FUTEX_SHARED_OWNERS_INC;
2570 assert(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK);
2571 wait = FALSE;
2573 else
2575 new = old | SRWLOCK_FUTEX_SHARED_WAITERS_BIT;
2576 wait = TRUE;
2578 } while (InterlockedCompareExchange( futex, new, old ) != old);
2580 if (!wait)
2581 return STATUS_SUCCESS;
2583 futex_wait_bitset( futex, new, NULL, SRWLOCK_FUTEX_BITSET_SHARED );
2586 return STATUS_SUCCESS;
2589 NTSTATUS CDECL fast_RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
2591 int old, new, *futex;
2593 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2595 if (!(futex = get_futex( &lock->Ptr )))
2596 return STATUS_NOT_IMPLEMENTED;
2600 old = *futex;
2602 if (!(old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT))
2604 ERR("Lock %p is not owned exclusive! (%#x)\n", lock, *futex);
2605 return STATUS_RESOURCE_NOT_OWNED;
2608 new = old & ~SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT;
2610 if (!(new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
2611 new &= ~SRWLOCK_FUTEX_SHARED_WAITERS_BIT;
2612 } while (InterlockedCompareExchange( futex, new, old ) != old);
2614 if (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK)
2615 futex_wake_bitset( futex, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE );
2616 else if (old & SRWLOCK_FUTEX_SHARED_WAITERS_BIT)
2617 futex_wake_bitset( futex, INT_MAX, SRWLOCK_FUTEX_BITSET_SHARED );
2619 return STATUS_SUCCESS;
2622 NTSTATUS CDECL fast_RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
2624 int old, new, *futex;
2626 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2628 if (!(futex = get_futex( &lock->Ptr )))
2629 return STATUS_NOT_IMPLEMENTED;
2633 old = *futex;
2635 if (old & SRWLOCK_FUTEX_EXCLUSIVE_LOCK_BIT)
2637 ERR("Lock %p is owned exclusive! (%#x)\n", lock, *futex);
2638 return STATUS_RESOURCE_NOT_OWNED;
2640 else if (!(old & SRWLOCK_FUTEX_SHARED_OWNERS_MASK))
2642 ERR("Lock %p is not owned shared! (%#x)\n", lock, *futex);
2643 return STATUS_RESOURCE_NOT_OWNED;
2646 new = old - SRWLOCK_FUTEX_SHARED_OWNERS_INC;
2647 } while (InterlockedCompareExchange( futex, new, old ) != old);
2649 /* Optimization: only bother waking if there are actually exclusive waiters. */
2650 if (!(new & SRWLOCK_FUTEX_SHARED_OWNERS_MASK) && (new & SRWLOCK_FUTEX_EXCLUSIVE_WAITERS_MASK))
2651 futex_wake_bitset( futex, 1, SRWLOCK_FUTEX_BITSET_EXCLUSIVE );
2653 return STATUS_SUCCESS;
2656 NTSTATUS CDECL fast_wait_cv( RTL_CONDITION_VARIABLE *variable, const void *value, const LARGE_INTEGER *timeout )
2658 const char *value_ptr;
2659 int aligned_value, *futex;
2660 struct timespec timespec;
2661 int ret;
2663 if (!use_futexes())
2664 return STATUS_NOT_IMPLEMENTED;
2666 if (!(futex = get_futex( &variable->Ptr )))
2667 return STATUS_NOT_IMPLEMENTED;
2669 value_ptr = (const char *)&value;
2670 value_ptr += ((ULONG_PTR)futex) - ((ULONG_PTR)&variable->Ptr);
2671 aligned_value = *(int *)value_ptr;
2673 if (timeout && timeout->QuadPart != TIMEOUT_INFINITE)
2675 timespec_from_timeout( &timespec, timeout );
2676 ret = futex_wait( futex, aligned_value, &timespec );
2678 else
2679 ret = futex_wait( futex, aligned_value, NULL );
2681 if (ret == -1 && errno == ETIMEDOUT)
2682 return STATUS_TIMEOUT;
2683 return STATUS_WAIT_0;
2686 NTSTATUS CDECL fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable, int count )
2688 int *futex;
2690 if (!use_futexes()) return STATUS_NOT_IMPLEMENTED;
2692 if (!(futex = get_futex( &variable->Ptr )))
2693 return STATUS_NOT_IMPLEMENTED;
2695 InterlockedIncrement( futex );
2696 futex_wake( futex, count );
2697 return STATUS_SUCCESS;
2701 /* We can't map addresses to futex directly, because an application can wait on
2702 * 8 bytes, and we can't pass all 8 as the compare value to futex(). Instead we
2703 * map all addresses to a small fixed table of futexes. This may result in
2704 * spurious wakes, but the application is already expected to handle those. */
2706 static int addr_futex_table[256];
2708 static inline int *hash_addr( const void *addr )
2710 ULONG_PTR val = (ULONG_PTR)addr;
2712 return &addr_futex_table[(val >> 2) & 255];
2715 static inline NTSTATUS fast_wait_addr( const void *addr, const void *cmp, SIZE_T size,
2716 const LARGE_INTEGER *timeout )
2718 int *futex;
2719 int val;
2720 struct timespec timespec;
2721 int ret;
2723 if (!use_futexes())
2724 return STATUS_NOT_IMPLEMENTED;
2726 futex = hash_addr( addr );
2728 /* We must read the previous value of the futex before checking the value
2729 * of the address being waited on. That way, if we receive a wake between
2730 * now and waiting on the futex, we know that val will have changed.
2731 * Use an atomic load so that memory accesses are ordered between this read
2732 * and the increment below. */
2733 val = InterlockedCompareExchange( futex, 0, 0 );
2734 if (!compare_addr( addr, cmp, size ))
2735 return STATUS_SUCCESS;
2737 if (timeout)
2739 timespec_from_timeout( &timespec, timeout );
2740 ret = futex_wait( futex, val, &timespec );
2742 else
2743 ret = futex_wait( futex, val, NULL );
2745 if (ret == -1 && errno == ETIMEDOUT)
2746 return STATUS_TIMEOUT;
2747 return STATUS_SUCCESS;
2750 static inline NTSTATUS fast_wake_addr( const void *addr )
2752 int *futex;
2754 if (!use_futexes())
2755 return STATUS_NOT_IMPLEMENTED;
2757 futex = hash_addr( addr );
2759 InterlockedIncrement( futex );
2761 futex_wake( futex, INT_MAX );
2762 return STATUS_SUCCESS;
2765 #else
2767 NTSTATUS CDECL fast_RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
2769 return STATUS_NOT_IMPLEMENTED;
2772 NTSTATUS CDECL fast_RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
2774 return STATUS_NOT_IMPLEMENTED;
2777 NTSTATUS CDECL fast_RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock )
2779 return STATUS_NOT_IMPLEMENTED;
2782 NTSTATUS CDECL fast_RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
2784 return STATUS_NOT_IMPLEMENTED;
2787 NTSTATUS CDECL fast_RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
2789 return STATUS_NOT_IMPLEMENTED;
2792 NTSTATUS CDECL fast_RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
2794 return STATUS_NOT_IMPLEMENTED;
2797 NTSTATUS CDECL fast_RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable, int count )
2799 return STATUS_NOT_IMPLEMENTED;
2802 NTSTATUS CDECL fast_wait_cv( RTL_CONDITION_VARIABLE *variable, const void *value, const LARGE_INTEGER *timeout )
2804 return STATUS_NOT_IMPLEMENTED;
2807 static inline NTSTATUS fast_wait_addr( const void *addr, const void *cmp, SIZE_T size,
2808 const LARGE_INTEGER *timeout )
2810 return STATUS_NOT_IMPLEMENTED;
2813 static inline NTSTATUS fast_wake_addr( const void *addr )
2815 return STATUS_NOT_IMPLEMENTED;
2818 #endif
2821 /***********************************************************************
2822 * RtlWaitOnAddress (NTDLL.@)
2824 NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size,
2825 const LARGE_INTEGER *timeout )
2827 select_op_t select_op;
2828 NTSTATUS ret;
2829 timeout_t abs_timeout = timeout ? timeout->QuadPart : TIMEOUT_INFINITE;
2831 if (size != 1 && size != 2 && size != 4 && size != 8)
2832 return STATUS_INVALID_PARAMETER;
2834 if ((ret = fast_wait_addr( addr, cmp, size, timeout )) != STATUS_NOT_IMPLEMENTED)
2835 return ret;
2837 mutex_lock( &addr_mutex );
2838 if (!compare_addr( addr, cmp, size ))
2840 mutex_unlock( &addr_mutex );
2841 return STATUS_SUCCESS;
2844 if (abs_timeout < 0)
2846 LARGE_INTEGER now;
2848 NtQueryPerformanceCounter( &now, NULL );
2849 abs_timeout -= now.QuadPart;
2852 select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT;
2853 select_op.keyed_event.handle = wine_server_obj_handle( keyed_event );
2854 select_op.keyed_event.key = wine_server_client_ptr( addr );
2856 return server_select( &select_op, sizeof(select_op.keyed_event), SELECT_INTERRUPTIBLE,
2857 abs_timeout, NULL, &addr_mutex, NULL );
2860 /***********************************************************************
2861 * RtlWakeAddressAll (NTDLL.@)
2863 void WINAPI RtlWakeAddressAll( const void *addr )
2865 if (fast_wake_addr( addr ) != STATUS_NOT_IMPLEMENTED) return;
2867 mutex_lock( &addr_mutex );
2868 while (NtReleaseKeyedEvent( 0, addr, 0, &zero_timeout ) == STATUS_SUCCESS) {}
2869 mutex_unlock( &addr_mutex );
2872 /***********************************************************************
2873 * RtlWakeAddressSingle (NTDLL.@)
2875 void WINAPI RtlWakeAddressSingle( const void *addr )
2877 if (fast_wake_addr( addr ) != STATUS_NOT_IMPLEMENTED) return;
2879 mutex_lock( &addr_mutex );
2880 NtReleaseKeyedEvent( 0, addr, 0, &zero_timeout );
2881 mutex_unlock( &addr_mutex );