From 4d20defb0e12891e3d85a2f162f152f89cf0447d 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 aad7bd89d14..8544d759587 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -138,6 +138,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) diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index d31c5b69015..2dad70be456 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 @@ -82,6 +85,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) { @@ -2333,6 +2342,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 7a8a977b512..6bb6ad58277 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -3799,6 +3799,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); @@ -4036,6 +4037,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