Commit c23c72fe authored by Marc-Aurel Zent's avatar Marc-Aurel Zent Committed by Alexandre Julliard

ntdll: Implement thread-ID alerts using kqueue/kevent.

parent 3448a84c
...@@ -49,11 +49,11 @@ ...@@ -49,11 +49,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
#ifdef __APPLE__ #ifdef __APPLE__
# include <mach/mach.h>
# include <mach/task.h>
# include <mach/semaphore.h>
# include <mach/mach_time.h> # include <mach/mach_time.h>
#endif #endif
#ifdef HAVE_KQUEUE
# include <sys/event.h>
#endif
#include "ntstatus.h" #include "ntstatus.h"
#define WIN32_NO_STATUS #define WIN32_NO_STATUS
...@@ -2354,8 +2354,8 @@ NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS cl ...@@ -2354,8 +2354,8 @@ NTSTATUS WINAPI NtQueryInformationAtom( RTL_ATOM atom, ATOM_INFORMATION_CLASS cl
union tid_alert_entry union tid_alert_entry
{ {
#ifdef __APPLE__ #ifdef HAVE_KQUEUE
semaphore_t sem; int kq;
#else #else
HANDLE event; HANDLE event;
#ifdef __linux__ #ifdef __linux__
...@@ -2396,15 +2396,35 @@ static union tid_alert_entry *get_tid_alert_entry( HANDLE tid ) ...@@ -2396,15 +2396,35 @@ static union tid_alert_entry *get_tid_alert_entry( HANDLE tid )
entry = &tid_alert_blocks[block_idx][idx % TID_ALERT_BLOCK_SIZE]; entry = &tid_alert_blocks[block_idx][idx % TID_ALERT_BLOCK_SIZE];
#ifdef __APPLE__ #ifdef HAVE_KQUEUE
if (!entry->sem) if (!entry->kq)
{ {
semaphore_t sem; int kq = kqueue();
static const struct kevent init_event =
{
.ident = 1,
.filter = EVFILT_USER,
.flags = EV_ADD | EV_CLEAR,
.fflags = 0,
.data = 0,
.udata = NULL
};
if (kq == -1)
{
ERR( "kqueue failed with error: %d (%s)\n", errno, strerror( errno ) );
return NULL;
}
if (semaphore_create( mach_task_self(), &sem, SYNC_POLICY_FIFO, 0 )) if (kevent( kq, &init_event, 1, NULL, 0, NULL) == -1)
{
ERR( "kevent creation failed with error: %d (%s)\n", errno, strerror( errno ) );
close( kq );
return NULL; return NULL;
if (InterlockedCompareExchange( (LONG *)&entry->sem, sem, 0 )) }
semaphore_destroy( mach_task_self(), sem );
if (InterlockedCompareExchange( (LONG *)&entry->kq, kq, 0 ))
close( kq );
} }
#else #else
#ifdef __linux__ #ifdef __linux__
...@@ -2438,9 +2458,21 @@ NTSTATUS WINAPI NtAlertThreadByThreadId( HANDLE tid ) ...@@ -2438,9 +2458,21 @@ NTSTATUS WINAPI NtAlertThreadByThreadId( HANDLE tid )
if (!entry) return STATUS_INVALID_CID; if (!entry) return STATUS_INVALID_CID;
#ifdef __APPLE__ #ifdef HAVE_KQUEUE
semaphore_signal( entry->sem ); {
return STATUS_SUCCESS; static const struct kevent signal_event =
{
.ident = 1,
.filter = EVFILT_USER,
.flags = 0,
.fflags = NOTE_TRIGGER,
.data = 0,
.udata = NULL
};
kevent( entry->kq, &signal_event, 1, NULL, 0, NULL );
return STATUS_SUCCESS;
}
#else #else
#ifdef __linux__ #ifdef __linux__
if (use_futexes()) if (use_futexes())
...@@ -2457,7 +2489,7 @@ NTSTATUS WINAPI NtAlertThreadByThreadId( HANDLE tid ) ...@@ -2457,7 +2489,7 @@ NTSTATUS WINAPI NtAlertThreadByThreadId( HANDLE tid )
} }
#if defined(__linux__) || defined(__APPLE__) #if defined(__linux__) || defined(HAVE_KQUEUE)
static LONGLONG get_absolute_timeout( const LARGE_INTEGER *timeout ) static LONGLONG get_absolute_timeout( const LARGE_INTEGER *timeout )
{ {
LARGE_INTEGER now; LARGE_INTEGER now;
...@@ -2480,7 +2512,7 @@ static LONGLONG update_timeout( ULONGLONG end ) ...@@ -2480,7 +2512,7 @@ static LONGLONG update_timeout( ULONGLONG end )
#endif #endif
#ifdef __APPLE__ #ifdef HAVE_KQUEUE
/*********************************************************************** /***********************************************************************
* NtWaitForAlertByThreadId (NTDLL.@) * NtWaitForAlertByThreadId (NTDLL.@)
...@@ -2488,14 +2520,14 @@ static LONGLONG update_timeout( ULONGLONG end ) ...@@ -2488,14 +2520,14 @@ static LONGLONG update_timeout( ULONGLONG end )
NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEGER *timeout ) NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEGER *timeout )
{ {
union tid_alert_entry *entry = get_tid_alert_entry( NtCurrentTeb()->ClientId.UniqueThread ); union tid_alert_entry *entry = get_tid_alert_entry( NtCurrentTeb()->ClientId.UniqueThread );
semaphore_t sem;
ULONGLONG end; ULONGLONG end;
kern_return_t ret; int ret;
struct timespec timespec;
struct kevent wait_event;
TRACE( "%p %s\n", address, debugstr_timeout( timeout ) ); TRACE( "%p %s\n", address, debugstr_timeout( timeout ) );
if (!entry) return STATUS_INVALID_CID; if (!entry) return STATUS_INVALID_CID;
sem = entry->sem;
if (timeout) if (timeout)
{ {
...@@ -2505,27 +2537,29 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG ...@@ -2505,27 +2537,29 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG
end = get_absolute_timeout( timeout ); end = get_absolute_timeout( timeout );
} }
for (;;) do
{ {
if (timeout) if (timeout)
{ {
LONGLONG timeleft = update_timeout( end ); LONGLONG timeleft = update_timeout( end );
mach_timespec_t timespec;
timespec.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; timespec.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC;
timespec.tv_nsec = (timeleft % TICKSPERSEC) * 100; timespec.tv_nsec = (timeleft % TICKSPERSEC) * 100;
ret = semaphore_timedwait( sem, timespec ); if (timespec.tv_sec > 0x7FFFFFFF) timeout = NULL;
} }
else
ret = semaphore_wait( sem );
switch (ret) ret = kevent( entry->kq, NULL, 0, &wait_event, 1, timeout ? &timespec : NULL );
{ } while (ret == -1 && errno == EINTR);
case KERN_SUCCESS: return STATUS_ALERTED;
case KERN_ABORTED: continue; switch (ret)
case KERN_OPERATION_TIMED_OUT: return STATUS_TIMEOUT; {
default: return STATUS_INVALID_HANDLE; case 1:
} return STATUS_ALERTED;
case 0:
return STATUS_TIMEOUT;
default:
ERR( "kevent failed with error: %d (%s)\n", errno, strerror( errno ) );
return STATUS_INVALID_HANDLE;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment