diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index e7c1fa1dcf3..e5a49ba1a1f 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -140,6 +140,7 @@ @ stdcall -syscall NtAdjustPrivilegesToken(long long ptr long ptr ptr) @ stdcall -syscall NtAlertResumeThread(long ptr) @ stdcall -syscall NtAlertThread(long) +@ stdcall -syscall NtAlertThreadByThreadId(ptr) @ stdcall -syscall NtAllocateLocallyUniqueId(ptr) # @ stub NtAllocateUserPhysicalPages @ stdcall -syscall NtAllocateUuids(ptr ptr ptr ptr) @@ -424,6 +425,7 @@ @ stdcall -syscall NtUnmapViewOfSection(long ptr) # @ stub NtVdmControl # @ stub NtW32Call +@ stdcall -syscall NtWaitForAlertByThreadId(ptr ptr) @ stdcall -syscall NtWaitForDebugEvent(long long ptr ptr) @ stdcall -syscall NtWaitForKeyedEvent(long ptr long ptr) @ stdcall -syscall NtWaitForMultipleObjects(long ptr long long ptr) @@ -1161,6 +1163,7 @@ @ stdcall -private -syscall ZwAdjustPrivilegesToken(long long ptr long ptr ptr) NtAdjustPrivilegesToken @ stdcall -private -syscall ZwAlertResumeThread(long ptr) NtAlertResumeThread @ stdcall -private -syscall ZwAlertThread(long) NtAlertThread +@ stdcall -private -syscall ZwAlertThreadByThreadId(ptr) NtAlertThreadByThreadId @ stdcall -private -syscall ZwAllocateLocallyUniqueId(ptr) NtAllocateLocallyUniqueId # @ stub ZwAllocateUserPhysicalPages @ stdcall -private -syscall ZwAllocateUuids(ptr ptr ptr ptr) NtAllocateUuids @@ -1443,6 +1446,7 @@ @ stdcall -private -syscall ZwUnmapViewOfSection(long ptr) NtUnmapViewOfSection # @ stub ZwVdmControl # @ stub ZwW32Call +@ stdcall -private -syscall ZwWaitForAlertByThreadId(ptr ptr) NtWaitForAlertByThreadId @ stdcall -private -syscall ZwWaitForDebugEvent(long long ptr ptr) NtWaitForDebugEvent @ stdcall -private -syscall ZwWaitForKeyedEvent(long ptr long ptr) NtWaitForKeyedEvent @ stdcall -private -syscall ZwWaitForMultipleObjects(long ptr long long ptr) NtWaitForMultipleObjects diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 99226d472da..7f36dc42579 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -132,6 +132,7 @@ static void * const syscalls[] = NtAdjustPrivilegesToken, NtAlertResumeThread, NtAlertThread, + NtAlertThreadByThreadId, NtAllocateLocallyUniqueId, NtAllocateUuids, NtAllocateVirtualMemory, @@ -334,6 +335,7 @@ static void * const syscalls[] = NtUnlockFile, NtUnlockVirtualMemory, NtUnmapViewOfSection, + NtWaitForAlertByThreadId, NtWaitForDebugEvent, NtWaitForKeyedEvent, NtWaitForMultipleObjects, diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index daf9f46f43b..33cd1d84dd5 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -33,6 +33,9 @@ #include #include #include +#ifdef HAVE_SYS_MMAN_H +#include +#endif #ifdef HAVE_SYS_SYSCALL_H #include #endif @@ -74,6 +77,12 @@ static const LARGE_INTEGER zero_timeout; static pthread_mutex_t addr_mutex = PTHREAD_MUTEX_INITIALIZER; +static const char *debugstr_timeout( const LARGE_INTEGER *timeout ) +{ + if (!timeout) return "(infinite)"; + return wine_dbgstr_longlong( timeout->QuadPart ); +} + /* return a monotonic time counter, in Win32 ticks */ static inline ULONGLONG monotonic_counter(void) { @@ -2330,6 +2339,90 @@ NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS cl } +union tid_alert_entry +{ + HANDLE event; +}; + +#define TID_ALERT_BLOCK_SIZE (65536 / sizeof(union tid_alert_entry)) +static union tid_alert_entry *tid_alert_blocks[4096]; + +static unsigned int handle_to_index( HANDLE handle, unsigned int *block_idx ) +{ + unsigned int idx = (wine_server_obj_handle(handle) >> 2) - 1; + *block_idx = idx / TID_ALERT_BLOCK_SIZE; + return idx % TID_ALERT_BLOCK_SIZE; +} + +static union tid_alert_entry *get_tid_alert_entry( HANDLE tid ) +{ + unsigned int block_idx, idx = handle_to_index( tid, &block_idx ); + union tid_alert_entry *entry; + + if (block_idx > ARRAY_SIZE(tid_alert_blocks)) + { + FIXME( "tid %p is too high\n", tid ); + return NULL; + } + + if (!tid_alert_blocks[block_idx]) + { + static const size_t size = TID_ALERT_BLOCK_SIZE * sizeof(union tid_alert_entry); + void *ptr = anon_mmap_alloc( size, PROT_READ | PROT_WRITE ); + if (ptr == MAP_FAILED) return NULL; + if (InterlockedCompareExchangePointer( (void **)&tid_alert_blocks[block_idx], ptr, NULL )) + munmap( ptr, size ); /* someone beat us to it */ + } + + entry = &tid_alert_blocks[block_idx][idx % TID_ALERT_BLOCK_SIZE]; + + if (!entry->event) + { + HANDLE event; + + if (NtCreateEvent( &event, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE )) + return NULL; + if (InterlockedCompareExchangePointer( &entry->event, event, NULL )) + NtClose( event ); + } + + return entry; +} + + +/*********************************************************************** + * NtAlertThreadByThreadId (NTDLL.@) + */ +NTSTATUS WINAPI NtAlertThreadByThreadId( HANDLE tid ) +{ + union tid_alert_entry *entry = get_tid_alert_entry( tid ); + + TRACE( "%p\n", tid ); + + if (!entry) return STATUS_INVALID_CID; + + return NtSetEvent( entry->event, NULL ); +} + + +/*********************************************************************** + * NtWaitForAlertByThreadId (NTDLL.@) + */ +NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEGER *timeout ) +{ + union tid_alert_entry *entry = get_tid_alert_entry( NtCurrentTeb()->ClientId.UniqueThread ); + NTSTATUS status; + + TRACE( "%p %s\n", address, debugstr_timeout( timeout ) ); + + if (!entry) return STATUS_INVALID_CID; + + status = NtWaitForSingleObject( entry->event, FALSE, timeout ); + if (!status) return STATUS_ALERTED; + return status; +} + + #ifdef __linux__ NTSTATUS CDECL fast_RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit, int timeout ) diff --git a/dlls/wow64/process.c b/dlls/wow64/process.c index d66b973385b..fbe501ed034 100644 --- a/dlls/wow64/process.c +++ b/dlls/wow64/process.c @@ -460,6 +460,17 @@ NTSTATUS WINAPI wow64_NtAlertThread( UINT *args ) } +/********************************************************************** + * wow64_NtAlertThreadByThreadId + */ +NTSTATUS WINAPI wow64_NtAlertThreadByThreadId( UINT *args ) +{ + HANDLE tid = get_handle( &args ); + + return NtAlertThreadByThreadId( tid ); +} + + /********************************************************************** * wow64_NtAssignProcessToJobObject */ diff --git a/dlls/wow64/sync.c b/dlls/wow64/sync.c index e2e9468a727..20776378a7d 100644 --- a/dlls/wow64/sync.c +++ b/dlls/wow64/sync.c @@ -1460,6 +1460,18 @@ NTSTATUS WINAPI wow64_NtTraceControl( UINT *args ) } +/********************************************************************** + * wow64_NtWaitForAlertByThreadId + */ +NTSTATUS WINAPI wow64_NtWaitForAlertByThreadId( UINT *args ) +{ + const void *address = get_ptr( &args ); + const LARGE_INTEGER *timeout = get_ptr( &args ); + + return NtWaitForAlertByThreadId( address, timeout ); +} + + /********************************************************************** * wow64_NtWaitForDebugEvent */ diff --git a/dlls/wow64/syscall.h b/dlls/wow64/syscall.h index bc403dd6d31..112711875f7 100644 --- a/dlls/wow64/syscall.h +++ b/dlls/wow64/syscall.h @@ -30,6 +30,7 @@ SYSCALL_ENTRY( NtAdjustPrivilegesToken ) \ SYSCALL_ENTRY( NtAlertResumeThread ) \ SYSCALL_ENTRY( NtAlertThread ) \ + SYSCALL_ENTRY( NtAlertThreadByThreadId ) \ SYSCALL_ENTRY( NtAllocateLocallyUniqueId ) \ SYSCALL_ENTRY( NtAllocateUuids ) \ SYSCALL_ENTRY( NtAllocateVirtualMemory ) \ @@ -231,6 +232,7 @@ SYSCALL_ENTRY( NtUnlockFile ) \ SYSCALL_ENTRY( NtUnlockVirtualMemory ) \ SYSCALL_ENTRY( NtUnmapViewOfSection ) \ + SYSCALL_ENTRY( NtWaitForAlertByThreadId ) \ SYSCALL_ENTRY( NtWaitForDebugEvent ) \ SYSCALL_ENTRY( NtWaitForKeyedEvent ) \ SYSCALL_ENTRY( NtWaitForMultipleObjects ) \ diff --git a/include/winternl.h b/include/winternl.h index eea97f1238b..cfd83f16337 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -3858,6 +3858,7 @@ NTSYSAPI NTSTATUS WINAPI NtAdjustGroupsToken(HANDLE,BOOLEAN,PTOKEN_GROUPS,ULONG NTSYSAPI NTSTATUS WINAPI NtAdjustPrivilegesToken(HANDLE,BOOLEAN,PTOKEN_PRIVILEGES,DWORD,PTOKEN_PRIVILEGES,PDWORD); NTSYSAPI NTSTATUS WINAPI NtAlertResumeThread(HANDLE,PULONG); NTSYSAPI NTSTATUS WINAPI NtAlertThread(HANDLE ThreadHandle); +NTSYSAPI NTSTATUS WINAPI NtAlertThreadByThreadId(HANDLE); NTSYSAPI NTSTATUS WINAPI NtAllocateLocallyUniqueId(PLUID lpLuid); NTSYSAPI NTSTATUS WINAPI NtAllocateUuids(PULARGE_INTEGER,PULONG,PULONG,PUCHAR); NTSYSAPI NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE,PVOID*,ULONG_PTR,SIZE_T*,ULONG,ULONG); @@ -4097,6 +4098,7 @@ NTSYSAPI NTSTATUS WINAPI NtUnlockFile(HANDLE,PIO_STATUS_BLOCK,PLARGE_INTEGER,PL NTSYSAPI NTSTATUS WINAPI NtUnlockVirtualMemory(HANDLE,PVOID*,SIZE_T*,ULONG); NTSYSAPI NTSTATUS WINAPI NtUnmapViewOfSection(HANDLE,PVOID); NTSYSAPI NTSTATUS WINAPI NtVdmControl(ULONG,PVOID); +NTSYSAPI NTSTATUS WINAPI NtWaitForAlertByThreadId(const void*,const LARGE_INTEGER*); NTSYSAPI NTSTATUS WINAPI NtWaitForDebugEvent(HANDLE,BOOLEAN,LARGE_INTEGER*,DBGUI_WAIT_STATE_CHANGE*); NTSYSAPI NTSTATUS WINAPI NtWaitForKeyedEvent(HANDLE,const void*,BOOLEAN,const LARGE_INTEGER*); NTSYSAPI NTSTATUS WINAPI NtWaitForSingleObject(HANDLE,BOOLEAN,const LARGE_INTEGER*);