Skip to content

Commit 2c0e5ee

Browse files
authored
Merge pull request swiftlang#101 from dgrove-oss/cf-runloop-hooks
Enable CF runloop support for linux
2 parents 78b9e82 + 0ad1c28 commit 2c0e5ee

File tree

4 files changed

+155
-53
lines changed

4 files changed

+155
-53
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: 129 additions & 36 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,48 @@ _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+
// decode: 0 is a valid fd, so offset by 1 to distinguish from NULL
4088+
return ((dispatch_runloop_handle_t)(uintptr_t)dq->do_ctxt) - 1;
4089+
#else
4090+
#error "runloop support not implemented on this platform"
4091+
#endif
4092+
}
4093+
4094+
DISPATCH_ALWAYS_INLINE
4095+
static inline void
4096+
_dispatch_runloop_queue_set_handle(dispatch_queue_t dq, dispatch_runloop_handle_t handle)
4097+
{
4098+
#if TARGET_OS_MAC
4099+
dq->do_ctxt = (void *)(uintptr_t)handle;
4100+
#elif defined(__linux__)
4101+
// encode: 0 is a valid fd, so offset by 1 to distinguish from NULL
4102+
dq->do_ctxt = (void *)(uintptr_t)(handle + 1);
4103+
#else
4104+
#error "runloop support not implemented on this platform"
4105+
#endif
4106+
}
4107+
40664108
void
40674109
_dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp,
40684110
dispatch_wakeup_flags_t flags)
@@ -4090,13 +4132,6 @@ _dispatch_runloop_queue_wakeup(dispatch_queue_t dq, pthread_priority_t pp,
40904132
return _dispatch_release_tailcall(dq);
40914133
}
40924134
}
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-
}
41004135
#endif
41014136

