From f910f81d3c8f3c01f7582738e61071ae7a24dfea Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 30 Apr 2021 16:35:13 -0500 Subject: [PATCH] ntdll: Implement thread-ID alerts using futexes if possible. Signed-off-by: Zebediah Figura --- dlls/ntdll/unix/sync.c | 76 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 014e5e5d0a7..058262ac0ad 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -2289,6 +2289,9 @@ NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS cl union tid_alert_entry { HANDLE event; +#ifdef __linux__ + int futex; +#endif }; #define TID_ALERT_BLOCK_SIZE (65536 / sizeof(union tid_alert_entry)) @@ -2323,6 +2326,11 @@ static union tid_alert_entry *get_tid_alert_entry( HANDLE tid ) entry = &tid_alert_blocks[block_idx][idx % TID_ALERT_BLOCK_SIZE]; +#ifdef __linux__ + if (use_futexes()) + return entry; +#endif + if (!entry->event) { HANDLE event; @@ -2348,10 +2356,43 @@ NTSTATUS WINAPI NtAlertThreadByThreadId( HANDLE tid ) if (!entry) return STATUS_INVALID_CID; +#ifdef __linux__ + if (use_futexes()) + { + int *futex = &entry->futex; + if (!InterlockedExchange( futex, 1 )) + futex_wake( futex, 1 ); + return STATUS_SUCCESS; + } +#endif + return NtSetEvent( entry->event, NULL ); } +#ifdef __linux__ +static LONGLONG get_absolute_timeout( const LARGE_INTEGER *timeout ) +{ + LARGE_INTEGER now; + + if (timeout->QuadPart >= 0) return timeout->QuadPart; + NtQuerySystemTime( &now ); + return now.QuadPart - timeout->QuadPart; +} + +static LONGLONG update_timeout( ULONGLONG end ) +{ + LARGE_INTEGER now; + LONGLONG timeleft; + + NtQuerySystemTime( &now ); + timeleft = end - now.QuadPart; + if (timeleft < 0) timeleft = 0; + return timeleft; +} +#endif + + /*********************************************************************** * NtWaitForAlertByThreadId (NTDLL.@) */ @@ -2364,6 +2405,41 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG if (!entry) return STATUS_INVALID_CID; +#ifdef __linux__ + if (use_futexes()) + { + int *futex = &entry->futex; + ULONGLONG end; + int ret; + + if (timeout) + { + if (timeout->QuadPart == TIMEOUT_INFINITE) + timeout = NULL; + else + end = get_absolute_timeout( timeout ); + } + + while (!InterlockedExchange( futex, 0 )) + { + if (timeout) + { + LONGLONG timeleft = update_timeout( end ); + struct timespec timespec; + + timespec.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; + timespec.tv_nsec = (timeleft % TICKSPERSEC) * 100; + ret = futex_wait( futex, 0, ×pec ); + } + else + ret = futex_wait( futex, 0, NULL ); + + if (ret == -1 && errno == ETIMEDOUT) return STATUS_TIMEOUT; + } + return STATUS_ALERTED; + } +#endif + status = NtWaitForSingleObject( entry->event, FALSE, timeout ); if (!status) return STATUS_ALERTED; return status; -- 2.30.2