Skip to content

Commit 989c9dd

Browse files
dgrove-ossdas
authored andcommitted
Enable CF runloop support for linux
Signed-off-by: Daniel A. Steffen <[email protected]>
1 parent 3bbed1b commit 989c9dd

File tree

4 files changed

+156
-48
lines changed

4 files changed

+156
-48
lines changed

private/private.h

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -166,31 +166,43 @@ void _dispatch_prohibit_transition_to_multithreaded(bool prohibit);
166166
* SPI for CoreFoundation/Foundation ONLY
167167
*/
168168

169-
#define DISPATCH_COCOA_COMPAT (TARGET_OS_MAC || TARGET_OS_WIN32)
169+
#if TARGET_OS_MAC
170+
#define DISPATCH_COCOA_COMPAT 1
171+
#elif defined(__linux__)
172+
#define DISPATCH_COCOA_COMPAT 1
173+
#else
174+
#define DISPATCH_COCOA_COMPAT 0
175+
#endif
170176

171177
#if DISPATCH_COCOA_COMPAT
172178

179+
#define DISPATCH_CF_SPI_VERSION 20160712
180+
181+
#if TARGET_OS_MAC
182+
typedef mach_port_t dispatch_runloop_handle_t;
183+
#elif defined(__linux__)
184+
typedef int dispatch_runloop_handle_t;
185+
#else
186+
#error "runloop support not implemented on this platform"
187+
#endif
188+
173189
#if TARGET_OS_MAC
174190
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
175191
DISPATCH_EXPORT DISPATCH_CONST DISPATCH_WARN_RESULT DISPATCH_NOTHROW
176-
mach_port_t
192+
dispatch_runloop_handle_t
177193
_dispatch_get_main_queue_port_4CF(void);
194+
#endif
178195

179-
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
180-
DISPATCH_EXPORT DISPATCH_NOTHROW
181-
void
182-
_dispatch_main_queue_callback_4CF(mach_msg_header_t *_Null_unspecified msg);
183-
#elif TARGET_OS_WIN32
184-
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
196+
__OSX_AVAILABLE(10.12) __IOS_AVAILABLE(10.0)
197+
__TVOS_AVAILABLE(10.0) __WATCHOS_AVAILABLE(3.0)
185198
DISPATCH_EXPORT DISPATCH_NOTHROW
186-
HANDLE
199+
dispatch_runloop_handle_t
187200
_dispatch_get_main_queue_handle_4CF(void);
188201

189202
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
190203
DISPATCH_EXPORT DISPATCH_NOTHROW
191204
void
192-
_dispatch_main_queue_callback_4CF(void);
193-
#endif // TARGET_OS_WIN32
205+
_dispatch_main_queue_callback_4CF(void *_Null_unspecified msg);
194206

195207
__OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_7_0)
196208
DISPATCH_EXPORT DISPATCH_MALLOC DISPATCH_RETURNS_RETAINED DISPATCH_WARN_RESULT

src/internal.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,9 @@ DISPATCH_EXPORT DISPATCH_NOTHROW void dispatch_atfork_child(void);
251251
#include <sys/mman.h>
252252
#include <netinet/in.h>
253253
#endif
254+
#if defined(__linux__)
255+
#include <sys/eventfd.h>
256+
#endif
254257

255258
#ifdef __BLOCKS__
256259
#include <Block_private.h>

src/queue.c

Lines changed: 130 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,11 @@ static int _dispatch_pthread_sigmask(int how, sigset_t *set, sigset_t *oset);
7474
#endif
7575

7676
#if DISPATCH_COCOA_COMPAT
77-
static dispatch_once_t _dispatch_main_q_port_pred;
77+
static dispatch_once_t _dispatch_main_q_handle_pred;
7878
static void _dispatch_runloop_queue_poke(dispatch_queue_t dq,
7979
pthread_priority_t pp, dispatch_wakeup_flags_t flags);
80-
static void _dispatch_runloop_queue_port_init(void *ctxt);
81-
static void _dispatch_runloop_queue_port_dispose(dispatch_queue_t dq);
80+
static void _dispatch_runloop_queue_handle_init(void *ctxt);
81+
static void _dispatch_runloop_queue_handle_dispose(dispatch_queue_t dq);
8282
#endif
8383

8484
static void _dispatch_root_queues_init_once(void *context);
@@ -4058,6 +4058,49 @@ _dispatch_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp,
40584058
}
40594059
}
40604060