41024137
void
@@ -4130,10 +4165,13 @@ _dispatch_root_queue_wakeup(dispatch_queue_t dq,
41304165
static inline void
41314166
_dispatch_runloop_queue_class_poke(dispatch_queue_t dq)
41324167
{
4133-
mach_port_t mp = (mach_port_t)dq->do_ctxt;
4134-
if (!mp) {
4168+
dispatch_runloop_handle_t handle = _dispatch_runloop_queue_get_handle(dq);
4169+
if (!_dispatch_runloop_handle_is_valid(handle)) {
41354170
return;
41364171
}
4172+
4173+
#if TARGET_OS_MAC
4174+
mach_port_t mp = handle;
41374175
kern_return_t kr = _dispatch_send_wakeup_runloop_thread(mp, 0);
41384176
switch (kr) {
41394177
case MACH_SEND_TIMEOUT:
@@ -4144,6 +4182,15 @@ _dispatch_runloop_queue_class_poke(dispatch_queue_t dq)
41444182
(void)dispatch_assume_zero(kr);
41454183
break;
41464184
}
4185+
#elif defined(__linux__)
4186+
int result;
4187+
do {
4188+
result = eventfd_write(handle, 1);
4189+
} while (result == -1 && errno == EINTR);
4190+
(void)dispatch_assume_zero(result);
4191+
#else
4192+
#error "runloop support not implemented on this platform"
4193+
#endif
41474194
}
41484195

41494196
DISPATCH_NOINLINE
@@ -4158,8 +4205,8 @@ _dispatch_runloop_queue_poke(dispatch_queue_t dq,
41584205
// or in _dispatch_queue_cleanup2() for the main thread.
41594206

41604207
if (dq == &_dispatch_main_q) {
4161-
dispatch_once_f(&_dispatch_main_q_port_pred, dq,
4162-
_dispatch_runloop_queue_port_init);
4208+
dispatch_once_f(&_dispatch_main_q_handle_pred, dq,
4209+
_dispatch_runloop_queue_handle_init);
41634210
}
41644211
_dispatch_queue_override_priority(dq, /* inout */ &pp, /* inout */ &flags);
41654212
if (flags & DISPATCH_WAKEUP_OVERRIDING) {
@@ -4501,8 +4548,8 @@ _dispatch_main_queue_drain(void)
45014548
" from the wrong thread");
45024549
}
45034550

4504-
dispatch_once_f(&_dispatch_main_q_port_pred, dq,
4505-
_dispatch_runloop_queue_port_init);
4551+
dispatch_once_f(&_dispatch_main_q_handle_pred, dq,
4552+
_dispatch_runloop_queue_handle_init);
45064553

45074554
_dispatch_perfmon_start();
45084555
// <rdar://problem/23256682> hide the frame chaining when CFRunLoop
@@ -5547,7 +5594,7 @@ _dispatch_runloop_root_queue_create_4CF(const char *label, unsigned long flags)
55475594
_dispatch_queue_init(dq, DQF_THREAD_BOUND | DQF_CANNOT_TRYSYNC, 1, false);
55485595
dq->do_targetq = _dispatch_get_root_queue(_DISPATCH_QOS_CLASS_DEFAULT,true);
55495596
dq->dq_label = label ? label : "runloop-queue"; // no-copy contract
5550-
_dispatch_runloop_queue_port_init(dq);
5597+
_dispatch_runloop_queue_handle_init(dq);
55515598
_dispatch_queue_set_bound_thread(dq);
55525599
_dispatch_object_debug(dq, "%s", __func__);
55535600
return _dispatch_introspection_queue_create(dq);
@@ -5569,7 +5616,7 @@ _dispatch_runloop_queue_dispose(dispatch_queue_t dq)
55695616
{
55705617
_dispatch_object_debug(dq, "%s", __func__);
55715618
_dispatch_introspection_queue_dispose(dq);
5572-
_dispatch_runloop_queue_port_dispose(dq);
5619+
_dispatch_runloop_queue_handle_dispose(dq);
55735620
_dispatch_queue_destroy(dq);
55745621
}
55755622

@@ -5594,23 +5641,26 @@ _dispatch_runloop_root_queue_wakeup_4CF(dispatch_queue_t dq)
55945641
_dispatch_runloop_queue_wakeup(dq, 0, false);
55955642
}
55965643

5597-
mach_port_t
5644+
dispatch_runloop_handle_t
55985645
_dispatch_runloop_root_queue_get_port_4CF(dispatch_queue_t dq)
55995646
{
56005647
if (slowpath(dq->do_vtable != DISPATCH_VTABLE(queue_runloop))) {
56015648
DISPATCH_CLIENT_CRASH(dq->do_vtable, "Not a runloop queue");
56025649
}
5603-
return (mach_port_t)dq->do_ctxt;
5650+
return _dispatch_runloop_queue_get_handle(dq);
56045651
}
56055652

56065653
static void
5607-
_dispatch_runloop_queue_port_init(void *ctxt)
5654+
_dispatch_runloop_queue_handle_init(void *ctxt)
56085655
{
56095656
dispatch_queue_t dq = (dispatch_queue_t)ctxt;
5610-
mach_port_t mp;
5611-
kern_return_t kr;
5657+
dispatch_runloop_handle_t handle;
56125658

56135659
_dispatch_fork_becomes_unsafe();
5660+
5661+
#if TARGET_OS_MAC
5662+
mach_port_t mp;
5663+
kern_return_t kr;
56145664
kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &mp);
56155665
DISPATCH_VERIFY_MIG(kr);
56165666
(void)dispatch_assume_zero(kr);
@@ -5628,38 +5678,81 @@ _dispatch_runloop_queue_port_init(void *ctxt)
56285678
DISPATCH_VERIFY_MIG(kr);
56295679
(void)dispatch_assume_zero(kr);
56305680
}
5631-
dq->do_ctxt = (void*)(uintptr_t)mp;
5681+
handle = mp;
5682+
#elif defined(__linux__)
5683+
int fd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
5684+
if (fd == -1) {
5685+
int err = errno;
5686+
switch (err) {
5687+
case EMFILE:
5688+
DISPATCH_CLIENT_CRASH(err, "eventfd() failure: "
5689+
"process is out of file descriptors");
5690+
break;
5691+
case ENFILE:
5692+
DISPATCH_CLIENT_CRASH(err, "eventfd() failure: "
5693+
"system is out of file descriptors");
5694+
break;
5695+
case ENOMEM:
5696+
DISPATCH_CLIENT_CRASH(err, "eventfd() failure: "
5697+
"kernel is out of memory");
5698+
break;
5699+
default:
5700+
DISPATCH_INTERNAL_CRASH(err, "eventfd() failure");
5701+
break;
5702+
}
5703+
}
5704+
handle = fd;
5705+
#else
5706+
#error "runloop support not implemented on this platform"
5707+
#endif
5708+
_dispatch_runloop_queue_set_handle(dq, handle);
56325709

