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