Skip to content

Commit c52900b

Browse files
3405691582dana
authored and
dana
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 888f89c commit c52900b

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
@@ -6472,7 +6472,7 @@ _dispatch_runloop_handle_is_valid(dispatch_runloop_handle_t handle)
64726472
{
64736473
#if TARGET_OS_MAC
64746474
return MACH_PORT_VALID(handle);
6475-
#elif defined(__linux__)
6475+
#elif defined(__linux__) || defined(__unix__)
64766476
return handle >= 0;
64776477
#elif defined(_WIN32)
64786478
return handle != NULL;
@@ -6490,6 +6490,8 @@ _dispatch_runloop_queue_get_handle(dispatch_lane_t dq)
64906490
#elif defined(__linux__)
64916491
// decode: 0 is a valid fd, so offset by 1 to distinguish from NULL
64926492
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt) - 1;
6493+
#elif defined(__unix__) && !defined(__linux__)
6494+
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt);
64936495
#elif defined(_WIN32)
64946496
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt);
64956497
#else
@@ -6507,13 +6509,21 @@ _dispatch_runloop_queue_set_handle(dispatch_lane_t dq,
65076509
#elif defined(__linux__)
65086510
// encode: 0 is a valid fd, so offset by 1 to distinguish from NULL
65096511
dq->do_ctxt = (void *)(uintptr_t)(handle + 1);
6512+
#elif defined(__unix__) && !defined(__linux__)
6513+
dq->do_ctxt = (void *)(uintptr_t)handle;
65106514
#elif defined(_WIN32)
65116515
dq->do_ctxt = (void *)(uintptr_t)handle;
65126516
#else
65136517
#error "runloop support not implemented on this platform"
65146518
#endif
65156519
}
65166520

6521+
#if defined(__unix__)
6522+
#define DISPATCH_RUNLOOP_HANDLE_PACK(rfd, wfd) (((uint64_t)(rfd) << 32) | (wfd))
6523+
#define DISPATCH_RUNLOOP_HANDLE_RFD(h) ((int)((h) >> 32))
6524+
#define DISPATCH_RUNLOOP_HANDLE_WFD(h) ((int)((h) & 0xffffffff))
6525+
#endif
6526+
65176527
static void
65186528
_dispatch_runloop_queue_handle_init(void *ctxt)
65196529
{
@@ -6563,6 +6573,14 @@ _dispatch_runloop_queue_handle_init(void *ctxt)
65636573
}
65646574
}
65656575
handle = fd;
6576+
#elif defined(__unix__) && !defined(__linux__)
6577+
int fds[2];
6578+
int r = pipe2(fds, O_CLOEXEC | O_NONBLOCK);
6579+
if (r == -1) {
6580+
DISPATCH_CLIENT_CRASH(errno, "pipe2 failure");
6581+
}
6582+
uint32_t rfd = (uint32_t)fds[0], wfd = (uint32_t)fds[1];
6583+
handle = DISPATCH_RUNLOOP_HANDLE_PACK(rfd, wfd);
65666584
#elif defined(_WIN32)
65676585
HANDLE hEvent;
65686586
hEvent = CreateEventW(NULL, /*bManualReset=*/FALSE,
@@ -6597,6 +6615,11 @@ _dispatch_runloop_queue_handle_dispose(dispatch_lane_t dq)
65976615
#elif defined(__linux__)
65986616
int rc = close(handle);
65996617
(void)dispatch_assume_zero(rc);
6618+
#elif defined(__unix__) && !defined(__linux__)
6619+
int rc = close(DISPATCH_RUNLOOP_HANDLE_WFD(handle));
6620+
(void)dispatch_assume_zero(rc);
6621+
rc = close(DISPATCH_RUNLOOP_HANDLE_RFD(handle));
6622+
(void)dispatch_assume_zero(rc);
66006623
#elif defined(_WIN32)
66016624
BOOL bSuccess;
66026625
bSuccess = CloseHandle(handle);
@@ -6633,6 +6656,13 @@ _dispatch_runloop_queue_class_poke(dispatch_lane_t dq)
66336656
result = eventfd_write(handle, 1);
66346657
} while (result == -1 && errno == EINTR);
66356658
(void)dispatch_assume_zero(result);
6659+
#elif defined(__unix__) && !defined(__linux__)
6660+
int wfd = DISPATCH_RUNLOOP_HANDLE_WFD(handle);
6661+
ssize_t result;
6662+
do {
6663+
result = write(wfd, "x", 1);
6664+
} while (result == -1 && errno == EINTR);
6665+
(void)dispatch_assume_zero(result - 1);
66366666
#elif defined(_WIN32)
66376667
BOOL bSuccess;
66386668
bSuccess = SetEvent(handle);
@@ -7311,6 +7341,13 @@ _gettid(void)
73117341
{
73127342
return (pid_t)pthread_getthreadid_np();
73137343
}
7344+
#elif defined(__OpenBSD__)
7345+
DISPATCH_ALWAYS_INLINE
7346+
static inline pid_t
7347+
_gettid(void)
7348+
{
7349+
return getthrid();
7350+
}
73147351
#elif defined(_WIN32)
73157352
DISPATCH_ALWAYS_INLINE
73167353
static inline DWORD

0 commit comments

Comments
 (0)