Skip to content

Commit 9b80070

Browse files
committed
Merge pull request #72 from seabaylea/cfrunloop
Add support for CFRunLoop integration APIs
2 parents 65370c9 + 9f58d82 commit 9b80070

File tree

6 files changed

+174
-10
lines changed

6 files changed

+174
-10
lines changed

private/queue_private.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,53 @@ dispatch_async_enforce_qos_class_f(dispatch_queue_t queue,
369369
void *context,
370370
dispatch_function_t work);
371371

372+
#if DISPATCH_ENABLE_RUNLOOP_SUPPORT
373+
/*!
374+
* @functiongroup Runloop integration APIs
375+
* APIs to provide integration of the main queue into run loop implementations
376+
* such as Swift Foundation.
377+
*/
378+
379+
/*!
380+
* @function dispatch_get_main_queue_eventfd_4CF
381+
*
382+
* @abstract
383+
* Returns a file descriptor representing an eventfd object that provides a
384+
* wait/notify mechanism to signal pending tasks on the main queue.
385+
*
386+
* @discussion
387+
* The file descriptor can be monitored with epoll() and becomes readable when
388+
* there are pending tasks on the queue. Once readable you should call
389+
* eventfd_read() to acknowledge the notification and then call
390+
* dispatch_main_queue_drain_np() to perform the pending tasks on the queue.
391+
*
392+
* @availability
393+
* Linux only.
394+
*
395+
* @result
396+
* A file descriptor representing the eventfd object.
397+
*/
398+
DISPATCH_EXPORT DISPATCH_WARN_RESULT DISPATCH_NOTHROW
399+
int
400+
dispatch_get_main_queue_eventfd_4CF();
401+
402+
/*!
403+
* @function dispatch_main_queue_drain_4CF
404+
*
405+
* @abstract
406+
* Executes pending tasks enqueued to the main queue.
407+
*
408+
* @availability
409+
* Linux only.
410+
*
411+
* @discussion
412+
* The run loop should invoke this function to execute pending tasks on the
413+
* main queue.
414+
*/
415+
DISPATCH_EXPORT DISPATCH_NOTHROW
416+
void
417+
dispatch_main_queue_drain_4CF();
418+
#endif
372419

373420
__END_DECLS
374421

src/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ libdispatch_la_SOURCES= \
4949
shims/perfmon.h \
5050
shims/time.h \
5151
shims/tsd.h \
52+
shims/pthread_main_np.h \
5253
shims/yield.h
5354

5455
EXTRA_libdispatch_la_SOURCES=

src/internal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@
3737
#include <TargetConditionals.h>
3838
#endif
3939

40+
#ifdef __linux__
41+
#include <sys/eventfd.h>
42+
#define DISPATCH_LINUX_COMPAT 1
43+
#endif
44+
45+
#define DISPATCH_ENABLE_RUNLOOP_SUPPORT (DISPATCH_LINUX_COMPAT || DISPATCH_COCOA_COMPAT)
4046

4147
#if !defined(DISPATCH_MACH_SPI) && TARGET_OS_MAC
4248
#define DISPATCH_MACH_SPI 1

src/queue.c

Lines changed: 78 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,18 @@ static void *_dispatch_worker_thread(void *context);
7575
static int _dispatch_pthread_sigmask(int how, sigset_t *set, sigset_t *oset);
7676
#endif
7777

78+
#if DISPATCH_ENABLE_RUNLOOP_SUPPORT
79+
static dispatch_queue_t _dispatch_main_queue_wakeup(void);
7880
#if DISPATCH_COCOA_COMPAT
7981
static dispatch_once_t _dispatch_main_q_port_pred;
80-
static dispatch_queue_t _dispatch_main_queue_wakeup(void);
8182
unsigned long _dispatch_runloop_queue_wakeup(dispatch_queue_t dq);
8283
static void _dispatch_runloop_queue_port_init(void *ctxt);
8384
static void _dispatch_runloop_queue_port_dispose(dispatch_queue_t dq);
85+
#elif DISPATCH_LINUX_COMPAT
86+
static dispatch_once_t _dispatch_main_q_eventfd_pred;
87+
static void _dispatch_main_q_eventfd_init(void *ctxt);
88+
static int main_q_eventfd = -1;
89+
#endif
8490
#endif
8591

