Skip to content

Commit 906efaa

Browse files
committed
Add a runloop implementation based on pipe2.
The Linux implementation uses an eventfd to impement the runloop contract for CF. However, ordinary POSIX pipes are a widely available API and can be used to achieve the same result as eventfd on other systems that support it. Since POSIX pipes require a pair of file descriptors, we force file descriptors to 32-bit integers and pack these two into a single 64-bit integer. This keeps the management of the runloop handle simple rather than having to manage the handle storage externally, for the cost of limiting the range of the file descriptor type.
1 parent 83e9914 commit 906efaa

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

private/private.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ void _dispatch_prohibit_transition_to_multithreaded(bool prohibit);
191191
typedef mach_port_t dispatch_runloop_handle_t;
192192
#elif defined(__linux__) || defined(__FreeBSD__)
193193
typedef int dispatch_runloop_handle_t;
194+
#elif defined(__unix__) && !defined(__linux__) && !defined(__FreeBSD__)
195+
typedef uint64_t dispatch_runloop_handle_t;
194196
#elif defined(_WIN32)
195197
typedef void *dispatch_runloop_handle_t;
196198
#else

src/queue.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6467,7 +6467,7 @@ _dispatch_runloop_handle_is_valid(dispatch_runloop_handle_t handle)
64676467
{
64686468
#if TARGET_OS_MAC
64696469
return MACH_PORT_VALID(handle);
6470-
#elif defined(__linux__)
6470+
#elif defined(__linux__) || defined(__unix__)
64716471
return handle >= 0;
64726472
#elif defined(_WIN32)
64736473
return handle != NULL;
@@ -6485,6 +6485,8 @@ _dispatch_runloop_queue_get_handle(dispatch_lane_t dq)
64856485
#elif defined(__linux__)
64866486
// decode: 0 is a valid fd, so offset by 1 to distinguish from NULL
64876487
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt) - 1;
6488+
#elif defined(__unix__) && !defined(__linux__)
6489+
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt);
64886490
#elif defined(_WIN32)
64896491
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt);
64906492
#else
@@ -6502,13 +6504,21 @@ _dispatch_runloop_queue_set_handle(dispatch_lane_t dq,
65026504
#elif defined(__linux__)
65036505
// encode: 0 is a valid fd, so offset by 1 to distinguish from NULL
65046506
dq->do_ctxt = (void *)(uintptr_t)(handle + 1);
6507+
#elif defined(__unix__) && !defined(__linux__)
6508+
dq->do_ctxt = (void *)(uintptr_t)handle;
65056509
#elif defined(_WIN32)
65066510
dq->do_ctxt = (void *)(uintptr_t)handle;
65076511
#else
65086512
#error "runloop support not implemented on this platform"
65096513
#endif
65106514
}
65116515

6516+
#if defined(__unix__)
6517+
#define DISPATCH_RUNLOOP_HANDLE_PACK(rfd, wfd) (((uint64_t)(rfd) << 32) | (wfd))
6518+
#define DISPATCH_RUNLOOP_HANDLE_RFD(h) ((int)((h) >> 32))
6519+
#define DISPATCH_RUNLOOP_HANDLE_WFD(h) ((int)((h) & 0xffffffff))
6520+
#endif
6521+
65126522
static void
65136523
_dispatch_runloop_queue_handle_init(void *ctxt)
65146524
{
@@ -6558,6 +6568,14 @@ _dispatch_runloop_queue_handle_init(void *ctxt)
65586568
}
65596569
}
65606570
handle = fd;
6571+
#elif defined(__unix__) && !defined(__linux__)
6572+
int fds[2];
6573+
int r = pipe2(fds, O_CLOEXEC | O_NONBLOCK);
6574+
if (r == -1) {
6575+
DISPATCH_CLIENT_CRASH(errno, "pipe2 failure");
6576+
}
6577+
uint32_t rfd = (uint32_t)fds[0], wfd = (uint32_t)fds[1];
6578+
handle = DISPATCH_RUNLOOP_HANDLE_PACK(rfd, wfd);
65616579
#elif defined(_WIN32)
65626580
HANDLE hEvent;
65636581
hEvent = CreateEventW(NULL, /*bManualReset=*/FALSE,
@@ -6592,6 +6610,11 @@ _dispatch_runloop_queue_handle_dispose(dispatch_lane_t dq)
65926610
#elif defined(__linux__)
65936611
int rc = close(handle);
65946612
(void)dispatch_assume_zero(rc);
6613+
#elif defined(__unix__) && !defined(__linux__)
6614+
int rc = close(DISPATCH_RUNLOOP_HANDLE_WFD(handle));
6615+
(void)dispatch_assume_zero(rc);
6616+
rc = close(DISPATCH_RUNLOOP_HANDLE_RFD(handle));
6617+
(void)dispatch_assume_zero(rc);
65956618
#elif defined(_WIN32)
65966619
BOOL bSuccess;
65976620
bSuccess = CloseHandle(handle);
@@ -6628,6 +6651,13 @@ _dispatch_runloop_queue_class_poke(dispatch_lane_t dq)
66286651
result = eventfd_write(handle, 1);
66296652
} while (result == -1 && errno == EINTR);
66306653
(void)dispatch_assume_zero(result);
6654+
#elif defined(__unix__) && !defined(__linux__)
6655+
int wfd = DISPATCH_RUNLOOP_HANDLE_WFD(handle);
6656+
ssize_t result;
6657+
do {
6658+
result = write(wfd, "x", 1);
6659+
} while (result == -1 && errno == EINTR);
6660+
(void)dispatch_assume_zero(result - 1);
66316661
#elif defined(_WIN32)
66326662
BOOL bSuccess;
66336663
bSuccess = SetEvent(handle);
@@ -7306,6 +7336,13 @@ _gettid(void)
73067336
{
73077337
return (pid_t)pthread_getthreadid_np();
73087338
}
7339+
#elif defined(__OpenBSD__)
7340+
DISPATCH_ALWAYS_INLINE
7341+
static inline pid_t
7342+
_gettid(void)
7343+
{
7344+
return getthrid();
7345+
}
73097346
#elif defined(_WIN32)
73107347
DISPATCH_ALWAYS_INLINE
73117348
static inline DWORD

0 commit comments

Comments
 (0)