4061+
#if DISPATCH_COCOA_COMPAT
4062+
DISPATCH_ALWAYS_INLINE
4063+
static inline bool
4064+
_dispatch_runloop_handle_is_valid(dispatch_runloop_handle_t handle)
4065+
{
4066+
#if TARGET_OS_MAC
4067+
return MACH_PORT_VALID(handle);
4068+
#elif defined(__linux__)
4069+
return handle >= 0;
4070+
#else
4071+
#error "runloop support not implemented on this platform"
4072+
#endif
4073+
}
4074+
4075+
DISPATCH_ALWAYS_INLINE
4076+
static inline dispatch_runloop_handle_t
4077+
_dispatch_runloop_queue_get_handle(dispatch_queue_t dq)
4078+
{
4079+
#if TARGET_OS_MAC
4080+
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt);
4081+
#elif defined(__linux__)
4082+
// decode: 0 is a valid fd, so offset by 1 to distinguish from NULL
4083+
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt) - 1;
4084+
#else
4085+
#error "runloop support not implemented on this platform"
4086+
#endif
4087+
}
4088+
4089+
DISPATCH_ALWAYS_INLINE
4090+
static inline void
4091+
_dispatch_runloop_queue_set_handle(dispatch_queue_t dq, dispatch_runloop_handle_t handle)
4092+
{
4093+
#if TARGET_OS_MAC
4094+
dq->do_ctxt = (void *)(uintptr_t)handle;
4095+
#elif defined(__linux__)
4096+
// encode: 0 is a valid fd, so offset by 1 to distinguish from NULL
4097+
dq->do_ctxt = (void *)(uintptr_t)(handle + 1);
4098+
#else
4099+
#error "runloop support not implemented on this platform"
4100+
#endif
4101+
}
4102+
#endif // DISPATCH_COCOA_COMPAT
4103+
40614104
void
40624105
_dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp,
40634106
dispatch_wakeup_flags_t flags)
@@ -4084,8 +4127,6 @@ _dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp,
40844127
if (flags & DISPATCH_WAKEUP_CONSUME) {
40854128
return _dispatch_release_tailcall(dq);
40864129
}
4087-
#elif defined(__linux__)
4088-
LINUX_PORT_ERROR();
40894130
#else
40904131
return _dispatch_queue_wakeup(dq, pp, flags);
40914132
#endif
@@ -4122,10 +4163,13 @@ _dispatch_root_queue_wakeup(dispatch_queue_t dq,
41224163
static inline void
41234164
_dispatch_runloop_queue_class_poke(dispatch_queue_t dq)
41244165
{
4125-
mach_port_t mp = (mach_port_t)dq->do_ctxt;
4126-
if (!mp) {
4166+
dispatch_runloop_handle_t handle = _dispatch_runloop_queue_get_handle(dq);
4167+
if (!_dispatch_runloop_handle_is_valid(handle)) {
41274168
return;
41284169
}
4170+
4171+
#if TARGET_OS_MAC
4172+
mach_port_t mp = handle;
41294173
kern_return_t kr = _dispatch_send_wakeup_runloop_thread(mp, 0);
41304174
switch (kr) {
41314175
case MACH_SEND_TIMEOUT:
@@ -4136,6 +4180,15 @@ _dispatch_runloop_queue_class_poke(dispatch_queue_t dq)
41364180
(void)dispatch_assume_zero(kr);
41374181
break;
41384182
}
4183+
#elif defined(__linux__)
4184+
int result;
4185+
do {
4186+
result = eventfd_write(handle, 1);
4187+
} while (result == -1 && errno == EINTR);
4188+
(void)dispatch_assume_zero(result);
4189+
#else
4190+
#error "runloop support not implemented on this platform"
4191+
#endif
41394192
}
41404193

41414194
DISPATCH_NOINLINE
@@ -4150,8 +4203,8 @@ _dispatch_runloop_queue_poke(dispatch_queue_t dq,
41504203
// or in _dispatch_queue_cleanup2() for the main thread.
41514204

41524205
if (dq == &_dispatch_main_q) {
4153-
dispatch_once_f(&_dispatch_main_q_port_pred, dq,
4154-
_dispatch_runloop_queue_port_init);
4206+
dispatch_once_f(&_dispatch_main_q_handle_pred, dq,
4207+
_dispatch_runloop_queue_handle_init);
41554208
}
41564209
_dispatch_queue_override_priority(dq, /* inout */ &pp, /* inout */ &flags);
41574210
if (flags & DISPATCH_WAKEUP_OVERRIDING) {
@@ -4493,8 +4546,8 @@ _dispatch_main_queue_drain(void)
44934546
" from the wrong thread");
44944547
}
44954548

4496-
dispatch_once_f(&_dispatch_main_q_port_pred, dq,
4497-
_dispatch_runloop_queue_port_init);
4549+
dispatch_once_f(&_dispatch_main_q_handle_pred, dq,
4550+
_dispatch_runloop_queue_handle_init);
44984551

44994552
_dispatch_perfmon_start();
45004553
// <rdar://problem/23256682> hide the frame chaining when CFRunLoop
@@ -5544,7 +5597,7 @@ _dispatch_runloop_root_queue_create_4CF(const char *label, unsigned long flags)
55445597
_dispatch_queue_init(dq, DQF_THREAD_BOUND | DQF_CANNOT_TRYSYNC, 1, false);
55455598
dq->do_targetq = _dispatch_get_root_queue(_DISPATCH_QOS_CLASS_DEFAULT,true);
55465599
dq->dq_label = label ? label : "runloop-queue"; // no-copy contract
5547-
_dispatch_runloop_queue_port_init(dq);
5600+
_dispatch_runloop_queue_handle_init(dq);
55485601
_dispatch_queue_set_bound_thread(dq);
55495602
_dispatch_object_debug(dq, "%s", __func__);
55505603
return _dispatch_introspection_queue_create(dq);
@@ -5566,7 +5619,7 @@ _dispatch_runloop_queue_dispose(dispatch_queue_t dq)
55665619
{
55675620
_dispatch_object_debug(dq, "%s", __func__);
55685621
_dispatch_introspection_queue_dispose(dq);
5569-
_dispatch_runloop_queue_port_dispose(dq);
5622+
_dispatch_runloop_queue_handle_dispose(dq);
55705623
_dispatch_queue_destroy(dq);
55715624
}
55725625

@@ -5591,23 +5644,26 @@ _dispatch_runloop_root_queue_wakeup_4CF(dispatch_queue_t dq)
55915644
_dispatch_runloop_queue_wakeup(dq, 0, false);
55925645
}
55935646

5594-
mach_port_t
5647+
dispatch_runloop_handle_t
55955648
_dispatch_runloop_root_queue_get_port_4CF(dispatch_queue_t dq)
55965649
{
55975650
if (slowpath(dq->do_vtable != DISPATCH_VTABLE(queue_runloop))) {
55985651
DISPATCH_CLIENT_CRASH(dq->do_vtable, "Not a runloop queue");
55995652
}
5600-
return (mach_port_t)dq->do_ctxt;
5653+
return _dispatch_runloop_queue_get_handle(dq);
56015654
}
56025655

56035656
static void
5604-
_dispatch_runloop_queue_port_init(void *ctxt)
5657+
_dispatch_runloop_queue_handle_init(void *ctxt)
56055658
{
56065659
dispatch_queue_t dq = (dispatch_queue_t)ctxt;
5607-
mach_port_t mp;
5608-
kern_return_t kr;
5660+
dispatch_runloop_handle_t handle;
56095661

56105662
_dispatch_fork_becomes_unsafe();
5663+
5664+
#if TARGET_OS_MAC
5665+
mach_port_t mp;
5666+
kern_return_t kr;
56115667
kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
56125668
DISPATCH_VERIFY_MIG(kr);
56135669
(void)dispatch_assume_zero(kr);
@@ -5625,38 +5681,81 @@ _dispatch_runloop_queue_port_init(void *ctxt)
56255681
DISPATCH_VERIFY_MIG(kr);
56265682
(void)dispatch_assume_zero(kr);
56275683
}
5628-
dq->do_ctxt = (void*)(uintptr_t)mp;
5684+
handle = mp;
5685+
#elif defined(__linux__)
5686+
int fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
5687+
if (fd == -1) {
5688+
int err = errno;
5689+
switch (err) {
5690+
case EMFILE:
5691+
DISPATCH_CLIENT_CRASH(err, "eventfd() failure: "
5692+
"process is out of file descriptors");
5693+
break;
5694+
case ENFILE:
5695+
DISPATCH_CLIENT_CRASH(err, "eventfd() failure: "
5696+
"system is out of file descriptors");
5697+
break;
5698+
case ENOMEM:
5699+
DISPATCH_CLIENT_CRASH(err, "eventfd() failure: "
5700+
"kernel is out of memory");
5701+
break;
5702+
default:
5703+
DISPATCH_INTERNAL_CRASH(err, "eventfd() failure");
5704+
break;
5705+
}
5706+
}
5707+
handle = fd;
5708+
#else
5709+
#error "runloop support not implemented on this platform"
5710+
#endif
5711+
_dispatch_runloop_queue_set_handle(dq, handle);
56295712

56305713
_dispatch_program_is_probably_callback_driven = true;
56315714
}
56325715

