Skip to content

Commit 2e73a01

Browse files
committed
Enable CF runloop support for linux
1 parent 2dbf83c commit 2e73a01

File tree

4 files changed

+128
-50
lines changed

4 files changed

+128
-50
lines changed

private/private.h

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,31 +166,45 @@ 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 || TARGET_OS_WIN32)
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+
#if TARGET_OS_MAC
180+
typedef mach_port_t dispatch_runloop_handle_t;
181+
#elif defined(__linux__)
182+
typedef int dispatch_runloop_handle_t;
183+
#else
184+
#error "runloop support not implemented on this platform"
185+
#endif
186+
173187
#if TARGET_OS_MAC
174188
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
175189
DISPATCH_EXPORT DISPATCH_CONST DISPATCH_WARN_RESULT DISPATCH_NOTHROW
176-
mach_port_t
190+
dispatch_runloop_handle_t
177191
_dispatch_get_main_queue_port_4CF(void);
178192

179193
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
180194
DISPATCH_EXPORT DISPATCH_NOTHROW
181195
void
182196
_dispatch_main_queue_callback_4CF(mach_msg_header_t *_Null_unspecified msg);
183-
#elif TARGET_OS_WIN32
197+
#else
184198
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
185199
DISPATCH_EXPORT DISPATCH_NOTHROW
186-
HANDLE
200+
dispatch_runloop_handle_t
187201
_dispatch_get_main_queue_handle_4CF(void);
188202

189203
__OSX_AVAILABLE_STARTING(__MAC_10_6,__IPHONE_4_0)
190204
DISPATCH_EXPORT DISPATCH_NOTHROW
191205
void
192206
_dispatch_main_queue_callback_4CF(void);
193-
#endif // TARGET_OS_WIN32
207+
#endif
194208

195209
__OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_7_0)
196210
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: 106 additions & 39 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);
@@ -4063,6 +4063,46 @@ _dispatch_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp,
40634063
}
40644064

40654065
#if DISPATCH_COCOA_COMPAT
4066+
4067+
DISPATCH_ALWAYS_INLINE
4068+
static inline bool
4069+
_dispatch_runloop_handle_is_valid(dispatch_runloop_handle_t handle)
4070+
{
4071+
#if TARGET_OS_MAC
4072+
return MACH_PORT_VALID(handle);
4073+
#elif defined(__linux__)
4074+
return handle >= 0;
4075+
#else
4076+
#error "runloop support not implemented on this platform"
4077+
#endif
4078+
}
4079+
4080+
DISPATCH_ALWAYS_INLINE
4081+
static inline dispatch_runloop_handle_t
4082+
_dispatch_runloop_queue_get_handle(dispatch_queue_t dq)
4083+
{
4084+
#if TARGET_OS_MAC
4085+
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt);
4086+
#elif defined(__linux__)
4087+
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt) - 1;
4088+
#else
4089+
#error "runloop support not implemented on this platform"
4090+
#endif
4091+
}
4092+
4093+
DISPATCH_ALWAYS_INLINE
4094+
static inline void
4095+
_dispatch_runloop_queue_set_handle(dispatch_queue_t dq, dispatch_runloop_handle_t handle)
4096+
{
4097+
#if TARGET_OS_MAC
4098+
dq->do_ctxt = (void *)(uintptr_t)handle;
4099+
#elif defined(__linux__)
4100+
dq->do_ctxt = (void *)(uintptr_t)(handle + 1);
4101+
#else
4102+
#error "runloop support not implemented on this platform"
4103+
#endif
4104+
}
4105+
40664106
void
40674107
_dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp,
40684108
dispatch_wakeup_flags_t flags)
@@ -4090,13 +4130,6 @@ _dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp,
40904130
return _dispatch_release_tailcall(dq);
40914131
}
40924132
}
4093-
#else
4094-
void
4095-
_dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp,
4096-
dispatch_wakeup_flags_t flags)
4097-
{
4098-
LINUX_PORT_ERROR();
4099-
}
41004133
#endif
41014134

