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
35 #include <sys/types.h>
36 #ifdef HAVE_SYS_MMAN_H
39 #ifdef HAVE_SYS_SYSCALL_H
40 #include <sys/syscall.h>
42 #ifdef HAVE_SYS_TIME_H
43 # include <sys/time.h>
56 # include <mach/mach.h>
57 # include <mach/task.h>
58 # include <mach/semaphore.h>
59 # include <mach/mach_time.h>
63 #define WIN32_NO_STATUS
64 #define NONAMELESSUNION
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)
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;
94 return mach_absolute_time() * timebase
.numer
/ timebase
.denom
/ 100;
95 #elif defined(HAVE_CLOCK_GETTIME)
97 #ifdef CLOCK_MONOTONIC_RAW
98 if (!clock_gettime( CLOCK_MONOTONIC_RAW
, &ts
))
99 return ts
.tv_sec
* (ULONGLONG
)TICKSPERSEC
+ ts
.tv_nsec
/ 100;
101 if (!clock_gettime( CLOCK_MONOTONIC
, &ts
))
102 return ts
.tv_sec
* (ULONGLONG
)TICKSPERSEC
+ ts
.tv_nsec
/ 100;
104 gettimeofday( &now
, 0 );
105 return ticks_from_time_t( now
.tv_sec
) + now
.tv_usec
* 10 - server_start_time
;
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;
132 futex_wait( &supported
, 10, NULL
);
136 futex_wait( &supported
, 10, NULL
);
138 supported
= (errno
!= ENOSYS
);
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
;
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
);
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
);
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
)
263 struct object_attributes
*objattr
;
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
;
274 wine_server_add_data( req
, objattr
, len
);
275 ret
= wine_server_call( req
);
276 *handle
= wine_server_ptr_handle( reply
->handle
);
285 /******************************************************************************
286 * NtOpenSemaphore (NTDLL.@)
288 NTSTATUS WINAPI
NtOpenSemaphore( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
310 /******************************************************************************
311 * NtQuerySemaphore (NTDLL.@)
313 NTSTATUS WINAPI
NtQuerySemaphore( HANDLE handle
, SEMAPHORE_INFORMATION_CLASS
class,
314 void *info
, ULONG len
, ULONG
*ret_len
)
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
);
344 /******************************************************************************
345 * NtReleaseSemaphore (NTDLL.@)
347 NTSTATUS WINAPI
NtReleaseSemaphore( HANDLE handle
, ULONG count
, ULONG
*previous
)
351 SERVER_START_REQ( release_semaphore
)
353 req
->handle
= wine_server_obj_handle( handle
);
355 if (!(ret
= wine_server_call( req
)))
357 if (previous
) *previous
= reply
->prev_count
;
365 /**************************************************************************
366 * NtCreateEvent (NTDLL.@)
368 NTSTATUS WINAPI
NtCreateEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
369 EVENT_TYPE type
, BOOLEAN state
)
373 struct object_attributes
*objattr
;
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
);
395 /******************************************************************************
396 * NtOpenEvent (NTDLL.@)
398 NTSTATUS WINAPI
NtOpenEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
420 /******************************************************************************
421 * NtSetEvent (NTDLL.@)
423 NTSTATUS WINAPI
NtSetEvent( HANDLE handle
, LONG
*prev_state
)
427 SERVER_START_REQ( event_op
)
429 req
->handle
= wine_server_obj_handle( handle
);
431 ret
= wine_server_call( req
);
432 if (!ret
&& prev_state
) *prev_state
= reply
->state
;
439 /******************************************************************************
440 * NtResetEvent (NTDLL.@)
442 NTSTATUS WINAPI
NtResetEvent( HANDLE handle
, LONG
*prev_state
)
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
;
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
)
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
;
487 /******************************************************************************
488 * NtQueryEvent (NTDLL.@)
490 NTSTATUS WINAPI
NtQueryEvent( HANDLE handle
, EVENT_INFORMATION_CLASS
class,
491 void *info
, ULONG len
, ULONG
*ret_len
)
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",
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
);
522 /******************************************************************************
523 * NtCreateMutant (NTDLL.@)
525 NTSTATUS WINAPI
NtCreateMutant( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
530 struct object_attributes
*objattr
;
533 if ((ret
= alloc_object_attributes( attr
, &objattr
, &len
))) return ret
;
535 SERVER_START_REQ( create_mutex
)
537 req
->access
= access
;
539 wine_server_add_data( req
, objattr
, len
);
540 ret
= wine_server_call( req
);
541 *handle
= wine_server_ptr_handle( reply
->handle
);
550 /**************************************************************************
551 * NtOpenMutant (NTDLL.@)
553 NTSTATUS WINAPI
NtOpenMutant( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
575 /**************************************************************************
576 * NtReleaseMutant (NTDLL.@)
578 NTSTATUS WINAPI
NtReleaseMutant( HANDLE handle
, LONG
*prev_count
)
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
;
593 /******************************************************************
594 * NtQueryMutant (NTDLL.@)
596 NTSTATUS WINAPI
NtQueryMutant( HANDLE handle
, MUTANT_INFORMATION_CLASS
class,
597 void *info
, ULONG len
, ULONG
*ret_len
)
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
);
628 /**************************************************************************
629 * NtCreateJobObject (NTDLL.@)
631 NTSTATUS WINAPI
NtCreateJobObject( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
635 struct object_attributes
*objattr
;
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
);
653 /**************************************************************************
654 * NtOpenJobObject (NTDLL.@)
656 NTSTATUS WINAPI
NtOpenJobObject( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
678 /**************************************************************************
679 * NtTerminateJobObject (NTDLL.@)
681 NTSTATUS WINAPI
NtTerminateJobObject( HANDLE handle
, NTSTATUS status
)
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
);
699 /**************************************************************************
700 * NtQueryInformationJobObject (NTDLL.@)
702 NTSTATUS WINAPI
NtQueryInformationJobObject( HANDLE handle
, JOBOBJECTINFOCLASS
class, void *info
,
703 ULONG len
, ULONG
*ret_len
)
707 TRACE( "semi-stub: %p %u %p %u %p\n", handle
, class, info
, len
, ret_len
);
709 if (class >= MaxJobObjectInfoClass
) return STATUS_INVALID_PARAMETER
;
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
;
729 if (ret_len
) *ret_len
= sizeof(*accounting
);
732 case JobObjectBasicProcessIdList
:
734 JOBOBJECT_BASIC_PROCESS_ID_LIST
*process
= info
;
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
);
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
;
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
;
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
;
811 case JobObjectExtendedLimitInformation
:
812 info_size
= sizeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION
);
813 limit_flags
= JOB_OBJECT_EXTENDED_LIMIT_VALID_FLAGS
;
815 case JobObjectBasicLimitInformation
:
816 if (len
!= info_size
) return STATUS_INVALID_PARAMETER
;
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
);
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
);
839 case JobObjectBasicUIRestrictions
:
840 status
= STATUS_SUCCESS
;
843 FIXME( "stub: %p %u %p %u\n", handle
, class, info
, len
);
849 /**************************************************************************
850 * NtIsProcessInJob (NTDLL.@)
852 NTSTATUS WINAPI
NtIsProcessInJob( HANDLE process
, HANDLE job
)
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
);
869 /**************************************************************************
870 * NtAssignProcessToJobObject (NTDLL.@)
872 NTSTATUS WINAPI
NtAssignProcessToJobObject( HANDLE job
, HANDLE process
)
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
);
889 /**********************************************************************
890 * NtCreateDebugObject (NTDLL.@)
892 NTSTATUS WINAPI
NtCreateDebugObject( HANDLE
*handle
, ACCESS_MASK access
,
893 OBJECT_ATTRIBUTES
*attr
, ULONG flags
)
897 struct object_attributes
*objattr
;
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
;
907 wine_server_add_data( req
, objattr
, len
);
908 ret
= wine_server_call( req
);
909 *handle
= wine_server_ptr_handle( reply
->handle
);
917 /**********************************************************************
918 * NtSetInformationDebugObject (NTDLL.@)
920 NTSTATUS WINAPI
NtSetInformationDebugObject( HANDLE handle
, DEBUGOBJECTINFOCLASS
class,
921 void *info
, ULONG len
, ULONG
*ret_len
)
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
);
939 ret
= wine_server_call( req
);
942 if (!ret
&& ret_len
) *ret_len
= 0;
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
)
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
)
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
);
1040 if (ret
!= STATUS_PENDING
) return ret
;
1041 if (!wait
) return STATUS_TIMEOUT
;
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
)
1056 struct object_attributes
*objattr
;
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
);
1074 /**************************************************************************
1075 * NtOpenDirectoryObject (NTDLL.@)
1077 NTSTATUS WINAPI
NtOpenDirectoryObject( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
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
)
1108 if (restart
) *context
= 0;
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;
1137 *ret_size
= buffer
->ObjectName
.MaximumLength
+ buffer
->ObjectTypeName
.MaximumLength
+ sizeof(*buffer
);
1141 FIXME("multiple entries not implemented\n");
1142 ret
= STATUS_NOT_IMPLEMENTED
;
1148 /**************************************************************************
1149 * NtCreateSymbolicLinkObject (NTDLL.@)
1151 NTSTATUS WINAPI
NtCreateSymbolicLinkObject( HANDLE
*handle
, ACCESS_MASK access
,
1152 OBJECT_ATTRIBUTES
*attr
, UNICODE_STRING
*target
)
1156 struct object_attributes
*objattr
;
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
);
1177 /**************************************************************************
1178 * NtOpenSymbolicLinkObject (NTDLL.@)
1180 NTSTATUS WINAPI
NtOpenSymbolicLinkObject( HANDLE
*handle
, ACCESS_MASK access
,
1181 const OBJECT_ATTRIBUTES
*attr
)
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
);
1203 /**************************************************************************
1204 * NtQuerySymbolicLinkObject (NTDLL.@)
1206 NTSTATUS WINAPI
NtQuerySymbolicLinkObject( HANDLE handle
, UNICODE_STRING
*target
, ULONG
*length
)
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
);
1230 /**************************************************************************
1231 * NtMakeTemporaryObject (NTDLL.@)
1233 NTSTATUS WINAPI
NtMakeTemporaryObject( HANDLE handle
)
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
);
1249 /**************************************************************************
1250 * NtCreateTimer (NTDLL.@)
1252 NTSTATUS WINAPI
NtCreateTimer( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
,
1257 struct object_attributes
*objattr
;
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
);
1279 /**************************************************************************
1280 * NtOpenTimer (NTDLL.@)
1282 NTSTATUS WINAPI
NtOpenTimer( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
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
;
1326 /* set error but can still succeed */
1327 if (resume
&& ret
== STATUS_SUCCESS
) return STATUS_TIMER_RESUME_IGNORED
;
1332 /**************************************************************************
1333 * NtCancelTimer (NTDLL.@)
1335 NTSTATUS WINAPI
NtCancelTimer( HANDLE handle
, BOOLEAN
*state
)
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
;
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
;
1360 TRACE( "(%p,%d,%p,0x%08x,%p)\n", handle
, class, info
, len
, ret_len
);
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
;
1377 /* convert into relative time */
1378 if (basic_info
->RemainingTime
.QuadPart
> 0) NtQuerySystemTime( &now
);
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;
1388 basic_info
->RemainingTime
.QuadPart
-= now
.QuadPart
;
1390 if (ret_len
) *ret_len
= sizeof(TIMER_BASIC_INFORMATION
);
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)
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
);
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 */
1480 if (!when
) return STATUS_SUCCESS
;
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
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
;
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;
1535 #endif /* HAVE_CLOCK_GETTIME */
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
)
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() */
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
1595 if (!has_request
&& !set
)
1596 return STATUS_TIMER_RESOLUTION_NOT_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)
1629 #ifdef HAVE_CLOCK_GETTIME
1632 if (!clock_gettime( CLOCK_REALTIME
, &ts
))
1633 return ticks_from_time_t( ts
.tv_sec
) + (ts
.tv_nsec
+ 50) / 100;
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
)
1648 struct object_attributes
*objattr
;
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
);
1667 /******************************************************************************
1668 * NtOpenKeyedEvent (NTDLL.@)
1670 NTSTATUS WINAPI
NtOpenKeyedEvent( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
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
,
1737 struct object_attributes
*objattr
;
1739 TRACE( "(%p, %x, %p, %d)\n", handle
, access
, attr
, threads
);
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
);
1758 /***********************************************************************
1759 * NtOpenIoCompletion (NTDLL.@)
1761 NTSTATUS WINAPI
NtOpenIoCompletion( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
1783 /***********************************************************************
1784 * NtSetIoCompletion (NTDLL.@)
1786 NTSTATUS WINAPI
NtSetIoCompletion( HANDLE handle
, ULONG_PTR key
, ULONG_PTR value
,
1787 NTSTATUS status
, SIZE_T count
)
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
);
1797 req
->cvalue
= value
;
1798 req
->status
= status
;
1799 req
->information
= count
;
1800 ret
= wine_server_call( req
);
1807 /***********************************************************************
1808 * NtRemoveIoCompletion (NTDLL.@)
1810 NTSTATUS WINAPI
NtRemoveIoCompletion( HANDLE handle
, ULONG_PTR
*key
, ULONG_PTR
*value
,
1811 IO_STATUS_BLOCK
*io
, LARGE_INTEGER
*timeout
)
1815 TRACE( "(%p, %p, %p, %p, %p)\n", handle
, key
, value
, io
, timeout
);
1819 SERVER_START_REQ( remove_completion
)
1821 req
->handle
= wine_server_obj_handle( handle
);
1822 if (!(status
= wine_server_call( req
)))
1825 *value
= reply
->cvalue
;
1826 io
->Information
= reply
->information
;
1827 io
->u
.Status
= reply
->status
;
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
)
1847 TRACE( "%p %p %u %p %p %u\n", handle
, info
, count
, written
, timeout
, alertable
);
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
;
1865 if (status
!= STATUS_SUCCESS
) break;
1868 if (i
|| status
!= STATUS_PENDING
)
1870 if (status
== STATUS_PENDING
) status
= STATUS_SUCCESS
;
1873 status
= NtWaitForSingleObject( handle
, alertable
, timeout
);
1874 if (status
!= WAIT_OBJECT_0
) break;
1876 *written
= i
? i
: 1;
1881 /***********************************************************************
1882 * NtQueryIoCompletion (NTDLL.@)
1884 NTSTATUS WINAPI
NtQueryIoCompletion( HANDLE handle
, IO_COMPLETION_INFORMATION_CLASS
class,
1885 void *buffer
, ULONG len
, ULONG
*ret_len
)
1889 TRACE( "(%p, %d, %p, 0x%x, %p)\n", handle
, class, buffer
, len
, ret_len
);
1891 if (!buffer
) return STATUS_INVALID_PARAMETER
;
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
;
1908 else status
= STATUS_INFO_LENGTH_MISMATCH
;
1912 return STATUS_INVALID_PARAMETER
;
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
)
1926 unsigned int file_access
;
1928 struct object_attributes
*objattr
;
1932 switch (protect
& 0xff)
1935 case PAGE_EXECUTE_READ
:
1936 case PAGE_WRITECOPY
:
1937 case PAGE_EXECUTE_WRITECOPY
:
1938 file_access
= FILE_READ_DATA
;
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
;
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
);
1973 /***********************************************************************
1974 * NtOpenSection (NTDLL.@)
1976 NTSTATUS WINAPI
NtOpenSection( HANDLE
*handle
, ACCESS_MASK access
, const OBJECT_ATTRIBUTES
*attr
)
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
);
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
);
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
)
2109 if ((ULONG_PTR
)atomstr
>> 16)
2111 const WCHAR
* ptr
= atomstr
;
2112 if (!len
) return STATUS_OBJECT_NAME_INVALID
;
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
);
2128 if (!atom
|| atom
>= MAXINTATOM
) return STATUS_INVALID_PARAMETER
;
2130 return STATUS_SUCCESS
;
2133 static ULONG
integral_atom_name( WCHAR
*buffer
, ULONG len
, RTL_ATOM atom
)
2136 int ret
= sprintf( tmp
, "#%u", atom
);
2138 len
/= sizeof(WCHAR
);
2141 if (len
<= ret
) ret
= len
- 1;
2142 ascii_to_unicode( buffer
, tmp
, ret
);
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
;
2166 TRACE( "%s -> %x\n", debugstr_wn(name
, length
/sizeof(WCHAR
)), status
== STATUS_SUCCESS
? *atom
: 0 );
2171 /***********************************************************************
2172 * NtDeleteAtom (NTDLL.@)
2174 NTSTATUS WINAPI
NtDeleteAtom( RTL_ATOM atom
)
2178 SERVER_START_REQ( delete_atom
)
2181 status
= wine_server_call( req
);
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
;
2205 TRACE( "%s -> %x\n", debugstr_wn(name
, length
/sizeof(WCHAR
)), status
== STATUS_SUCCESS
? *atom
: 0 );
2210 /***********************************************************************
2211 * NtQueryInformationAtom (NTDLL.@)
2213 NTSTATUS WINAPI
NtQueryInformationAtom( RTL_ATOM atom
, ATOM_INFORMATION_CLASS
class,
2214 void *ptr
, ULONG size
, ULONG
*retsize
)
2220 case AtomBasicInformation
:
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
)
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;
2237 else status
= STATUS_INVALID_PARAMETER
;
2241 SERVER_START_REQ( get_atom_information
)
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
);
2251 abi
->NameLength
= name_len
;
2252 abi
->Name
[name_len
/ sizeof(WCHAR
)] = 0;
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
;
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
;
2273 FIXME( "Unsupported class %u\n", class );
2274 status
= STATUS_INVALID_INFO_CLASS
;
2281 union tid_alert_entry
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
);
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
];
2330 if (semaphore_create( mach_task_self(), &sem
, SYNC_POLICY_FIFO
, 0 ))
2332 if (InterlockedCompareExchange( (int *)&entry
->sem
, sem
, NULL
))
2333 semaphore_destroy( mach_task_self(), sem
);
2345 if (NtCreateEvent( &event
, EVENT_ALL_ACCESS
, NULL
, SynchronizationEvent
, FALSE
))
2347 if (InterlockedCompareExchangePointer( &entry
->event
, event
, NULL
))
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
;
2368 semaphore_signal( entry
->sem
);
2369 return STATUS_SUCCESS
;
2374 int *futex
= &entry
->futex
;
2375 if (!InterlockedExchange( futex
, 1 ))
2376 futex_wake( futex
, 1 );
2377 return STATUS_SUCCESS
;
2381 return NtSetEvent( entry
->event
, NULL
);
2386 #if defined(__linux__) || defined(__APPLE__)
2387 static LONGLONG
get_absolute_timeout( const LARGE_INTEGER
*timeout
)
2391 if (timeout
->QuadPart
>= 0) return timeout
->QuadPart
;
2392 NtQuerySystemTime( &now
);
2393 return now
.QuadPart
- timeout
->QuadPart
;
2396 static LONGLONG
update_timeout( ULONGLONG end
)
2401 NtQuerySystemTime( &now
);
2402 timeleft
= end
- now
.QuadPart
;
2403 if (timeleft
< 0) timeleft
= 0;
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
);
2421 TRACE( "%p %s\n", address
, debugstr_timeout( timeout
) );
2423 if (!entry
) return STATUS_INVALID_CID
;
2428 if (timeout
->QuadPart
== TIMEOUT_INFINITE
)
2431 end
= get_absolute_timeout( 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
);
2446 ret
= semaphore_wait( sem
);
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
;
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
);
2468 TRACE( "%p %s\n", address
, debugstr_timeout( timeout
) );
2470 if (!entry
) return STATUS_INVALID_CID
;
2475 int *futex
= &entry
->futex
;
2481 if (timeout
->QuadPart
== TIMEOUT_INFINITE
)
2484 end
= get_absolute_timeout( timeout
);
2487 while (!InterlockedExchange( futex
, 0 ))
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, ×pec
);
2499 ret
= futex_wait( futex
, 0, NULL
);
2501 if (ret
== -1 && errno
== ETIMEDOUT
) return STATUS_TIMEOUT
;
2503 return STATUS_ALERTED
;
2507 status
= NtWaitForSingleObject( entry
->event
, FALSE
, timeout
);
2508 if (!status
) return STATUS_ALERTED
;