56335716
static void
5634-
_dispatch_runloop_queue_port_dispose(dispatch_queue_t dq)
5717+
_dispatch_runloop_queue_handle_dispose(dispatch_queue_t dq)
56355718
{
5636-
mach_port_t mp = (mach_port_t)dq->do_ctxt;
5637-
if (!mp) {
5719+
dispatch_runloop_handle_t handle = _dispatch_runloop_queue_get_handle(dq);
5720+
if (!_dispatch_runloop_handle_is_valid(handle)) {
56385721
return;
56395722
}
56405723
dq->do_ctxt = NULL;
5724+
#if TARGET_OS_MAC
5725+
mach_port_t mp = handle;
56415726
kern_return_t kr = mach_port_deallocate(mach_task_self(), mp);
56425727
DISPATCH_VERIFY_MIG(kr);
56435728
(void)dispatch_assume_zero(kr);
56445729
kr = mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1);
56455730
DISPATCH_VERIFY_MIG(kr);
56465731
(void)dispatch_assume_zero(kr);
5732+
#elif defined(__linux__)
5733+
int rc = close(handle);
5734+
(void)dispatch_assume_zero(rc);
5735+
#else
5736+
#error "runloop support not implemented on this platform"
5737+
#endif
56475738
}
56485739

56495740
#pragma mark -
56505741
#pragma mark dispatch_main_queue
56515742