8692
static void _dispatch_root_queues_init(void *context);
@@ -3468,6 +3474,7 @@ _dispatch_wakeup(dispatch_object_t dou)
34683474
// probe does
34693475
}
34703476

3477+
#if DISPATCH_ENABLE_RUNLOOP_SUPPORT
34713478
#if DISPATCH_COCOA_COMPAT
34723479
static inline void
34733480
_dispatch_runloop_queue_wakeup_thread(dispatch_queue_t dq)
@@ -3495,6 +3502,7 @@ _dispatch_runloop_queue_wakeup(dispatch_queue_t dq)
34953502
_dispatch_runloop_queue_wakeup_thread(dq);
34963503
return false;
34973504
}
3505+
#endif
34983506

34993507
DISPATCH_NOINLINE
35003508
static dispatch_queue_t
@@ -3504,9 +3512,21 @@ _dispatch_main_queue_wakeup(void)
35043512
if (!dq->dq_is_thread_bound) {
35053513
return NULL;
35063514
}
3515+
#if DISPATCH_COCOA_COMPAT
35073516
dispatch_once_f(&_dispatch_main_q_port_pred, dq,
35083517
_dispatch_runloop_queue_port_init);
35093518
_dispatch_runloop_queue_wakeup_thread(dq);
3519+
#elif DISPATCH_LINUX_COMPAT
3520+
dispatch_once_f(&_dispatch_main_q_eventfd_pred, dq,
3521+
_dispatch_main_q_eventfd_init);
3522+
if (main_q_eventfd != -1) {
3523+
int result;
3524+
do {
3525+
result = eventfd_write(main_q_eventfd, 1);
3526+
} while (result == -1 && errno == EINTR);
3527+
(void)dispatch_assume_zero(result);
3528+
}
3529+
#endif
35103530
return NULL;
35113531
}
35123532
#endif
@@ -3754,7 +3774,7 @@ _dispatch_queue_drain(dispatch_object_t dou)
37543774
return sema;
37553775
}
37563776

3757-
#if DISPATCH_COCOA_COMPAT
3777+
#if DISPATCH_ENABLE_RUNLOOP_SUPPORT
37583778
static void
37593779
_dispatch_main_queue_drain(void)
37603780
{
@@ -3805,6 +3825,7 @@ _dispatch_main_queue_drain(void)
38053825
_dispatch_force_cache_cleanup();
38063826
}
38073827

3828+
#if DISPATCH_COCOA_COMPAT
38083829
static bool
38093830
_dispatch_runloop_queue_drain_one(dispatch_queue_t dq)
38103831
{
@@ -3833,6 +3854,7 @@ _dispatch_runloop_queue_drain_one(dispatch_queue_t dq)
38333854
return next_dc;
38343855
}
38353856
#endif
3857+
#endif
38363858

38373859
DISPATCH_ALWAYS_INLINE_NDEBUG
38383860
static inline _dispatch_thread_semaphore_t
@@ -4487,10 +4509,24 @@ _dispatch_runloop_queue_port_dispose(dispatch_queue_t dq)
44874509
DISPATCH_VERIFY_MIG(kr);
44884510
(void)dispatch_assume_zero(kr);
44894511
}
4512+
#endif
44904513

44914514
#pragma mark -
44924515
#pragma mark dispatch_main_queue
44934516

4517+
#if DISPATCH_ENABLE_RUNLOOP_SUPPORT
4518+
static bool main_q_is_draining;
4519+
4520+
// 6618342 Contact the team that owns the Instrument DTrace probe before
4521+
// renaming this symbol
4522+
DISPATCH_NOINLINE
4523+
static void
4524+
_dispatch_queue_set_mainq_drain_state(bool arg)
4525+
{
4526+
main_q_is_draining = arg;
4527+
}
4528+
4529+
#if DISPATCH_COCOA_COMPAT
44944530
mach_port_t
44954531
_dispatch_get_main_queue_port_4CF(void)
44964532
{
@@ -4500,20 +4536,34 @@ _dispatch_get_main_queue_port_4CF(void)
45004536
return (mach_port_t)dq->do_ctxt;
45014537
}
45024538

