From b14229169f51d73f36bd5821388a3ba455ee5c99 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 30 Apr 2021 15:07:04 -0500 Subject: [PATCH] ntdll: Implement NtAlertThreadByThreadId and NtWaitForAlertByThreadId. Signed-off-by: Zebediah Figura --- dlls/ntdll/ntdll.spec | 2 + dlls/ntdll/unix/sync.c | 93 ++++++++++++++++++++++++++++++++++++++++++ include/winternl.h | 2 + 3 files changed, 97 insertions(+) diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index a9cf662a29a..c9cd6fb59fd 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -137,6 +137,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) @@ -423,6 +424,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) diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 16635ee42fa..014e5e5d0a7 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -32,6 +32,9 @@ #include #include #include +#ifdef HAVE_SYS_MMAN_H +#include +#endif #ifdef HAVE_SYS_SYSCALL_H #include #endif @@ -81,6 +84,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) { @@ -2277,6 +2286,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/include/winternl.h b/include/winternl.h index 69d0e32f1d4..a6c22a5711d 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -3639,6 +3639,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); @@ -3876,6 +3877,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*); -- 2.30.2