ntdll: Reimplement SRW locks on top of Win32 futexes.
[wine.git] / dlls / ntdll / unix / sync.c
blob0065f265e42547631cbafd6571750acf8094d807
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 #ifdef HAVE_SYS_MMAN_H
37 #include <sys/mman.h>
38 #endif
39 #ifdef HAVE_SYS_SYSCALL_H
40 #include <sys/syscall.h>
41 #endif
42 #ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
44 #endif
45 #include <poll.h>
46 #include <unistd.h>
47 #ifdef HAVE_SCHED_H
48 # include <sched.h>
49 #endif
50 #include <string.h>
51 #include <stdarg.h>
52 #include <stdio.h>
53 #include <stdlib.h>
54 #include <time.h>
55 #ifdef __APPLE__
56 # include <mach/mach.h>
57 # include <mach/task.h>
58 # include <mach/semaphore.h>
59 # include <mach/mach_time.h>
60 #endif
62 #include "ntstatus.h"
63 #define WIN32_NO_STATUS
64 #define NONAMELESSUNION
65 #include "windef.h"
66 #include "winternl.h"
67 #include "ddk/wdm.h"
68 #include "wine/server.h"
69 #include "wine/debug.h"
70 #include "unix_private.h"
72 WINE_DEFAULT_DEBUG_CHANNEL(sync);
74 HANDLE keyed_event = 0;
76 static const char *debugstr_timeout( const LARGE_INTEGER *timeout )
78 if (!timeout) return "(infinite)";
79 return wine_dbgstr_longlong( timeout->QuadPart );
82 /* return a monotonic time counter, in Win32 ticks */
83 static inline ULONGLONG monotonic_counter(void)
85 struct timeval now;
86 #ifdef __APPLE__
87 static mach_timebase_info_data_t timebase;
89 if (!timebase.denom) mach_timebase_info( &timebase );
90 #ifdef HAVE_MACH_CONTINUOUS_TIME
91 if (&mach_continuous_time != NULL)
92 return mach_continuous_time() * timebase.numer / timebase.denom / 100;
93 #endif
94 return mach_absolute_time() * timebase.numer / timebase.denom / 100;
95 #elif defined(HAVE_CLOCK_GETTIME)
96 struct timespec ts;
97 #ifdef CLOCK_MONOTONIC_RAW
98 if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts ))
99 return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
100 #endif
101 if (!clock_gettime( CLOCK_MONOTONIC, &ts ))
102 return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100;
103 #endif
104 gettimeofday( &now, 0 );
105 return ticks_from_time_t( now.tv_sec ) + now.tv_usec * 10 - server_start_time;
109 #ifdef __linux__
111 #define FUTEX_WAIT 0
112 #define FUTEX_WAKE 1
114 static int futex_private = 128;
116 static inline int futex_wait( const int *addr, int val, struct timespec *timeout )
118 return syscall( __NR_futex, addr, FUTEX_WAIT | futex_private, val, timeout, 0, 0 );
121 static inline int futex_wake( const int *addr, int val )
123 return syscall( __NR_futex, addr, FUTEX_WAKE | futex_private, val, NULL, 0, 0 );
126 static inline int use_futexes(void)
128 static int supported = -1;
130 if (supported == -1)
132 futex_wait( &supported, 10, NULL );
133 if (errno == ENOSYS)
135 futex_private = 0;
136 futex_wait( &supported, 10, NULL );
138 supported = (errno != ENOSYS);
140 return supported;
143 #endif
146 /* create a struct security_descriptor and contained information in one contiguous piece of memory */
147 NTSTATUS alloc_object_attributes( const OBJECT_ATTRIBUTES *attr, struct object_attributes **ret,
148 data_size_t *ret_len )
150 unsigned int len = sizeof(**ret);
151 SID *owner = NULL, *group = NULL;
152 ACL *dacl = NULL, *sacl = NULL;
153 SECURITY_DESCRIPTOR *sd;
155 *ret = NULL;
156 *ret_len = 0;
158 if (!attr) return STATUS_SUCCESS;
160 if (attr->Length != sizeof(*attr)) return STATUS_INVALID_PARAMETER;
162 if ((sd = attr->SecurityDescriptor))
164 len += sizeof(struct security_descriptor);
165 if (sd->Revision != SECURITY_DESCRIPTOR_REVISION) return STATUS_UNKNOWN_REVISION;
166 if (sd->Control & SE_SELF_RELATIVE)
168 SECURITY_DESCRIPTOR_RELATIVE *rel = (SECURITY_DESCRIPTOR_RELATIVE *)sd;
169 if (rel->Owner) owner = (PSID)((BYTE *)rel + rel->Owner);
170 if (rel->Group) group = (PSID)((BYTE *)rel + rel->Group);
171 if ((sd->Control & SE_SACL_PRESENT) && rel->Sacl) sacl = (PSID)((BYTE *)rel + rel->Sacl);
172 if ((sd->Control & SE_DACL_PRESENT) && rel->Dacl) dacl = (PSID)((BYTE *)rel + rel->Dacl);
174 else
176 owner = sd->Owner;
177 group = sd->Group;
178 if (sd->Control & SE_SACL_PRESENT) sacl = sd->Sacl;
179 if (sd->Control & SE_DACL_PRESENT) dacl = sd->Dacl;
182 if (owner) len += offsetof( SID, SubAuthority[owner->SubAuthorityCount] );
183 if (group) len += offsetof( SID, SubAuthority[group->SubAuthorityCount] );
184 if (sacl) len += sacl->AclSize;
185 if (dacl) len += dacl->AclSize;
187 /* fix alignment for the Unicode name that follows the structure */
188 len = (len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
191 if (attr->ObjectName)
193 if ((ULONG_PTR)attr->ObjectName->Buffer & (sizeof(WCHAR) - 1)) return STATUS_DATATYPE_MISALIGNMENT;
194 if (attr->ObjectName->Length & (sizeof(WCHAR) - 1)) return STATUS_OBJECT_NAME_INVALID;
195 len += attr->ObjectName->Length;
197 else if (attr->RootDirectory) return STATUS_OBJECT_NAME_INVALID;
199 len = (len + 3) & ~3; /* DWORD-align the entire structure */
201 if (!(*ret = calloc( len, 1 ))) return STATUS_NO_MEMORY;
203 (*ret)->rootdir = wine_server_obj_handle( attr->RootDirectory );
204 (*ret)->attributes = attr->Attributes;
206 if (attr->SecurityDescriptor)
208 struct security_descriptor *descr = (struct security_descriptor *)(*ret + 1);
209 unsigned char *ptr = (unsigned char *)(descr + 1);
211 descr->control = sd->Control & ~SE_SELF_RELATIVE;
212 if (owner) descr->owner_len = offsetof( SID, SubAuthority[owner->SubAuthorityCount] );
213 if (group) descr->group_len = offsetof( SID, SubAuthority[group->SubAuthorityCount] );
214 if (sacl) descr->sacl_len = sacl->AclSize;
215 if (dacl) descr->dacl_len = dacl->AclSize;
217 memcpy( ptr, owner, descr->owner_len );
218 ptr += descr->owner_len;
219 memcpy( ptr, group, descr->group_len );
220 ptr += descr->group_len;
221 memcpy( ptr, sacl, descr->sacl_len );
222 ptr += descr->sacl_len;
223 memcpy( ptr, dacl, descr->dacl_len );
224 (*ret)->sd_len = (sizeof(*descr) + descr->owner_len + descr->group_len + descr->sacl_len +
225 descr->dacl_len + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
228 if (attr->ObjectName)
230 unsigned char *ptr = (unsigned char *)(*ret + 1) + (*ret)->sd_len;
231 (*ret)->name_len = attr->ObjectName->Length;
232 memcpy( ptr, attr->ObjectName->Buffer, (*ret)->name_len );
235 *ret_len = len;
236 return STATUS_SUCCESS;
240 static NTSTATUS validate_open_object_attributes( const OBJECT_ATTRIBUTES *attr )
242 if (!attr || attr->Length != sizeof(*attr)) return STATUS_INVALID_PARAMETER;
244 if (attr->ObjectName)
246 if ((ULONG_PTR)attr->ObjectName->Buffer & (sizeof(WCHAR) - 1)) return STATUS_DATATYPE_MISALIGNMENT;
247 if (attr->ObjectName->Length & (sizeof(WCHAR) - 1)) return STATUS_OBJECT_NAME_INVALID;
249 else if (attr->RootDirectory) return STATUS_OBJECT_NAME_INVALID;
251 return STATUS_SUCCESS;
255 /******************************************************************************
256 * NtCreateSemaphore (NTDLL.@)
258 NTSTATUS WINAPI NtCreateSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
259 LONG initial, LONG max )
261 NTSTATUS ret;
262 data_size_t len;
263 struct object_attributes *objattr;
265 *handle = 0;
266 if (max <= 0 || initial < 0 || initial > max) return STATUS_INVALID_PARAMETER;
267 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
269 SERVER_START_REQ( create_semaphore )
271 req->access = access;
272 req->initial = initial;
273 req->max = max;
274 wine_server_add_data( req, objattr, len );
275 ret = wine_server_call( req );
276 *handle = wine_server_ptr_handle( reply->handle );
278 SERVER_END_REQ;
280 free( objattr );
281 return ret;
285 /******************************************************************************
286 * NtOpenSemaphore (NTDLL.@)
288 NTSTATUS WINAPI NtOpenSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
290 NTSTATUS ret;
292 *handle = 0;
293 if ((ret = validate_open_object_attributes( attr ))) return ret;
295 SERVER_START_REQ( open_semaphore )
297 req->access = access;
298 req->attributes = attr->Attributes;
299 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
300 if (attr->ObjectName)
301 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
302 ret = wine_server_call( req );
303 *handle = wine_server_ptr_handle( reply->handle );
305 SERVER_END_REQ;
306 return ret;
310 /******************************************************************************
311 * NtQuerySemaphore (NTDLL.@)
313 NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS class,
314 void *info, ULONG len, ULONG *ret_len )
316 NTSTATUS ret;
317 SEMAPHORE_BASIC_INFORMATION *out = info;
319 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, len, ret_len);
321 if (class != SemaphoreBasicInformation)
323 FIXME("(%p,%d,%u) Unknown class\n", handle, class, len);
324 return STATUS_INVALID_INFO_CLASS;
327 if (len != sizeof(SEMAPHORE_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
329 SERVER_START_REQ( query_semaphore )
331 req->handle = wine_server_obj_handle( handle );
332 if (!(ret = wine_server_call( req )))
334 out->CurrentCount = reply->current;
335 out->MaximumCount = reply->max;
336 if (ret_len) *ret_len = sizeof(SEMAPHORE_BASIC_INFORMATION);
339 SERVER_END_REQ;
340 return ret;
344 /******************************************************************************
345 * NtReleaseSemaphore (NTDLL.@)
347 NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, ULONG *previous )
349 NTSTATUS ret;
351 SERVER_START_REQ( release_semaphore )
353 req->handle = wine_server_obj_handle( handle );
354 req->count = count;
355 if (!(ret = wine_server_call( req )))
357 if (previous) *previous = reply->prev_count;
360 SERVER_END_REQ;
361 return ret;
365 /**************************************************************************
366 * NtCreateEvent (NTDLL.@)
368 NTSTATUS WINAPI NtCreateEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
369 EVENT_TYPE type, BOOLEAN state )
371 NTSTATUS ret;
372 data_size_t len;
373 struct object_attributes *objattr;
375 *handle = 0;
376 if (type != NotificationEvent && type != SynchronizationEvent) return STATUS_INVALID_PARAMETER;
377 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
379 SERVER_START_REQ( create_event )
381 req->access = access;
382 req->manual_reset = (type == NotificationEvent);
383 req->initial_state = state;
384 wine_server_add_data( req, objattr, len );
385 ret = wine_server_call( req );
386 *handle = wine_server_ptr_handle( reply->handle );
388 SERVER_END_REQ;
390 free( objattr );
391 return ret;
395 /******************************************************************************
396 * NtOpenEvent (NTDLL.@)
398 NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
400 NTSTATUS ret;
402 *handle = 0;
403 if ((ret = validate_open_object_attributes( attr ))) return ret;
405 SERVER_START_REQ( open_event )
407 req->access = access;
408 req->attributes = attr->Attributes;
409 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
410 if (attr->ObjectName)
411 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
412 ret = wine_server_call( req );
413 *handle = wine_server_ptr_handle( reply->handle );
415 SERVER_END_REQ;
416 return ret;
420 /******************************************************************************
421 * NtSetEvent (NTDLL.@)
423 NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state )
425 NTSTATUS ret;
427 SERVER_START_REQ( event_op )
429 req->handle = wine_server_obj_handle( handle );
430 req->op = SET_EVENT;
431 ret = wine_server_call( req );
432 if (!ret && prev_state) *prev_state = reply->state;
434 SERVER_END_REQ;
435 return ret;
439 /******************************************************************************
440 * NtResetEvent (NTDLL.@)
442 NTSTATUS WINAPI NtResetEvent( HANDLE handle, LONG *prev_state )
444 NTSTATUS ret;
446 SERVER_START_REQ( event_op )
448 req->handle = wine_server_obj_handle( handle );
449 req->op = RESET_EVENT;
450 ret = wine_server_call( req );
451 if (!ret && prev_state) *prev_state = reply->state;
453 SERVER_END_REQ;
454 return ret;
458 /******************************************************************************
459 * NtClearEvent (NTDLL.@)
461 NTSTATUS WINAPI NtClearEvent( HANDLE handle )
463 /* FIXME: same as NtResetEvent ??? */
464 return NtResetEvent( handle, NULL );
468 /******************************************************************************
469 * NtPulseEvent (NTDLL.@)
471 NTSTATUS WINAPI NtPulseEvent( HANDLE handle, LONG *prev_state )
473 NTSTATUS ret;
475 SERVER_START_REQ( event_op )
477 req->handle = wine_server_obj_handle( handle );
478 req->op = PULSE_EVENT;
479 ret = wine_server_call( req );
480 if (!ret && prev_state) *prev_state = reply->state;
482 SERVER_END_REQ;
483 return ret;
487 /******************************************************************************
488 * NtQueryEvent (NTDLL.@)
490 NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class,
491 void *info, ULONG len, ULONG *ret_len )
493 NTSTATUS ret;
494 EVENT_BASIC_INFORMATION *out = info;
496 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, len, ret_len);
498 if (class != EventBasicInformation)
500 FIXME("(%p, %d, %d) Unknown class\n",
501 handle, class, len);
502 return STATUS_INVALID_INFO_CLASS;
505 if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
507 SERVER_START_REQ( query_event )
509 req->handle = wine_server_obj_handle( handle );
510 if (!(ret = wine_server_call( req )))
512 out->EventType = reply->manual_reset ? NotificationEvent : SynchronizationEvent;
513 out->EventState = reply->state;
514 if (ret_len) *ret_len = sizeof(EVENT_BASIC_INFORMATION);
517 SERVER_END_REQ;
518 return ret;
522 /******************************************************************************
523 * NtCreateMutant (NTDLL.@)
525 NTSTATUS WINAPI NtCreateMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
526 BOOLEAN owned )
528 NTSTATUS ret;
529 data_size_t len;
530 struct object_attributes *objattr;
532 *handle = 0;
533 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
535 SERVER_START_REQ( create_mutex )
537 req->access = access;
538 req->owned = owned;
539 wine_server_add_data( req, objattr, len );
540 ret = wine_server_call( req );
541 *handle = wine_server_ptr_handle( reply->handle );
543 SERVER_END_REQ;
545 free( objattr );
546 return ret;
550 /**************************************************************************
551 * NtOpenMutant (NTDLL.@)
553 NTSTATUS WINAPI NtOpenMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
555 NTSTATUS ret;
557 *handle = 0;
558 if ((ret = validate_open_object_attributes( attr ))) return ret;
560 SERVER_START_REQ( open_mutex )
562 req->access = access;
563 req->attributes = attr->Attributes;
564 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
565 if (attr->ObjectName)
566 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
567 ret = wine_server_call( req );
568 *handle = wine_server_ptr_handle( reply->handle );
570 SERVER_END_REQ;
571 return ret;
575 /**************************************************************************
576 * NtReleaseMutant (NTDLL.@)
578 NTSTATUS WINAPI NtReleaseMutant( HANDLE handle, LONG *prev_count )
580 NTSTATUS ret;
582 SERVER_START_REQ( release_mutex )
584 req->handle = wine_server_obj_handle( handle );
585 ret = wine_server_call( req );
586 if (prev_count) *prev_count = 1 - reply->prev_count;
588 SERVER_END_REQ;
589 return ret;
593 /******************************************************************
594 * NtQueryMutant (NTDLL.@)
596 NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class,
597 void *info, ULONG len, ULONG *ret_len )
599 NTSTATUS ret;
600 MUTANT_BASIC_INFORMATION *out = info;
602 TRACE("(%p, %u, %p, %u, %p)\n", handle, class, info, len, ret_len);
604 if (class != MutantBasicInformation)
606 FIXME( "(%p, %d, %d) Unknown class\n", handle, class, len );
607 return STATUS_INVALID_INFO_CLASS;
610 if (len != sizeof(MUTANT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
612 SERVER_START_REQ( query_mutex )
614 req->handle = wine_server_obj_handle( handle );
615 if (!(ret = wine_server_call( req )))
617 out->CurrentCount = 1 - reply->count;
618 out->OwnedByCaller = reply->owned;
619 out->AbandonedState = reply->abandoned;
620 if (ret_len) *ret_len = sizeof(MUTANT_BASIC_INFORMATION);
623 SERVER_END_REQ;
624 return ret;
628 /**************************************************************************
629 * NtCreateJobObject (NTDLL.@)
631 NTSTATUS WINAPI NtCreateJobObject( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
633 NTSTATUS ret;
634 data_size_t len;
635 struct object_attributes *objattr;
637 *handle = 0;
638 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
640 SERVER_START_REQ( create_job )
642 req->access = access;
643 wine_server_add_data( req, objattr, len );
644 ret = wine_server_call( req );
645 *handle = wine_server_ptr_handle( reply->handle );
647 SERVER_END_REQ;
648 free( objattr );
649 return ret;
653 /**************************************************************************
654 * NtOpenJobObject (NTDLL.@)
656 NTSTATUS WINAPI NtOpenJobObject( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
658 NTSTATUS ret;
660 *handle = 0;
661 if ((ret = validate_open_object_attributes( attr ))) return ret;
663 SERVER_START_REQ( open_job )
665 req->access = access;
666 req->attributes = attr->Attributes;
667 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
668 if (attr->ObjectName)
669 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
670 ret = wine_server_call( req );
671 *handle = wine_server_ptr_handle( reply->handle );
673 SERVER_END_REQ;
674 return ret;
678 /**************************************************************************
679 * NtTerminateJobObject (NTDLL.@)
681 NTSTATUS WINAPI NtTerminateJobObject( HANDLE handle, NTSTATUS status )
683 NTSTATUS ret;
685 TRACE( "(%p, %d)\n", handle, status );
687 SERVER_START_REQ( terminate_job )
689 req->handle = wine_server_obj_handle( handle );
690 req->status = status;
691 ret = wine_server_call( req );
693 SERVER_END_REQ;
695 return ret;
699 /**************************************************************************
700 * NtQueryInformationJobObject (NTDLL.@)
702 NTSTATUS WINAPI NtQueryInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, void *info,
703 ULONG len, ULONG *ret_len )
705 NTSTATUS ret;
707 TRACE( "semi-stub: %p %u %p %u %p\n", handle, class, info, len, ret_len );
709 if (class >= MaxJobObjectInfoClass) return STATUS_INVALID_PARAMETER;
711 switch (class)
713 case JobObjectBasicAccountingInformation:
715 JOBOBJECT_BASIC_ACCOUNTING_INFORMATION *accounting = info;
717 if (len < sizeof(*accounting)) return STATUS_INFO_LENGTH_MISMATCH;
718 SERVER_START_REQ(get_job_info)
720 req->handle = wine_server_obj_handle( handle );
721 if (!(ret = wine_server_call( req )))
723 memset( accounting, 0, sizeof(*accounting) );
724 accounting->TotalProcesses = reply->total_processes;
725 accounting->ActiveProcesses = reply->active_processes;
728 SERVER_END_REQ;
729 if (ret_len) *ret_len = sizeof(*accounting);
730 return ret;
732 case JobObjectBasicProcessIdList:
734 JOBOBJECT_BASIC_PROCESS_ID_LIST *process = info;
735 DWORD count, i;
737 if (len < sizeof(*process)) return STATUS_INFO_LENGTH_MISMATCH;
739 count = len - offsetof( JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList );
740 count /= sizeof(process->ProcessIdList[0]);
742 SERVER_START_REQ( get_job_info )
744 req->handle = wine_server_user_handle(handle);
745 wine_server_set_reply(req, process->ProcessIdList, count * sizeof(process_id_t));
746 if (!(ret = wine_server_call(req)))
748 process->NumberOfAssignedProcesses = reply->active_processes;
749 process->NumberOfProcessIdsInList = min(count, reply->active_processes);
752 SERVER_END_REQ;
754 if (ret != STATUS_SUCCESS) return ret;
756 if (sizeof(process_id_t) < sizeof(process->ProcessIdList[0]))
758 /* start from the end to not overwrite */
759 for (i = process->NumberOfProcessIdsInList; i--;)
761 ULONG_PTR id = ((process_id_t *)process->ProcessIdList)[i];
762 process->ProcessIdList[i] = id;
766 if (ret_len)
767 *ret_len = offsetof( JOBOBJECT_BASIC_PROCESS_ID_LIST, ProcessIdList[process->NumberOfProcessIdsInList] );
768 return count < process->NumberOfAssignedProcesses ? STATUS_MORE_ENTRIES : STATUS_SUCCESS;
770 case JobObjectExtendedLimitInformation:
772 JOBOBJECT_EXTENDED_LIMIT_INFORMATION *extended_limit = info;
774 if (len < sizeof(*extended_limit)) return STATUS_INFO_LENGTH_MISMATCH;
775 memset( extended_limit, 0, sizeof(*extended_limit) );
776 if (ret_len) *ret_len = sizeof(*extended_limit);
777 return STATUS_SUCCESS;
779 case JobObjectBasicLimitInformation:
781 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit = info;
783 if (len < sizeof(*basic_limit)) return STATUS_INFO_LENGTH_MISMATCH;
784 memset( basic_limit, 0, sizeof(*basic_limit) );
785 if (ret_len) *ret_len = sizeof(*basic_limit);
786 return STATUS_SUCCESS;
788 default:
789 return STATUS_NOT_IMPLEMENTED;
794 /**************************************************************************
795 * NtSetInformationJobObject (NTDLL.@)
797 NTSTATUS WINAPI NtSetInformationJobObject( HANDLE handle, JOBOBJECTINFOCLASS class, void *info, ULONG len )
799 NTSTATUS status = STATUS_NOT_IMPLEMENTED;
800 JOBOBJECT_BASIC_LIMIT_INFORMATION *basic_limit;
801 ULONG info_size = sizeof(JOBOBJECT_BASIC_LIMIT_INFORMATION);
802 DWORD limit_flags = JOB_OBJECT_BASIC_LIMIT_VALID_FLAGS;
804 TRACE( "(%p, %u, %p, %u)\n", handle, class, info, len );
806 if (class >= MaxJobObjectInfoClass) return STATUS_INVALID_PARAMETER;
808 switch (class)
811 case JobObjectExtendedLimitInformation:
812 info_size = sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION);
813 limit_flags = JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS;
814 /* fall through */
815 case JobObjectBasicLimitInformation:
816 if (len != info_size) return STATUS_INVALID_PARAMETER;
817 basic_limit = info;
818 if (basic_limit->LimitFlags & ~limit_flags) return STATUS_INVALID_PARAMETER;
819 SERVER_START_REQ( set_job_limits )
821 req->handle = wine_server_obj_handle( handle );
822 req->limit_flags = basic_limit->LimitFlags;
823 status = wine_server_call( req );
825 SERVER_END_REQ;
826 break;
827 case JobObjectAssociateCompletionPortInformation:
828 if (len != sizeof(JOBOBJECT_ASSOCIATE_COMPLETION_PORT)) return STATUS_INVALID_PARAMETER;
829 SERVER_START_REQ( set_job_completion_port )
831 JOBOBJECT_ASSOCIATE_COMPLETION_PORT *port_info = info;
832 req->job = wine_server_obj_handle( handle );
833 req->port = wine_server_obj_handle( port_info->CompletionPort );
834 req->key = wine_server_client_ptr( port_info->CompletionKey );
835 status = wine_server_call( req );
837 SERVER_END_REQ;
838 break;
839 case JobObjectBasicUIRestrictions:
840 status = STATUS_SUCCESS;
841 /* fall through */
842 default:
843 FIXME( "stub: %p %u %p %u\n", handle, class, info, len );
845 return status;
849 /**************************************************************************
850 * NtIsProcessInJob (NTDLL.@)
852 NTSTATUS WINAPI NtIsProcessInJob( HANDLE process, HANDLE job )
854 NTSTATUS status;
856 TRACE( "(%p %p)\n", job, process );
858 SERVER_START_REQ( process_in_job )
860 req->job = wine_server_obj_handle( job );
861 req->process = wine_server_obj_handle( process );
862 status = wine_server_call( req );
864 SERVER_END_REQ;
865 return status;
869 /**************************************************************************
870 * NtAssignProcessToJobObject (NTDLL.@)
872 NTSTATUS WINAPI NtAssignProcessToJobObject( HANDLE job, HANDLE process )
874 NTSTATUS status;
876 TRACE( "(%p %p)\n", job, process );
878 SERVER_START_REQ( assign_job )
880 req->job = wine_server_obj_handle( job );
881 req->process = wine_server_obj_handle( process );
882 status = wine_server_call( req );
884 SERVER_END_REQ;
885 return status;
889 /**********************************************************************
890 * NtCreateDebugObject (NTDLL.@)
892 NTSTATUS WINAPI NtCreateDebugObject( HANDLE *handle, ACCESS_MASK access,
893 OBJECT_ATTRIBUTES *attr, ULONG flags )
895 NTSTATUS ret;
896 data_size_t len;
897 struct object_attributes *objattr;
899 *handle = 0;
900 if (flags & ~DEBUG_KILL_ON_CLOSE) return STATUS_INVALID_PARAMETER;
901 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
903 SERVER_START_REQ( create_debug_obj )
905 req->access = access;
906 req->flags = flags;
907 wine_server_add_data( req, objattr, len );
908 ret = wine_server_call( req );
909 *handle = wine_server_ptr_handle( reply->handle );
911 SERVER_END_REQ;
912 free( objattr );
913 return ret;
917 /**********************************************************************
918 * NtSetInformationDebugObject (NTDLL.@)
920 NTSTATUS WINAPI NtSetInformationDebugObject( HANDLE handle, DEBUGOBJECTINFOCLASS class,
921 void *info, ULONG len, ULONG *ret_len )
923 NTSTATUS ret;
924 ULONG flags;
926 if (class != DebugObjectKillProcessOnExitInformation) return STATUS_INVALID_PARAMETER;
927 if (len != sizeof(ULONG))
929 if (ret_len) *ret_len = sizeof(ULONG);
930 return STATUS_INFO_LENGTH_MISMATCH;
932 flags = *(ULONG *)info;
933 if (flags & ~DEBUG_KILL_ON_CLOSE) return STATUS_INVALID_PARAMETER;
935 SERVER_START_REQ( set_debug_obj_info )
937 req->debug = wine_server_obj_handle( handle );
938 req->flags = flags;
939 ret = wine_server_call( req );
941 SERVER_END_REQ;
942 if (!ret && ret_len) *ret_len = 0;
943 return ret;
947 /* convert the server event data to an NT state change; helper for NtWaitForDebugEvent */
948 static NTSTATUS event_data_to_state_change( const debug_event_t *data, DBGUI_WAIT_STATE_CHANGE *state )
950 int i;
952 switch (data->code)
954 case DbgIdle:
955 case DbgReplyPending:
956 return STATUS_PENDING;
957 case DbgCreateThreadStateChange:
959 DBGUI_CREATE_THREAD *info = &state->StateInfo.CreateThread;
960 info->HandleToThread = wine_server_ptr_handle( data->create_thread.handle );
961 info->NewThread.StartAddress = wine_server_get_ptr( data->create_thread.start );
962 return STATUS_SUCCESS;
964 case DbgCreateProcessStateChange:
966 DBGUI_CREATE_PROCESS *info = &state->StateInfo.CreateProcessInfo;
967 info->HandleToProcess = wine_server_ptr_handle( data->create_process.process );
968 info->HandleToThread = wine_server_ptr_handle( data->create_process.thread );
969 info->NewProcess.FileHandle = wine_server_ptr_handle( data->create_process.file );
970 info->NewProcess.BaseOfImage = wine_server_get_ptr( data->create_process.base );
971 info->NewProcess.DebugInfoFileOffset = data->create_process.dbg_offset;
972 info->NewProcess.DebugInfoSize = data->create_process.dbg_size;
973 info->NewProcess.InitialThread.StartAddress = wine_server_get_ptr( data->create_process.start );
974 return STATUS_SUCCESS;
976 case DbgExitThreadStateChange:
977 state->StateInfo.ExitThread.ExitStatus = data->exit.exit_code;
978 return STATUS_SUCCESS;
979 case DbgExitProcessStateChange:
980 state->StateInfo.ExitProcess.ExitStatus = data->exit.exit_code;
981 return STATUS_SUCCESS;
982 case DbgExceptionStateChange:
983 case DbgBreakpointStateChange:
984 case DbgSingleStepStateChange:
986 DBGKM_EXCEPTION *info = &state->StateInfo.Exception;
987 info->FirstChance = data->exception.first;
988 info->ExceptionRecord.ExceptionCode = data->exception.exc_code;
989 info->ExceptionRecord.ExceptionFlags = data->exception.flags;
990 info->ExceptionRecord.ExceptionRecord = wine_server_get_ptr( data->exception.record );
991 info->ExceptionRecord.ExceptionAddress = wine_server_get_ptr( data->exception.address );
992 info->ExceptionRecord.NumberParameters = data->exception.nb_params;
993 for (i = 0; i < data->exception.nb_params; i++)
994 info->ExceptionRecord.ExceptionInformation[i] = data->exception.params[i];
995 return STATUS_SUCCESS;
997 case DbgLoadDllStateChange:
999 DBGKM_LOAD_DLL *info = &state->StateInfo.LoadDll;
1000 info->FileHandle = wine_server_ptr_handle( data->load_dll.handle );
1001 info->BaseOfDll = wine_server_get_ptr( data->load_dll.base );
1002 info->DebugInfoFileOffset = data->load_dll.dbg_offset;
1003 info->DebugInfoSize = data->load_dll.dbg_size;
1004 info->NamePointer = wine_server_get_ptr( data->load_dll.name );
1005 return STATUS_SUCCESS;
1007 case DbgUnloadDllStateChange:
1008 state->StateInfo.UnloadDll.BaseAddress = wine_server_get_ptr( data->unload_dll.base );
1009 return STATUS_SUCCESS;
1011 return STATUS_INTERNAL_ERROR;
1014 /**********************************************************************
1015 * NtWaitForDebugEvent (NTDLL.@)
1017 NTSTATUS WINAPI NtWaitForDebugEvent( HANDLE handle, BOOLEAN alertable, LARGE_INTEGER *timeout,
1018 DBGUI_WAIT_STATE_CHANGE *state )
1020 debug_event_t data;
1021 NTSTATUS ret;
1022 BOOL wait = TRUE;
1024 for (;;)
1026 SERVER_START_REQ( wait_debug_event )
1028 req->debug = wine_server_obj_handle( handle );
1029 wine_server_set_reply( req, &data, sizeof(data) );
1030 ret = wine_server_call( req );
1031 if (!ret && !(ret = event_data_to_state_change( &data, state )))
1033 state->NewState = data.code;
1034 state->AppClientId.UniqueProcess = ULongToHandle( reply->pid );
1035 state->AppClientId.UniqueThread = ULongToHandle( reply->tid );
1038 SERVER_END_REQ;
1040 if (ret != STATUS_PENDING) return ret;
1041 if (!wait) return STATUS_TIMEOUT;
1042 wait = FALSE;
1043 ret = NtWaitForSingleObject( handle, alertable, timeout );
1044 if (ret != STATUS_WAIT_0) return ret;
1049 /**************************************************************************
1050 * NtCreateDirectoryObject (NTDLL.@)
1052 NTSTATUS WINAPI NtCreateDirectoryObject( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr )
1054 NTSTATUS ret;
1055 data_size_t len;
1056 struct object_attributes *objattr;
1058 *handle = 0;
1059 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1061 SERVER_START_REQ( create_directory )
1063 req->access = access;
1064 wine_server_add_data( req, objattr, len );
1065 ret = wine_server_call( req );
1066 *handle = wine_server_ptr_handle( reply->handle );
1068 SERVER_END_REQ;
1069 free( objattr );
1070 return ret;
1074 /**************************************************************************
1075 * NtOpenDirectoryObject (NTDLL.@)
1077 NTSTATUS WINAPI NtOpenDirectoryObject( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1079 NTSTATUS ret;
1081 *handle = 0;
1082 if ((ret = validate_open_object_attributes( attr ))) return ret;
1084 SERVER_START_REQ( open_directory )
1086 req->access = access;
1087 req->attributes = attr->Attributes;
1088 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1089 if (attr->ObjectName)
1090 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1091 ret = wine_server_call( req );
1092 *handle = wine_server_ptr_handle( reply->handle );
1094 SERVER_END_REQ;
1095 return ret;
1099 /**************************************************************************
1100 * NtQueryDirectoryObject (NTDLL.@)
1102 NTSTATUS WINAPI NtQueryDirectoryObject( HANDLE handle, DIRECTORY_BASIC_INFORMATION *buffer,
1103 ULONG size, BOOLEAN single_entry, BOOLEAN restart,
1104 ULONG *context, ULONG *ret_size )
1106 NTSTATUS ret;
1108 if (restart) *context = 0;
1110 if (single_entry)
1112 if (size <= sizeof(*buffer) + 2 * sizeof(WCHAR)) return STATUS_BUFFER_OVERFLOW;
1114 SERVER_START_REQ( get_directory_entry )
1116 req->handle = wine_server_obj_handle( handle );
1117 req->index = *context;
1118 wine_server_set_reply( req, buffer + 1, size - sizeof(*buffer) - 2*sizeof(WCHAR) );
1119 if (!(ret = wine_server_call( req )))
1121 buffer->ObjectName.Buffer = (WCHAR *)(buffer + 1);
1122 buffer->ObjectName.Length = reply->name_len;
1123 buffer->ObjectName.MaximumLength = reply->name_len + sizeof(WCHAR);
1124 buffer->ObjectTypeName.Buffer = (WCHAR *)(buffer + 1) + reply->name_len/sizeof(WCHAR) + 1;
1125 buffer->ObjectTypeName.Length = wine_server_reply_size( reply ) - reply->name_len;
1126 buffer->ObjectTypeName.MaximumLength = buffer->ObjectTypeName.Length + sizeof(WCHAR);
1127 /* make room for the terminating null */
1128 memmove( buffer->ObjectTypeName.Buffer, buffer->ObjectTypeName.Buffer - 1,
1129 buffer->ObjectTypeName.Length );
1130 buffer->ObjectName.Buffer[buffer->ObjectName.Length/sizeof(WCHAR)] = 0;
1131 buffer->ObjectTypeName.Buffer[buffer->ObjectTypeName.Length/sizeof(WCHAR)] = 0;
1132 (*context)++;
1135 SERVER_END_REQ;
1136 if (ret_size)
1137 *ret_size = buffer->ObjectName.MaximumLength + buffer->ObjectTypeName.MaximumLength + sizeof(*buffer);
1139 else
1141 FIXME("multiple entries not implemented\n");
1142 ret = STATUS_NOT_IMPLEMENTED;
1144 return ret;
1148 /**************************************************************************
1149 * NtCreateSymbolicLinkObject (NTDLL.@)
1151 NTSTATUS WINAPI NtCreateSymbolicLinkObject( HANDLE *handle, ACCESS_MASK access,
1152 OBJECT_ATTRIBUTES *attr, UNICODE_STRING *target )
1154 NTSTATUS ret;
1155 data_size_t len;
1156 struct object_attributes *objattr;
1158 *handle = 0;
1159 if (!target->MaximumLength) return STATUS_INVALID_PARAMETER;
1160 if (!target->Buffer) return STATUS_ACCESS_VIOLATION;
1161 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1163 SERVER_START_REQ( create_symlink )
1165 req->access = access;
1166 wine_server_add_data( req, objattr, len );
1167 wine_server_add_data( req, target->Buffer, target->Length );
1168 ret = wine_server_call( req );
1169 *handle = wine_server_ptr_handle( reply->handle );
1171 SERVER_END_REQ;
1172 free( objattr );
1173 return ret;
1177 /**************************************************************************
1178 * NtOpenSymbolicLinkObject (NTDLL.@)
1180 NTSTATUS WINAPI NtOpenSymbolicLinkObject( HANDLE *handle, ACCESS_MASK access,
1181 const OBJECT_ATTRIBUTES *attr )
1183 NTSTATUS ret;
1185 *handle = 0;
1186 if ((ret = validate_open_object_attributes( attr ))) return ret;
1188 SERVER_START_REQ( open_symlink )
1190 req->access = access;
1191 req->attributes = attr->Attributes;
1192 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1193 if (attr->ObjectName)
1194 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1195 ret = wine_server_call( req );
1196 *handle = wine_server_ptr_handle( reply->handle );
1198 SERVER_END_REQ;
1199 return ret;
1203 /**************************************************************************
1204 * NtQuerySymbolicLinkObject (NTDLL.@)
1206 NTSTATUS WINAPI NtQuerySymbolicLinkObject( HANDLE handle, UNICODE_STRING *target, ULONG *length )
1208 NTSTATUS ret;
1210 if (!target) return STATUS_ACCESS_VIOLATION;
1212 SERVER_START_REQ( query_symlink )
1214 req->handle = wine_server_obj_handle( handle );
1215 if (target->MaximumLength >= sizeof(WCHAR))
1216 wine_server_set_reply( req, target->Buffer, target->MaximumLength - sizeof(WCHAR) );
1217 if (!(ret = wine_server_call( req )))
1219 target->Length = wine_server_reply_size(reply);
1220 target->Buffer[target->Length / sizeof(WCHAR)] = 0;
1221 if (length) *length = reply->total + sizeof(WCHAR);
1223 else if (length && ret == STATUS_BUFFER_TOO_SMALL) *length = reply->total + sizeof(WCHAR);
1225 SERVER_END_REQ;
1226 return ret;
1230 /**************************************************************************
1231 * NtMakeTemporaryObject (NTDLL.@)
1233 NTSTATUS WINAPI NtMakeTemporaryObject( HANDLE handle )
1235 NTSTATUS ret;
1237 TRACE("%p\n", handle);
1239 SERVER_START_REQ( make_temporary )
1241 req->handle = wine_server_obj_handle( handle );
1242 ret = wine_server_call( req );
1244 SERVER_END_REQ;
1245 return ret;
1249 /**************************************************************************
1250 * NtCreateTimer (NTDLL.@)
1252 NTSTATUS WINAPI NtCreateTimer( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
1253 TIMER_TYPE type )
1255 NTSTATUS ret;
1256 data_size_t len;
1257 struct object_attributes *objattr;
1259 *handle = 0;
1260 if (type != NotificationTimer && type != SynchronizationTimer) return STATUS_INVALID_PARAMETER;
1261 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1263 SERVER_START_REQ( create_timer )
1265 req->access = access;
1266 req->manual = (type == NotificationTimer);
1267 wine_server_add_data( req, objattr, len );
1268 ret = wine_server_call( req );
1269 *handle = wine_server_ptr_handle( reply->handle );
1271 SERVER_END_REQ;
1273 free( objattr );
1274 return ret;
1279 /**************************************************************************
1280 * NtOpenTimer (NTDLL.@)
1282 NTSTATUS WINAPI NtOpenTimer( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1284 NTSTATUS ret;
1286 *handle = 0;
1287 if ((ret = validate_open_object_attributes( attr ))) return ret;
1289 SERVER_START_REQ( open_timer )
1291 req->access = access;
1292 req->attributes = attr->Attributes;
1293 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1294 if (attr->ObjectName)
1295 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1296 ret = wine_server_call( req );
1297 *handle = wine_server_ptr_handle( reply->handle );
1299 SERVER_END_REQ;
1300 return ret;
1304 /**************************************************************************
1305 * NtSetTimer (NTDLL.@)
1307 NTSTATUS WINAPI NtSetTimer( HANDLE handle, const LARGE_INTEGER *when, PTIMER_APC_ROUTINE callback,
1308 void *arg, BOOLEAN resume, ULONG period, BOOLEAN *state )
1310 NTSTATUS ret = STATUS_SUCCESS;
1312 TRACE( "(%p,%p,%p,%p,%08x,0x%08x,%p)\n", handle, when, callback, arg, resume, period, state );
1314 SERVER_START_REQ( set_timer )
1316 req->handle = wine_server_obj_handle( handle );
1317 req->period = period;
1318 req->expire = when->QuadPart;
1319 req->callback = wine_server_client_ptr( callback );
1320 req->arg = wine_server_client_ptr( arg );
1321 ret = wine_server_call( req );
1322 if (state) *state = reply->signaled;
1324 SERVER_END_REQ;
1326 /* set error but can still succeed */
1327 if (resume && ret == STATUS_SUCCESS) return STATUS_TIMER_RESUME_IGNORED;
1328 return ret;
1332 /**************************************************************************
1333 * NtCancelTimer (NTDLL.@)
1335 NTSTATUS WINAPI NtCancelTimer( HANDLE handle, BOOLEAN *state )
1337 NTSTATUS ret;
1339 SERVER_START_REQ( cancel_timer )
1341 req->handle = wine_server_obj_handle( handle );
1342 ret = wine_server_call( req );
1343 if (state) *state = reply->signaled;
1345 SERVER_END_REQ;
1346 return ret;
1350 /******************************************************************************
1351 * NtQueryTimer (NTDLL.@)
1353 NTSTATUS WINAPI NtQueryTimer( HANDLE handle, TIMER_INFORMATION_CLASS class,
1354 void *info, ULONG len, ULONG *ret_len )
1356 TIMER_BASIC_INFORMATION *basic_info = info;
1357 NTSTATUS ret;
1358 LARGE_INTEGER now;
1360 TRACE( "(%p,%d,%p,0x%08x,%p)\n", handle, class, info, len, ret_len );
1362 switch (class)
1364 case TimerBasicInformation:
1365 if (len < sizeof(TIMER_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
1367 SERVER_START_REQ( get_timer_info )
1369 req->handle = wine_server_obj_handle( handle );
1370 ret = wine_server_call(req);
1371 /* convert server time to absolute NTDLL time */
1372 basic_info->RemainingTime.QuadPart = reply->when;
1373 basic_info->TimerState = reply->signaled;
1375 SERVER_END_REQ;
1377 /* convert into relative time */
1378 if (basic_info->RemainingTime.QuadPart > 0) NtQuerySystemTime( &now );
1379 else
1381 NtQueryPerformanceCounter( &now, NULL );
1382 basic_info->RemainingTime.QuadPart = -basic_info->RemainingTime.QuadPart;
1385 if (now.QuadPart > basic_info->RemainingTime.QuadPart)
1386 basic_info->RemainingTime.QuadPart = 0;
1387 else
1388 basic_info->RemainingTime.QuadPart -= now.QuadPart;
1390 if (ret_len) *ret_len = sizeof(TIMER_BASIC_INFORMATION);
1391 return ret;
1394 FIXME( "Unhandled class %d\n", class );
1395 return STATUS_INVALID_INFO_CLASS;
1399 /******************************************************************
1400 * NtWaitForMultipleObjects (NTDLL.@)
1402 NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
1403 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1405 select_op_t select_op;
1406 UINT i, flags = SELECT_INTERRUPTIBLE;
1408 if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
1410 if (alertable) flags |= SELECT_ALERTABLE;
1411 select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL;
1412 for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] );
1413 return server_wait( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout );
1417 /******************************************************************
1418 * NtWaitForSingleObject (NTDLL.@)
1420 NTSTATUS WINAPI NtWaitForSingleObject( HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout )
1422 return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout );
1426 /******************************************************************
1427 * NtSignalAndWaitForSingleObject (NTDLL.@)
1429 NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait,
1430 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1432 select_op_t select_op;
1433 UINT flags = SELECT_INTERRUPTIBLE;
1435 if (!signal) return STATUS_INVALID_HANDLE;
1437 if (alertable) flags |= SELECT_ALERTABLE;
1438 select_op.signal_and_wait.op = SELECT_SIGNAL_AND_WAIT;
1439 select_op.signal_and_wait.wait = wine_server_obj_handle( wait );
1440 select_op.signal_and_wait.signal = wine_server_obj_handle( signal );
1441 return server_wait( &select_op, sizeof(select_op.signal_and_wait), flags, timeout );
1445 /******************************************************************
1446 * NtYieldExecution (NTDLL.@)
1448 NTSTATUS WINAPI NtYieldExecution(void)
1450 usleep(0);
1451 return STATUS_SUCCESS;
1455 /******************************************************************
1456 * NtDelayExecution (NTDLL.@)
1458 NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
1460 /* if alertable, we need to query the server */
1461 if (alertable) return server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout );
1463 if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */
1465 for (;;) select( 0, NULL, NULL, NULL, NULL );
1467 else
1469 LARGE_INTEGER now;
1470 timeout_t when, diff;
1472 if ((when = timeout->QuadPart) < 0)
1474 NtQuerySystemTime( &now );
1475 when = now.QuadPart - when;
1478 /* Note that we yield after establishing the desired timeout */
1479 NtYieldExecution();
1480 if (!when) return STATUS_SUCCESS;
1482 for (;;)
1484 struct timeval tv;
1485 NtQuerySystemTime( &now );
1486 diff = (when - now.QuadPart + 9) / 10;
1487 if (diff <= 0) break;
1488 tv.tv_sec = diff / 1000000;
1489 tv.tv_usec = diff % 1000000;
1490 if (select( 0, NULL, NULL, NULL, &tv ) != -1) break;
1493 return STATUS_SUCCESS;
1497 /******************************************************************************
1498 * NtQueryPerformanceCounter (NTDLL.@)
1500 NTSTATUS WINAPI NtQueryPerformanceCounter( LARGE_INTEGER *counter, LARGE_INTEGER *frequency )
1502 counter->QuadPart = monotonic_counter();
1503 if (frequency) frequency->QuadPart = TICKSPERSEC;
1504 return STATUS_SUCCESS;
1508 /***********************************************************************
1509 * NtQuerySystemTime (NTDLL.@)
1511 NTSTATUS WINAPI NtQuerySystemTime( LARGE_INTEGER *time )
1513 #ifdef HAVE_CLOCK_GETTIME
1514 struct timespec ts;
1515 static clockid_t clock_id = CLOCK_MONOTONIC; /* placeholder */
1517 if (clock_id == CLOCK_MONOTONIC)
1519 #ifdef CLOCK_REALTIME_COARSE
1520 struct timespec res;
1522 /* Use CLOCK_REALTIME_COARSE if it has 1 ms or better resolution */
1523 if (!clock_getres( CLOCK_REALTIME_COARSE, &res ) && res.tv_sec == 0 && res.tv_nsec <= 1000000)
1524 clock_id = CLOCK_REALTIME_COARSE;
1525 else
1526 #endif /* CLOCK_REALTIME_COARSE */
1527 clock_id = CLOCK_REALTIME;
1530 if (!clock_gettime( clock_id, &ts ))
1532 time->QuadPart = ticks_from_time_t( ts.tv_sec ) + (ts.tv_nsec + 50) / 100;
1534 else
1535 #endif /* HAVE_CLOCK_GETTIME */
1537 struct timeval now;
1539 gettimeofday( &now, 0 );
1540 time->QuadPart = ticks_from_time_t( now.tv_sec ) + now.tv_usec * 10;
1542 return STATUS_SUCCESS;
1546 /***********************************************************************
1547 * NtSetSystemTime (NTDLL.@)
1549 NTSTATUS WINAPI NtSetSystemTime( const LARGE_INTEGER *new, LARGE_INTEGER *old )
1551 LARGE_INTEGER now;
1552 LONGLONG diff;
1554 NtQuerySystemTime( &now );
1555 if (old) *old = now;
1556 diff = new->QuadPart - now.QuadPart;
1557 if (diff > -TICKSPERSEC / 2 && diff < TICKSPERSEC / 2) return STATUS_SUCCESS;
1558 ERR( "not allowed: difference %d ms\n", (int)(diff / 10000) );
1559 return STATUS_PRIVILEGE_NOT_HELD;
1563 /***********************************************************************
1564 * NtQueryTimerResolution (NTDLL.@)
1566 NTSTATUS WINAPI NtQueryTimerResolution( ULONG *min_res, ULONG *max_res, ULONG *current_res )
1568 TRACE( "(%p,%p,%p)\n", min_res, max_res, current_res );
1569 *max_res = *current_res = 10000; /* See NtSetTimerResolution() */
1570 *min_res = 156250;
1571 return STATUS_SUCCESS;
1575 /***********************************************************************
1576 * NtSetTimerResolution (NTDLL.@)
1578 NTSTATUS WINAPI NtSetTimerResolution( ULONG res, BOOLEAN set, ULONG *current_res )
1580 static BOOL has_request = FALSE;
1582 TRACE( "(%u,%u,%p), semi-stub!\n", res, set, current_res );
1584 /* Wine has no support for anything other that 1 ms and does not keep of
1585 * track resolution requests anyway.
1586 * Fortunately NtSetTimerResolution() should ignore requests to lower the
1587 * timer resolution. So by claiming that 'some other process' requested the
1588 * max resolution already, there no need to actually change it.
1590 *current_res = 10000;
1592 /* Just keep track of whether this process requested a specific timer
1593 * resolution.
1595 if (!has_request && !set)
1596 return STATUS_TIMER_RESOLUTION_NOT_SET;
1597 has_request = set;
1599 return STATUS_SUCCESS;
1603 /******************************************************************************
1604 * NtSetIntervalProfile (NTDLL.@)
1606 NTSTATUS WINAPI NtSetIntervalProfile( ULONG interval, KPROFILE_SOURCE source )
1608 FIXME( "%u,%d\n", interval, source );
1609 return STATUS_SUCCESS;
1613 /******************************************************************************
1614 * NtGetTickCount (NTDLL.@)
1616 ULONG WINAPI NtGetTickCount(void)
1618 /* note: we ignore TickCountMultiplier */
1619 return user_shared_data->u.TickCount.LowPart;
1623 /******************************************************************************
1624 * RtlGetSystemTimePrecise (NTDLL.@)
1626 LONGLONG WINAPI RtlGetSystemTimePrecise(void)
1628 struct timeval now;
1629 #ifdef HAVE_CLOCK_GETTIME
1630 struct timespec ts;
1632 if (!clock_gettime( CLOCK_REALTIME, &ts ))
1633 return ticks_from_time_t( ts.tv_sec ) + (ts.tv_nsec + 50) / 100;
1634 #endif
1635 gettimeofday( &now, 0 );
1636 return ticks_from_time_t( now.tv_sec ) + now.tv_usec * 10;
1640 /******************************************************************************
1641 * NtCreateKeyedEvent (NTDLL.@)
1643 NTSTATUS WINAPI NtCreateKeyedEvent( HANDLE *handle, ACCESS_MASK access,
1644 const OBJECT_ATTRIBUTES *attr, ULONG flags )
1646 NTSTATUS ret;
1647 data_size_t len;
1648 struct object_attributes *objattr;
1650 *handle = 0;
1651 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1653 SERVER_START_REQ( create_keyed_event )
1655 req->access = access;
1656 wine_server_add_data( req, objattr, len );
1657 ret = wine_server_call( req );
1658 *handle = wine_server_ptr_handle( reply->handle );
1660 SERVER_END_REQ;
1662 free( objattr );
1663 return ret;
1667 /******************************************************************************
1668 * NtOpenKeyedEvent (NTDLL.@)
1670 NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1672 NTSTATUS ret;
1674 *handle = 0;
1675 if ((ret = validate_open_object_attributes( attr ))) return ret;
1677 SERVER_START_REQ( open_keyed_event )
1679 req->access = access;
1680 req->attributes = attr->Attributes;
1681 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1682 if (attr->ObjectName)
1683 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1684 ret = wine_server_call( req );
1685 *handle = wine_server_ptr_handle( reply->handle );
1687 SERVER_END_REQ;
1688 return ret;
1691 /******************************************************************************
1692 * NtWaitForKeyedEvent (NTDLL.@)
1694 NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key,
1695 BOOLEAN alertable, const LARGE_INTEGER *timeout )
1697 select_op_t select_op;
1698 UINT flags = SELECT_INTERRUPTIBLE;
1700 if (!handle) handle = keyed_event;
1701 if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1;
1702 if (alertable) flags |= SELECT_ALERTABLE;
1703 select_op.keyed_event.op = SELECT_KEYED_EVENT_WAIT;
1704 select_op.keyed_event.handle = wine_server_obj_handle( handle );
1705 select_op.keyed_event.key = wine_server_client_ptr( key );
1706 return server_wait( &select_op, sizeof(select_op.keyed_event), flags, timeout );
1710 /******************************************************************************
1711 * NtReleaseKeyedEvent (NTDLL.@)
1713 NTSTATUS WINAPI NtReleaseKeyedEvent( 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_RELEASE;
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 * NtCreateIoCompletion (NTDLL.@)
1732 NTSTATUS WINAPI NtCreateIoCompletion( HANDLE *handle, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
1733 ULONG threads )
1735 NTSTATUS status;
1736 data_size_t len;
1737 struct object_attributes *objattr;
1739 TRACE( "(%p, %x, %p, %d)\n", handle, access, attr, threads );
1741 *handle = 0;
1742 if ((status = alloc_object_attributes( attr, &objattr, &len ))) return status;
1744 SERVER_START_REQ( create_completion )
1746 req->access = access;
1747 req->concurrent = threads;
1748 wine_server_add_data( req, objattr, len );
1749 if (!(status = wine_server_call( req ))) *handle = wine_server_ptr_handle( reply->handle );
1751 SERVER_END_REQ;
1753 free( objattr );
1754 return status;
1758 /***********************************************************************
1759 * NtOpenIoCompletion (NTDLL.@)
1761 NTSTATUS WINAPI NtOpenIoCompletion( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1763 NTSTATUS status;
1765 *handle = 0;
1766 if ((status = validate_open_object_attributes( attr ))) return status;
1768 SERVER_START_REQ( open_completion )
1770 req->access = access;
1771 req->attributes = attr->Attributes;
1772 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1773 if (attr->ObjectName)
1774 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1775 status = wine_server_call( req );
1776 *handle = wine_server_ptr_handle( reply->handle );
1778 SERVER_END_REQ;
1779 return status;
1783 /***********************************************************************
1784 * NtSetIoCompletion (NTDLL.@)
1786 NTSTATUS WINAPI NtSetIoCompletion( HANDLE handle, ULONG_PTR key, ULONG_PTR value,
1787 NTSTATUS status, SIZE_T count )
1789 NTSTATUS ret;
1791 TRACE( "(%p, %lx, %lx, %x, %lx)\n", handle, key, value, status, count );
1793 SERVER_START_REQ( add_completion )
1795 req->handle = wine_server_obj_handle( handle );
1796 req->ckey = key;
1797 req->cvalue = value;
1798 req->status = status;
1799 req->information = count;
1800 ret = wine_server_call( req );
1802 SERVER_END_REQ;
1803 return ret;
1807 /***********************************************************************
1808 * NtRemoveIoCompletion (NTDLL.@)
1810 NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR *value,
1811 IO_STATUS_BLOCK *io, LARGE_INTEGER *timeout )
1813 NTSTATUS status;
1815 TRACE( "(%p, %p, %p, %p, %p)\n", handle, key, value, io, timeout );
1817 for (;;)
1819 SERVER_START_REQ( remove_completion )
1821 req->handle = wine_server_obj_handle( handle );
1822 if (!(status = wine_server_call( req )))
1824 *key = reply->ckey;
1825 *value = reply->cvalue;
1826 io->Information = reply->information;
1827 io->u.Status = reply->status;
1830 SERVER_END_REQ;
1831 if (status != STATUS_PENDING) return status;
1832 status = NtWaitForSingleObject( handle, FALSE, timeout );
1833 if (status != WAIT_OBJECT_0) return status;
1838 /***********************************************************************
1839 * NtRemoveIoCompletionEx (NTDLL.@)
1841 NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORMATION *info, ULONG count,
1842 ULONG *written, LARGE_INTEGER *timeout, BOOLEAN alertable )
1844 NTSTATUS status;
1845 ULONG i = 0;
1847 TRACE( "%p %p %u %p %p %u\n", handle, info, count, written, timeout, alertable );
1849 for (;;)
1851 while (i < count)
1853 SERVER_START_REQ( remove_completion )
1855 req->handle = wine_server_obj_handle( handle );
1856 if (!(status = wine_server_call( req )))
1858 info[i].CompletionKey = reply->ckey;
1859 info[i].CompletionValue = reply->cvalue;
1860 info[i].IoStatusBlock.Information = reply->information;
1861 info[i].IoStatusBlock.u.Status = reply->status;
1864 SERVER_END_REQ;
1865 if (status != STATUS_SUCCESS) break;
1866 ++i;
1868 if (i || status != STATUS_PENDING)
1870 if (status == STATUS_PENDING) status = STATUS_SUCCESS;
1871 break;
1873 status = NtWaitForSingleObject( handle, alertable, timeout );
1874 if (status != WAIT_OBJECT_0) break;
1876 *written = i ? i : 1;
1877 return status;
1881 /***********************************************************************
1882 * NtQueryIoCompletion (NTDLL.@)
1884 NTSTATUS WINAPI NtQueryIoCompletion( HANDLE handle, IO_COMPLETION_INFORMATION_CLASS class,
1885 void *buffer, ULONG len, ULONG *ret_len )
1887 NTSTATUS status;
1889 TRACE( "(%p, %d, %p, 0x%x, %p)\n", handle, class, buffer, len, ret_len );
1891 if (!buffer) return STATUS_INVALID_PARAMETER;
1893 switch (class)
1895 case IoCompletionBasicInformation:
1897 ULONG *info = buffer;
1898 if (ret_len) *ret_len = sizeof(*info);
1899 if (len == sizeof(*info))
1901 SERVER_START_REQ( query_completion )
1903 req->handle = wine_server_obj_handle( handle );
1904 if (!(status = wine_server_call( req ))) *info = reply->depth;
1906 SERVER_END_REQ;
1908 else status = STATUS_INFO_LENGTH_MISMATCH;
1909 break;
1911 default:
1912 return STATUS_INVALID_PARAMETER;
1914 return status;
1918 /***********************************************************************
1919 * NtCreateSection (NTDLL.@)
1921 NTSTATUS WINAPI NtCreateSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr,
1922 const LARGE_INTEGER *size, ULONG protect,
1923 ULONG sec_flags, HANDLE file )
1925 NTSTATUS ret;
1926 unsigned int file_access;
1927 data_size_t len;
1928 struct object_attributes *objattr;
1930 *handle = 0;
1932 switch (protect & 0xff)
1934 case PAGE_READONLY:
1935 case PAGE_EXECUTE_READ:
1936 case PAGE_WRITECOPY:
1937 case PAGE_EXECUTE_WRITECOPY:
1938 file_access = FILE_READ_DATA;
1939 break;
1940 case PAGE_READWRITE:
1941 case PAGE_EXECUTE_READWRITE:
1942 if (sec_flags & SEC_IMAGE) file_access = FILE_READ_DATA;
1943 else file_access = FILE_READ_DATA | FILE_WRITE_DATA;
1944 break;
1945 case PAGE_EXECUTE:
1946 case PAGE_NOACCESS:
1947 file_access = 0;
1948 break;
1949 default:
1950 return STATUS_INVALID_PAGE_PROTECTION;
1953 if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
1955 SERVER_START_REQ( create_mapping )
1957 req->access = access;
1958 req->flags = sec_flags;
1959 req->file_handle = wine_server_obj_handle( file );
1960 req->file_access = file_access;
1961 req->size = size ? size->QuadPart : 0;
1962 wine_server_add_data( req, objattr, len );
1963 ret = wine_server_call( req );
1964 *handle = wine_server_ptr_handle( reply->handle );
1966 SERVER_END_REQ;
1968 free( objattr );
1969 return ret;
1973 /***********************************************************************
1974 * NtOpenSection (NTDLL.@)
1976 NTSTATUS WINAPI NtOpenSection( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
1978 NTSTATUS ret;
1980 *handle = 0;
1981 if ((ret = validate_open_object_attributes( attr ))) return ret;
1983 SERVER_START_REQ( open_mapping )
1985 req->access = access;
1986 req->attributes = attr->Attributes;
1987 req->rootdir = wine_server_obj_handle( attr->RootDirectory );
1988 if (attr->ObjectName)
1989 wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
1990 ret = wine_server_call( req );
1991 *handle = wine_server_ptr_handle( reply->handle );
1993 SERVER_END_REQ;
1994 return ret;
1998 /***********************************************************************
1999 * NtCreatePort (NTDLL.@)
2001 NTSTATUS WINAPI NtCreatePort( HANDLE *handle, OBJECT_ATTRIBUTES *attr, ULONG info_len,
2002 ULONG data_len, ULONG *reserved )
2004 FIXME( "(%p,%p,%u,%u,%p),stub!\n", handle, attr, info_len, data_len, reserved );
2005 return STATUS_NOT_IMPLEMENTED;
2009 /***********************************************************************
2010 * NtConnectPort (NTDLL.@)
2012 NTSTATUS WINAPI NtConnectPort( HANDLE *handle, UNICODE_STRING *name, SECURITY_QUALITY_OF_SERVICE *qos,
2013 LPC_SECTION_WRITE *write, LPC_SECTION_READ *read, ULONG *max_len,
2014 void *info, ULONG *info_len )
2016 FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p),stub!\n", handle, debugstr_us(name), qos,
2017 write, read, max_len, info, info_len );
2018 if (info && info_len) TRACE("msg = %s\n", debugstr_an( info, *info_len ));
2019 return STATUS_NOT_IMPLEMENTED;
2023 /***********************************************************************
2024 * NtSecureConnectPort (NTDLL.@)
2026 NTSTATUS WINAPI NtSecureConnectPort( HANDLE *handle, UNICODE_STRING *name, SECURITY_QUALITY_OF_SERVICE *qos,
2027 LPC_SECTION_WRITE *write, PSID sid, LPC_SECTION_READ *read,
2028 ULONG *max_len, void *info, ULONG *info_len )
2030 FIXME( "(%p,%s,%p,%p,%p,%p,%p,%p,%p),stub!\n", handle, debugstr_us(name), qos,
2031 write, sid, read, max_len, info, info_len );
2032 return STATUS_NOT_IMPLEMENTED;
2036 /***********************************************************************
2037 * NtListenPort (NTDLL.@)
2039 NTSTATUS WINAPI NtListenPort( HANDLE handle, LPC_MESSAGE *msg )
2041 FIXME("(%p,%p),stub!\n", handle, msg );
2042 return STATUS_NOT_IMPLEMENTED;
2046 /***********************************************************************
2047 * NtAcceptConnectPort (NTDLL.@)
2049 NTSTATUS WINAPI NtAcceptConnectPort( HANDLE *handle, ULONG id, LPC_MESSAGE *msg, BOOLEAN accept,
2050 LPC_SECTION_WRITE *write, LPC_SECTION_READ *read )
2052 FIXME("(%p,%u,%p,%d,%p,%p),stub!\n", handle, id, msg, accept, write, read );
2053 return STATUS_NOT_IMPLEMENTED;
2057 /***********************************************************************
2058 * NtCompleteConnectPort (NTDLL.@)
2060 NTSTATUS WINAPI NtCompleteConnectPort( HANDLE handle )
2062 FIXME( "(%p),stub!\n", handle );
2063 return STATUS_NOT_IMPLEMENTED;
2067 /***********************************************************************
2068 * NtRegisterThreadTerminatePort (NTDLL.@)
2070 NTSTATUS WINAPI NtRegisterThreadTerminatePort( HANDLE handle )
2072 FIXME( "(%p),stub!\n", handle );
2073 return STATUS_NOT_IMPLEMENTED;
2077 /***********************************************************************
2078 * NtRequestWaitReplyPort (NTDLL.@)
2080 NTSTATUS WINAPI NtRequestWaitReplyPort( HANDLE handle, LPC_MESSAGE *msg_in, LPC_MESSAGE *msg_out )
2082 FIXME( "(%p,%p,%p),stub!\n", handle, msg_in, msg_out );
2083 if (msg_in)
2084 TRACE("datasize %u msgsize %u type %u ranges %u client %p/%p msgid %lu size %lu data %s\n",
2085 msg_in->DataSize, msg_in->MessageSize, msg_in->MessageType, msg_in->VirtualRangesOffset,
2086 msg_in->ClientId.UniqueProcess, msg_in->ClientId.UniqueThread, msg_in->MessageId,
2087 msg_in->SectionSize, debugstr_an( (const char *)msg_in->Data, msg_in->DataSize ));
2088 return STATUS_NOT_IMPLEMENTED;
2092 /***********************************************************************
2093 * NtReplyWaitReceivePort (NTDLL.@)
2095 NTSTATUS WINAPI NtReplyWaitReceivePort( HANDLE handle, ULONG *id, LPC_MESSAGE *reply, LPC_MESSAGE *msg )
2097 FIXME("(%p,%p,%p,%p),stub!\n", handle, id, reply, msg );
2098 return STATUS_NOT_IMPLEMENTED;
2102 #define MAX_ATOM_LEN 255
2103 #define IS_INTATOM(x) (((ULONG_PTR)(x) >> 16) == 0)
2105 static NTSTATUS is_integral_atom( const WCHAR *atomstr, ULONG len, RTL_ATOM *ret_atom )
2107 RTL_ATOM atom;
2109 if ((ULONG_PTR)atomstr >> 16)
2111 const WCHAR* ptr = atomstr;
2112 if (!len) return STATUS_OBJECT_NAME_INVALID;
2114 if (*ptr++ == '#')
2116 atom = 0;
2117 while (ptr < atomstr + len && *ptr >= '0' && *ptr <= '9')
2119 atom = atom * 10 + *ptr++ - '0';
2121 if (ptr > atomstr + 1 && ptr == atomstr + len) goto done;
2123 if (len > MAX_ATOM_LEN) return STATUS_INVALID_PARAMETER;
2124 return STATUS_MORE_ENTRIES;
2126 else atom = LOWORD( atomstr );
2127 done:
2128 if (!atom || atom >= MAXINTATOM) return STATUS_INVALID_PARAMETER;
2129 *ret_atom = atom;
2130 return STATUS_SUCCESS;
2133 static ULONG integral_atom_name( WCHAR *buffer, ULONG len, RTL_ATOM atom )
2135 char tmp[16];
2136 int ret = sprintf( tmp, "#%u", atom );
2138 len /= sizeof(WCHAR);
2139 if (len)
2141 if (len <= ret) ret = len - 1;
2142 ascii_to_unicode( buffer, tmp, ret );
2143 buffer[ret] = 0;
2145 return ret * sizeof(WCHAR);
2149 /***********************************************************************
2150 * NtAddAtom (NTDLL.@)
2152 NTSTATUS WINAPI NtAddAtom( const WCHAR *name, ULONG length, RTL_ATOM *atom )
2154 NTSTATUS status = is_integral_atom( name, length / sizeof(WCHAR), atom );
2156 if (status == STATUS_MORE_ENTRIES)
2158 SERVER_START_REQ( add_atom )
2160 wine_server_add_data( req, name, length );
2161 status = wine_server_call( req );
2162 *atom = reply->atom;
2164 SERVER_END_REQ;
2166 TRACE( "%s -> %x\n", debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
2167 return status;
2171 /***********************************************************************
2172 * NtDeleteAtom (NTDLL.@)
2174 NTSTATUS WINAPI NtDeleteAtom( RTL_ATOM atom )
2176 NTSTATUS status;
2178 SERVER_START_REQ( delete_atom )
2180 req->atom = atom;
2181 status = wine_server_call( req );
2183 SERVER_END_REQ;
2184 return status;
2188 /***********************************************************************
2189 * NtFindAtom (NTDLL.@)
2191 NTSTATUS WINAPI NtFindAtom( const WCHAR *name, ULONG length, RTL_ATOM *atom )
2193 NTSTATUS status = is_integral_atom( name, length / sizeof(WCHAR), atom );
2195 if (status == STATUS_MORE_ENTRIES)
2197 SERVER_START_REQ( find_atom )
2199 wine_server_add_data( req, name, length );
2200 status = wine_server_call( req );
2201 *atom = reply->atom;
2203 SERVER_END_REQ;
2205 TRACE( "%s -> %x\n", debugstr_wn(name, length/sizeof(WCHAR)), status == STATUS_SUCCESS ? *atom : 0 );
2206 return status;
2210 /***********************************************************************
2211 * NtQueryInformationAtom (NTDLL.@)
2213 NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS class,
2214 void *ptr, ULONG size, ULONG *retsize )
2216 NTSTATUS status;
2218 switch (class)
2220 case AtomBasicInformation:
2222 ULONG name_len;
2223 ATOM_BASIC_INFORMATION *abi = ptr;
2225 if (size < sizeof(ATOM_BASIC_INFORMATION)) return STATUS_INVALID_PARAMETER;
2226 name_len = size - sizeof(ATOM_BASIC_INFORMATION);
2228 if (atom < MAXINTATOM)
2230 if (atom)
2232 abi->NameLength = integral_atom_name( abi->Name, name_len, atom );
2233 status = name_len ? STATUS_SUCCESS : STATUS_BUFFER_TOO_SMALL;
2234 abi->ReferenceCount = 1;
2235 abi->Pinned = 1;
2237 else status = STATUS_INVALID_PARAMETER;
2239 else
2241 SERVER_START_REQ( get_atom_information )
2243 req->atom = atom;
2244 if (name_len) wine_server_set_reply( req, abi->Name, name_len );
2245 status = wine_server_call( req );
2246 if (status == STATUS_SUCCESS)
2248 name_len = wine_server_reply_size( reply );
2249 if (name_len)
2251 abi->NameLength = name_len;
2252 abi->Name[name_len / sizeof(WCHAR)] = 0;
2254 else
2256 name_len = reply->total;
2257 abi->NameLength = name_len;
2258 status = STATUS_BUFFER_TOO_SMALL;
2260 abi->ReferenceCount = reply->count;
2261 abi->Pinned = reply->pinned;
2263 else name_len = 0;
2265 SERVER_END_REQ;
2267 TRACE( "%x -> %s (%u)\n", atom, debugstr_wn(abi->Name, abi->NameLength / sizeof(WCHAR)), status );
2268 if (retsize) *retsize = sizeof(ATOM_BASIC_INFORMATION) + name_len;
2269 break;
2272 default:
2273 FIXME( "Unsupported class %u\n", class );
2274 status = STATUS_INVALID_INFO_CLASS;
2275 break;
2277 return status;
2281 union tid_alert_entry
2283 #ifdef __APPLE__
2284 semaphore_t sem;
2285 #else
2286 HANDLE event;
2287 #ifdef __linux__
2288 int futex;
2289 #endif
2290 #endif
2293 #define TID_ALERT_BLOCK_SIZE (65536 / sizeof(union tid_alert_entry))
2294 static union tid_alert_entry *tid_alert_blocks[4096];
2296 static unsigned int handle_to_index( HANDLE handle, unsigned int *block_idx )
2298 unsigned int idx = (wine_server_obj_handle(handle) >> 2) - 1;
2299 *block_idx = idx / TID_ALERT_BLOCK_SIZE;
2300 return idx % TID_ALERT_BLOCK_SIZE;
2303 static union tid_alert_entry *get_tid_alert_entry( HANDLE tid )
2305 unsigned int block_idx, idx = handle_to_index( tid, &block_idx );
2306 union tid_alert_entry *entry;
2308 if (block_idx > ARRAY_SIZE(tid_alert_blocks))
2310 FIXME( "tid %p is too high\n", tid );
2311 return NULL;
2314 if (!tid_alert_blocks[block_idx])
2316 static const size_t size = TID_ALERT_BLOCK_SIZE * sizeof(union tid_alert_entry);
2317 void *ptr = anon_mmap_alloc( size, PROT_READ | PROT_WRITE );
2318 if (ptr == MAP_FAILED) return NULL;
2319 if (InterlockedCompareExchangePointer( (void **)&tid_alert_blocks[block_idx], ptr, NULL ))
2320 munmap( ptr, size ); /* someone beat us to it */
2323 entry = &tid_alert_blocks[block_idx][idx % TID_ALERT_BLOCK_SIZE];
2325 #ifdef __APPLE__
2326 if (!entry->sem)
2328 semaphore_t sem;
2330 if (semaphore_create( mach_task_self(), &sem, SYNC_POLICY_FIFO, 0 ))
2331 return NULL;
2332 if (InterlockedCompareExchange( (int *)&entry->sem, sem, NULL ))
2333 semaphore_destroy( mach_task_self(), sem );
2335 #else
2336 #ifdef __linux__
2337 if (use_futexes())
2338 return entry;
2339 #endif
2341 if (!entry->event)
2343 HANDLE event;
2345 if (NtCreateEvent( &event, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE ))
2346 return NULL;
2347 if (InterlockedCompareExchangePointer( &entry->event, event, NULL ))
2348 NtClose( event );
2350 #endif
2352 return entry;
2356 /***********************************************************************
2357 * NtAlertThreadByThreadId (NTDLL.@)
2359 NTSTATUS WINAPI NtAlertThreadByThreadId( HANDLE tid )
2361 union tid_alert_entry *entry = get_tid_alert_entry( tid );
2363 TRACE( "%p\n", tid );
2365 if (!entry) return STATUS_INVALID_CID;
2367 #ifdef __APPLE__
2368 semaphore_signal( entry->sem );
2369 return STATUS_SUCCESS;
2370 #else
2371 #ifdef __linux__
2372 if (use_futexes())
2374 int *futex = &entry->futex;
2375 if (!InterlockedExchange( futex, 1 ))
2376 futex_wake( futex, 1 );
2377 return STATUS_SUCCESS;
2379 #endif
2381 return NtSetEvent( entry->event, NULL );
2382 #endif
2386 #if defined(__linux__) || defined(__APPLE__)
2387 static LONGLONG get_absolute_timeout( const LARGE_INTEGER *timeout )
2389 LARGE_INTEGER now;
2391 if (timeout->QuadPart >= 0) return timeout->QuadPart;
2392 NtQuerySystemTime( &now );
2393 return now.QuadPart - timeout->QuadPart;
2396 static LONGLONG update_timeout( ULONGLONG end )
2398 LARGE_INTEGER now;
2399 LONGLONG timeleft;
2401 NtQuerySystemTime( &now );
2402 timeleft = end - now.QuadPart;
2403 if (timeleft < 0) timeleft = 0;
2404 return timeleft;
2406 #endif
2409 #ifdef __APPLE__
2411 /***********************************************************************
2412 * NtWaitForAlertByThreadId (NTDLL.@)
2414 NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEGER *timeout )
2416 union tid_alert_entry *entry = get_tid_alert_entry( NtCurrentTeb()->ClientId.UniqueThread );
2417 semaphore_t sem;
2418 ULONGLONG end;
2419 kern_return_t ret;
2421 TRACE( "%p %s\n", address, debugstr_timeout( timeout ) );
2423 if (!entry) return STATUS_INVALID_CID;
2424 sem = entry->sem;
2426 if (timeout)
2428 if (timeout->QuadPart == TIMEOUT_INFINITE)
2429 timeout = NULL;
2430 else
2431 end = get_absolute_timeout( timeout );
2434 for (;;)
2436 if (timeout)
2438 LONGLONG timeleft = update_timeout( end );
2439 mach_timespec_t timespec;
2441 timespec.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC;
2442 timespec.tv_nsec = (timeleft % TICKSPERSEC) * 100;
2443 ret = semaphore_timedwait( sem, timespec );
2445 else
2446 ret = semaphore_wait( sem );
2448 switch (ret)
2450 case KERN_SUCCESS: return STATUS_ALERTED;
2451 case KERN_ABORTED: continue;
2452 case KERN_OPERATION_TIMED_OUT: return STATUS_TIMEOUT;
2453 default: return STATUS_INVALID_HANDLE;
2458 #else
2460 /***********************************************************************
2461 * NtWaitForAlertByThreadId (NTDLL.@)
2463 NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEGER *timeout )
2465 union tid_alert_entry *entry = get_tid_alert_entry( NtCurrentTeb()->ClientId.UniqueThread );
2466 NTSTATUS status;
2468 TRACE( "%p %s\n", address, debugstr_timeout( timeout ) );
2470 if (!entry) return STATUS_INVALID_CID;
2472 #ifdef __linux__
2473 if (use_futexes())
2475 int *futex = &entry->futex;
2476 ULONGLONG end;
2477 int ret;
2479 if (timeout)
2481 if (timeout->QuadPart == TIMEOUT_INFINITE)
2482 timeout = NULL;
2483 else
2484 end = get_absolute_timeout( timeout );
2487 while (!InterlockedExchange( futex, 0 ))
2489 if (timeout)
2491 LONGLONG timeleft = update_timeout( end );
2492 struct timespec timespec;
2494 timespec.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC;
2495 timespec.tv_nsec = (timeleft % TICKSPERSEC) * 100;
2496 ret = futex_wait( futex, 0, &timespec );
2498 else
2499 ret = futex_wait( futex, 0, NULL );
2501 if (ret == -1 && errno == ETIMEDOUT) return STATUS_TIMEOUT;
2503 return STATUS_ALERTED;
2505 #endif
2507 status = NtWaitForSingleObject( entry->event, FALSE, timeout );
2508 if (!status) return STATUS_ALERTED;
2509 return status;
2512 #endif