4503-
static bool main_q_is_draining;
4539+
void
4540+
_dispatch_main_queue_callback_4CF(mach_msg_header_t *msg DISPATCH_UNUSED)
4541+
{
4542+
if (main_q_is_draining) {
4543+
return;
4544+
}
4545+
_dispatch_queue_set_mainq_drain_state(true);
4546+
_dispatch_main_queue_drain();
4547+
_dispatch_queue_set_mainq_drain_state(false);
4548+
}
45044549

4505-
// 6618342 Contact the team that owns the Instrument DTrace probe before
4506-
// renaming this symbol
4507-
DISPATCH_NOINLINE
4508-
static void
4509-
_dispatch_queue_set_mainq_drain_state(bool arg)
4550+
#elif DISPATCH_LINUX_COMPAT
4551+
int
4552+
dispatch_get_main_queue_eventfd_4CF()
45104553
{
4511-
main_q_is_draining = arg;
4554+
dispatch_once_f(&_dispatch_main_q_eventfd_pred, NULL,
4555+
_dispatch_main_q_eventfd_init);
4556+
return main_q_eventfd;
45124557
}
45134558

45144559
void
4515-
_dispatch_main_queue_callback_4CF(mach_msg_header_t *msg DISPATCH_UNUSED)
4560+
dispatch_main_queue_drain_4CF()
45164561
{
4562+
if (!pthread_main_np()) {
4563+
DISPATCH_CLIENT_CRASH("dispatch_main_queue_drain_np() must be called on "
4564+
"the main thread");
4565+
}
4566+
45174567
if (main_q_is_draining) {
45184568
return;
45194569
}
@@ -4522,6 +4572,15 @@ _dispatch_main_queue_callback_4CF(mach_msg_header_t *msg DISPATCH_UNUSED)
45224572
_dispatch_queue_set_mainq_drain_state(false);
45234573
}
45244574

4575+
static
4576+
void _dispatch_main_q_eventfd_init(void *ctxt DISPATCH_UNUSED)
4577+
{
4578+
_dispatch_safe_fork = false;
4579+
main_q_eventfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
4580+
(void)dispatch_assume(main_q_eventfd != -1);
4581+
_dispatch_program_is_probably_callback_driven = true;
4582+
}
4583+
#endif
45254584
#endif
45264585

45274586
void
@@ -4587,6 +4646,15 @@ _dispatch_queue_cleanup2(void)
45874646
dispatch_once_f(&_dispatch_main_q_port_pred, dq,
45884647
_dispatch_runloop_queue_port_init);
45894648
_dispatch_runloop_queue_port_dispose(dq);
4649+
#elif DISPATCH_LINUX_COMPAT
4650+
dispatch_once_f(&_dispatch_main_q_eventfd_pred, NULL,
4651+
_dispatch_main_q_eventfd_init);
4652+
int fd = main_q_eventfd;
4653+
main_q_eventfd = -1;
4654+
4655+
if (fd != -1) {
4656+
close(fd);
4657+
}
45904658
#endif
45914659
}
45924660

src/shims.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ void __builtin_trap(void);
174174
#include "shims/getprogname.h"
175175
#include "shims/time.h"
176176

177+
#include "shims/pthread_main_np.h"
178+
177179
#ifdef __APPLE__
178180
// Clear the stack before calling long-running thread-handler functions that
179181
// never return (and don't take arguments), to facilitate leak detection and

src/shims/pthread_main_np.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* @APPLE_APACHE_LICENSE_HEADER_START@
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* @APPLE_APACHE_LICENSE_HEADER_END@
17+
*/
18+
19+
#ifndef __DISPATCH_SHIMS_PTHREAD_MAIN_NP__
20+
#define __DISPATCH_SHIMS_PTHREAD_MAIN_NP__
21+
22+
#if !HAVE_PTHREAD_MAIN_NP
23+
24+
#if __linux__
25+
#include <unistd.h>
26+
#include <sys/syscall.h>
27+
#include <sys/types.h>
28+
#endif
29+
30+
static inline int
31+
pthread_main_np()
32+
{
33+
#if __linux__
34+
return syscall(SYS_gettid) == getpid() ? 1 : 0;
35+
#else
36+
#error "No suported way to determine if the current thread is the main thread."
37+
#endif
38+
}
39+
#endif /* !HAVE_PTHREAD_MAIN_NP */
40+
#endif /* __DISPATCH_SHIMS_PTHREAD_MAIN_NP__ */

0 commit comments

Comments
 (0)