56335710
_dispatch_program_is_probably_callback_driven = true;
56345711
}
56355712

56365713
static void
5637-
_dispatch_runloop_queue_port_dispose(dispatch_queue_t dq)
5714+
_dispatch_runloop_queue_handle_dispose(dispatch_queue_t dq)
56385715
{
5639-
mach_port_t mp = (mach_port_t)dq->do_ctxt;
5640-
if (!mp) {
5716+
dispatch_runloop_handle_t handle = _dispatch_runloop_queue_get_handle(dq);
5717+
if (!_dispatch_runloop_handle_is_valid(handle)) {
56415718
return;
56425719
}
56435720
dq->do_ctxt = NULL;
5721+
#if TARGET_OS_MAC
5722+
mach_port_t mp = handle;
56445723
kern_return_t kr = mach_port_deallocate(mach_task_self(), mp);
56455724
DISPATCH_VERIFY_MIG(kr);
56465725
(void)dispatch_assume_zero(kr);
56475726
kr = mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1);
56485727
DISPATCH_VERIFY_MIG(kr);
56495728
(void)dispatch_assume_zero(kr);
5729+
#elif defined(__linux__)
5730+
int rc = close(handle);
5731+
(void)dispatch_assume_zero(rc);
5732+
#else
5733+
#error "runloop support not implemented on this platform"
5734+
#endif
56505735
}
56515736

56525737
#pragma mark -
56535738
#pragma mark dispatch_main_queue
56545739

5655-
mach_port_t
5656-
_dispatch_get_main_queue_port_4CF(void)
5740+
dispatch_runloop_handle_t
5741+
_dispatch_get_main_queue_handle_4CF(void)
56575742
{
56585743
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;
5744+
dispatch_once_f(&_dispatch_main_q_handle_pred, dq,
5745+
_dispatch_runloop_queue_handle_init);
5746+
return _dispatch_runloop_queue_get_handle(dq);
5747+
}
5748+
5749+
#if TARGET_OS_MAC
5750+
dispatch_runloop_handle_t
5751+
_dispatch_get_main_queue_port_4CF(void)
5752+
{
5753+
return _dispatch_get_main_queue_handle_4CF();
56625754
}
5755+
#endif
56635756

56645757
static bool main_q_is_draining;
56655758

@@ -5673,7 +5766,7 @@ _dispatch_queue_set_mainq_drain_state(bool arg)
56735766
}
56745767

56755768
void
5676-
_dispatch_main_queue_callback_4CF(mach_msg_header_t *msg DISPATCH_UNUSED)
5769+
_dispatch_main_queue_callback_4CF(void *ignored DISPATCH_UNUSED)
56775770
{
56785771
if (main_q_is_draining) {
56795772
return;
@@ -5798,9 +5891,9 @@ _dispatch_queue_cleanup2(void)
57985891
#endif
57995892

58005893
#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);
5894+
dispatch_once_f(&_dispatch_main_q_handle_pred, dq,
5895+
_dispatch_runloop_queue_handle_init);
5896+
_dispatch_runloop_queue_handle_dispose(dq);
58045897
#endif
58055898
}
58065899

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)