[PATCH 3/4] ntdll: Implement thread-ID alerts using futexes if possible.

Zebediah Figura zfigura at codeweavers.com
Tue Nov 16 21:50:43 CST 2021


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 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 e58f3bd9261..47687d4d4e5 100644
--- a/dlls/ntdll/unix/sync.c
+++ b/dlls/ntdll/unix/sync.c
@@ -2400,6 +2400,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))
@@ -2434,6 +2437,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;
@@ -2459,10 +2467,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.@)
  */
@@ -2475,6 +2516,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, &timespec );
+            }
+            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.33.0




More information about the wine-devel mailing list