41024135
void
@@ -4130,11 +4163,13 @@ _dispatch_root_queue_wakeup(dispatch_queue_t dq,
41304163
static inline void
41314164
_dispatch_runloop_queue_class_poke(dispatch_queue_t dq)
41324165
{
4133-
mach_port_t mp = (mach_port_t)dq->do_ctxt;
4134-
if (!mp) {
4166+
dispatch_runloop_handle_t handle = _dispatch_runloop_queue_get_handle(dq);
4167+
if (!_dispatch_runloop_handle_is_valid(handle)) {
41354168
return;
41364169
}
4137-
kern_return_t kr = _dispatch_send_wakeup_runloop_thread(mp, 0);
4170+
4171+
#if TARGET_OS_MAC
4172+
kern_return_t kr = _dispatch_send_wakeup_runloop_thread(handle, 0);
41384173
switch (kr) {
41394174
case MACH_SEND_TIMEOUT:
41404175
case MACH_SEND_TIMED_OUT:
@@ -4144,6 +4179,15 @@ _dispatch_runloop_queue_class_poke(dispatch_queue_t dq)
41444179
(void)dispatch_assume_zero(kr);
41454180
break;
41464181
}
4182+
#elif defined(__linux__)
4183+
int result;
4184+
do {
4185+
result = eventfd_write(handle, 1);
4186+
} while (result == -1 && errno == EINTR);
4187+
(void)dispatch_assume_zero(result);
4188+
#else
4189+
#error "runloop support not implemented on this platform"
4190+
#endif
41474191
}
41484192

41494193
DISPATCH_NOINLINE
@@ -4158,8 +4202,8 @@ _dispatch_runloop_queue_poke(dispatch_queue_t dq,
41584202
// or in _dispatch_queue_cleanup2() for the main thread.
41594203

41604204
if (dq == &_dispatch_main_q) {
4161-
dispatch_once_f(&_dispatch_main_q_port_pred, dq,
4162-
_dispatch_runloop_queue_port_init);
4205+
dispatch_once_f(&_dispatch_main_q_handle_pred, dq,
4206+
_dispatch_runloop_queue_handle_init);
41634207
}
41644208
_dispatch_queue_override_priority(dq, /* inout */ &pp, /* inout */ &flags);
41654209
if (flags & DISPATCH_WAKEUP_OVERRIDING) {
@@ -4501,8 +4545,8 @@ _dispatch_main_queue_drain(void)
45014545
" from the wrong thread");
45024546
}
45034547

4504-
dispatch_once_f(&_dispatch_main_q_port_pred, dq,
4505-
_dispatch_runloop_queue_port_init);
4548+
dispatch_once_f(&_dispatch_main_q_handle_pred, dq,
4549+
_dispatch_runloop_queue_handle_init);
45064550

45074551
_dispatch_perfmon_start();
45084552
// <rdar://problem/23256682> hide the frame chaining when CFRunLoop
@@ -5547,7 +5591,7 @@ _dispatch_runloop_root_queue_create_4CF(const char *label, unsigned long flags)
55475591
_dispatch_queue_init(dq, DQF_THREAD_BOUND | DQF_CANNOT_TRYSYNC, 1, false);
55485592
dq->do_targetq = _dispatch_get_root_queue(_DISPATCH_QOS_CLASS_DEFAULT,true);
55495593
dq->dq_label = label ? label : "runloop-queue"; // no-copy contract
5550-
_dispatch_runloop_queue_port_init(dq);
5594+
_dispatch_runloop_queue_handle_init(dq);
55515595
_dispatch_queue_set_bound_thread(dq);
55525596
_dispatch_object_debug(dq, "%s", __func__);
55535597
return _dispatch_introspection_queue_create(dq);
@@ -5569,7 +5613,7 @@ _dispatch_runloop_queue_dispose(dispatch_queue_t dq)
55695613
{
55705614
_dispatch_object_debug(dq, "%s", __func__);
55715615
_dispatch_introspection_queue_dispose(dq);
5572-
_dispatch_runloop_queue_port_dispose(dq);
5616+
_dispatch_runloop_queue_handle_dispose(dq);
55735617
_dispatch_queue_destroy(dq);
55745618
}
55755619

@@ -5594,71 +5638,90 @@ _dispatch_runloop_root_queue_wakeup_4CF(dispatch_queue_t dq)
55945638
_dispatch_runloop_queue_wakeup(dq, 0, false);
55955639
}
55965640

5597-
mach_port_t
5641+
dispatch_runloop_handle_t
55985642
_dispatch_runloop_root_queue_get_port_4CF(dispatch_queue_t dq)
55995643
{
56005644
if (slowpath(dq->do_vtable != DISPATCH_VTABLE(queue_runloop))) {
56015645
DISPATCH_CLIENT_CRASH(dq->do_vtable, "Not a runloop queue");
56025646
}
5603-
return (mach_port_t)dq->do_ctxt;
5647+
return _dispatch_runloop_queue_get_handle(dq);
56045648
}
56055649

56065650
static void
5607-
_dispatch_runloop_queue_port_init(void *ctxt)
5651+
_dispatch_runloop_queue_handle_init(void *ctxt)
56085652
{
56095653
dispatch_queue_t dq = (dispatch_queue_t)ctxt;
5610-
mach_port_t mp;
5611-
kern_return_t kr;
5654+
dispatch_runloop_handle_t handle;
56125655

56135656
_dispatch_fork_becomes_unsafe();
5614-
kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
5657+
5658+
#if TARGET_OS_MAC
5659+
kern_return_t kr;
5660+
kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &handle);
56155661
DISPATCH_VERIFY_MIG(kr);
56165662
(void)dispatch_assume_zero(kr);
5617-
kr = mach_port_insert_right(mach_task_self(), mp, mp,
5663+
kr = mach_port_insert_right(mach_task_self(), handle, handle,
56185664
MACH_MSG_TYPE_MAKE_SEND);
56195665
DISPATCH_VERIFY_MIG(kr);
56205666
(void)dispatch_assume_zero(kr);
56215667
if (dq != &_dispatch_main_q) {
56225668
struct mach_port_limits limits = {
56235669
.mpl_qlimit = 1,
56245670
};
5625-
kr = mach_port_set_attributes(mach_task_self(), mp,
5671+
kr = mach_port_set_attributes(mach_task_self(), handle,
56265672
MACH_PORT_LIMITS_INFO, (mach_port_info_t)&limits,
56275673
sizeof(limits));
56285674
DISPATCH_VERIFY_MIG(kr);
56295675
(void)dispatch_assume_zero(kr);
56305676
}
5631-
dq->do_ctxt = (void*)(uintptr_t)mp;
5677+
#elif defined(__linux__)
5678+
handle = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
5679+
#else
5680+
#error "runloop support not implemented on this platform"
5681+
#endif
5682+
(void)dispatch_assume(_dispatch_runloop_handle_is_valid(handle));
5683+
_dispatch_runloop_queue_set_handle(dq, handle);
56325684

56335685
_dispatch_program_is_probably_callback_driven = true;
56345686
}
56355687

56365688
static void
5637-
_dispatch_runloop_queue_port_dispose(dispatch_queue_t dq)
5689+
_dispatch_runloop_queue_handle_dispose(dispatch_queue_t dq)
56385690
{
5639-
mach_port_t mp = (mach_port_t)dq->do_ctxt;
5640-
if (!mp) {
5691+
dispatch_runloop_handle_t handle = _dispatch_runloop_queue_get_handle(dq);
5692+
if (!_dispatch_runloop_handle_is_valid(handle)) {
56415693
return;
56425694
}
56435695
dq->do_ctxt = NULL;
5644-
kern_return_t kr = mach_port_deallocate(mach_task_self(), mp);
5696+
#if TARGET_OS_MAC
5697+
kern_return_t kr = mach_port_deallocate(mach_task_self(), hand);
56455698
DISPATCH_VERIFY_MIG(kr);
56465699
(void)dispatch_assume_zero(kr);
56475700
kr = mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1);
56485701
DISPATCH_VERIFY_MIG(kr);
56495702
(void)dispatch_assume_zero(kr);
5703+
#elif defined(__linux__)
5704+
int rc = close(handle);
5705+
(void)dispatch_assume_zero(rc);
5706+
#else
5707+
#error "runloop support not implemented on this platform"
5708+
#endif
56505709
}
56515710

56525711
#pragma mark -
56535712
#pragma mark dispatch_main_queue
56545713

5655-
mach_port_t
5714+
dispatch_runloop_handle_t
5715+
#if TARGET_OS_MAC
56565716
_dispatch_get_main_queue_port_4CF(void)
5717+
#else
5718+
_dispatch_get_main_queue_handle_4CF(void)
5719+
#endif
56575720
{
56585721
dispatch_queue_t dq = &_dispatch_main_q;
5659-
dispatch_once_f(&_dispatch_main_q_port_pred, dq,
5660-
_dispatch_runloop_queue_port_init);
5661-
return (mach_port_t)dq->do_ctxt;
5722+
dispatch_once_f(&_dispatch_main_q_handle_pred, dq,
5723+
_dispatch_runloop_queue_handle_init);
5724+
return _dispatch_runloop_queue_get_handle(dq);
56625725
}
56635726

56645727
static bool main_q_is_draining;
@@ -5673,7 +5736,11 @@ _dispatch_queue_set_mainq_drain_state(bool arg)
56735736
}
56745737

56755738
void
5739+
#if TARGET_OS_MAC
56765740
_dispatch_main_queue_callback_4CF(mach_msg_header_t *msg DISPATCH_UNUSED)
5741+
#else
5742+
_dispatch_main_queue_callback_4CF(void)
5743+
#endif
56775744
{
56785745
if (main_q_is_draining) {
56795746
return;
@@ -5798,9 +5865,9 @@ _dispatch_queue_cleanup2(void)
57985865
#endif
57995866

58005867
#if DISPATCH_COCOA_COMPAT
5801-
dispatch_once_f(&_dispatch_main_q_port_pred, dq,
5802-
_dispatch_runloop_queue_port_init);
5803-
_dispatch_runloop_queue_port_dispose(dq);
5868+
dispatch_once_f(&_dispatch_main_q_handle_pred, dq,
5869+
_dispatch_runloop_queue_handle_init);
5870+
_dispatch_runloop_queue_handle_dispose(dq);
58045871
#endif
58055872
}
58065873

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)