Skip to content

Commit a26b0d2

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 9da64fc commit a26b0d2

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
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__)
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: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6469,6 +6469,8 @@ _dispatch_runloop_handle_is_valid(dispatch_runloop_handle_t handle)
64696469
return MACH_PORT_VALID(handle);
64706470
#elif defined(__linux__)
64716471
return handle >= 0;
6472+
#elif defined(__unix__)
6473+
return handle >= 0;
64726474
#elif defined(_WIN32)
64736475
return handle != NULL;
64746476
#else
@@ -6485,6 +6487,8 @@ _dispatch_runloop_queue_get_handle(dispatch_lane_t dq)
64856487
#elif defined(__linux__)
64866488
// decode: 0 is a valid fd, so offset by 1 to distinguish from NULL
64876489
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt) - 1;
6490+
#elif defined(__unix__)
6491+
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt);
64886492
#elif defined(_WIN32)
64896493
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt);
64906494
#else
@@ -6502,13 +6506,21 @@ _dispatch_runloop_queue_set_handle(dispatch_lane_t dq,
65026506
#elif defined(__linux__)
65036507
// encode: 0 is a valid fd, so offset by 1 to distinguish from NULL
65046508
dq->do_ctxt = (void *)(uintptr_t)(handle + 1);
6509+
#elif defined(__unix__)
6510+
dq->do_ctxt = (void *)(uintptr_t)handle;
65056511
#elif defined(_WIN32)
65066512
dq->do_ctxt = (void *)(uintptr_t)handle;
65076513
#else
65086514
#error "runloop support not implemented on this platform"
65096515
#endif
65106516
}
65116517

6518+
#if defined(__unix__)
6519+
#define DISPATCH_RUNLOOP_HANDLE_PACK(rfd, wfd) (((uint64_t)(rfd) << 32) | (wfd))
6520+
#define DISPATCH_RUNLOOP_HANDLE_RFD(h) ((int)((h) >> 32))
6521+
#define DISPATCH_RUNLOOP_HANDLE_WFD(h) ((int)((h) & 0xffffffff))
6522+
#endif
6523+
65126524
static void
65136525
_dispatch_runloop_queue_handle_init(void *ctxt)
65146526
{
@@ -6558,6 +6570,14 @@ _dispatch_runloop_queue_handle_init(void *ctxt)
65586570
}
65596571
}
65606572
handle = fd;
6573+
#elif defined(__unix__)
6574+
int fds[2];
6575+
int r = pipe2(fds, O_CLOEXEC | O_NONBLOCK);
6576+
if (r == -1) {
6577+
DISPATCH_CLIENT_CRASH(errno, "pipe2 failure");
6578+
}
6579+
uint32_t rfd = (uint32_t)fds[0], wfd = (uint32_t)fds[1];
6580+
handle = DISPATCH_RUNLOOP_HANDLE_PACK(rfd, wfd);
65616581
#elif defined(_WIN32)
65626582
HANDLE hEvent;
65636583
hEvent = CreateEventW(NULL, /*bManualReset=*/FALSE,
@@ -6592,6 +6612,11 @@ _dispatch_runloop_queue_handle_dispose(dispatch_lane_t dq)
65926612
#elif defined(__linux__)
65936613
int rc = close(handle);
65946614
(void)dispatch_assume_zero(rc);
6615+
#elif defined(__unix__)
6616+
int rc = close(DISPATCH_RUNLOOP_HANDLE_WFD(handle));
6617+
(void)dispatch_assume_zero(rc);
6618+
rc = close(DISPATCH_RUNLOOP_HANDLE_RFD(handle));
6619+
(void)dispatch_assume_zero(rc);
65956620
#elif defined(_WIN32)
65966621
BOOL bSuccess;
65976622
bSuccess = CloseHandle(handle);
@@ -6628,6 +6653,13 @@ _dispatch_runloop_queue_class_poke(dispatch_lane_t dq)
66286653
result = eventfd_write(handle, 1);
66296654
} while (result == -1 && errno == EINTR);
66306655
(void)dispatch_assume_zero(result);
6656+
#elif defined(__unix__)
6657+
int wfd = DISPATCH_RUNLOOP_HANDLE_WFD(handle);
6658+
ssize_t result;
6659+
do {
6660+
result = write(wfd, "x", 1);
6661+
} while (result == -1 && errno == EINTR);
6662+
(void)dispatch_assume_zero(result - 1);
66316663
#elif defined(_WIN32)
66326664
BOOL bSuccess;
66336665
bSuccess = SetEvent(handle);
@@ -7305,6 +7337,13 @@ _gettid(void)
73057337
{
73067338
return (pid_t)pthread_getthreadid_np();
73077339
}
7340+
#elif defined(__OpenBSD__)
7341+
DISPATCH_ALWAYS_INLINE
7342+
static inline pid_t
7343+
_gettid(void)
7344+
{
7345+
return getthrid();
7346+
}
73087347
#elif defined(_WIN32)
73097348
DISPATCH_ALWAYS_INLINE
73107349
static inline DWORD

0 commit comments

Comments
 (0)