5652-
mach_port_t
5653-
_dispatch_get_main_queue_port_4CF(void)
5743+
dispatch_runloop_handle_t
5744+
_dispatch_get_main_queue_handle_4CF(void)
56545745
{
56555746
dispatch_queue_t dq = &_dispatch_main_q;
5656-
dispatch_once_f(&_dispatch_main_q_port_pred, dq,
5657-
_dispatch_runloop_queue_port_init);
5658-
return (mach_port_t)dq->do_ctxt;
5747+
dispatch_once_f(&_dispatch_main_q_handle_pred, dq,
5748+
_dispatch_runloop_queue_handle_init);
5749+
return _dispatch_runloop_queue_get_handle(dq);
5750+
}
5751+
5752+
#if TARGET_OS_MAC
5753+
dispatch_runloop_handle_t
5754+
_dispatch_get_main_queue_port_4CF(void)
5755+
{
5756+
return _dispatch_get_main_queue_handle_4CF();
56595757
}
5758+
#endif
56605759

56615760
static bool main_q_is_draining;
56625761

@@ -5670,7 +5769,7 @@ _dispatch_queue_set_mainq_drain_state(bool arg)
56705769
}
56715770

56725771
void
5673-
_dispatch_main_queue_callback_4CF(mach_msg_header_t *msg DISPATCH_UNUSED)
5772+
_dispatch_main_queue_callback_4CF(void *ignored DISPATCH_UNUSED)
56745773
{
56755774
if (main_q_is_draining) {
56765775
return;
@@ -5795,9 +5894,9 @@ _dispatch_queue_cleanup2(void)
57955894
#endif
57965895

57975896
#if DISPATCH_COCOA_COMPAT
5798-
dispatch_once_f(&_dispatch_main_q_port_pred, dq,
5799-
_dispatch_runloop_queue_port_init);
5800-
_dispatch_runloop_queue_port_dispose(dq);
5897+
dispatch_once_f(&_dispatch_main_q_handle_pred, dq,
5898+
_dispatch_runloop_queue_handle_init);
5899+
_dispatch_runloop_queue_handle_dispose(dq);
58015900
#endif
58025901
}
58035902

src/shims/linux_stubs.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,6 @@
3333
#undef LINUX_PORT_ERROR
3434
#define LINUX_PORT_ERROR() do { printf("LINUX_PORT_ERROR_CALLED %s:%d: %s\n",__FILE__,__LINE__,__FUNCTION__); abort(); } while (0)
3535

36-
unsigned long _dispatch_runloop_queue_probe(dispatch_queue_t dq) {
37-
LINUX_PORT_ERROR();
38-
}
39-
void _dispatch_runloop_queue_xref_dispose() { LINUX_PORT_ERROR(); }
40-
41-
void _dispatch_runloop_queue_dispose() { LINUX_PORT_ERROR(); }
4236

4337
/*
4438
* Stubbed out static data

0 commit comments

Comments
 (0)