Skip to content

Commit 1df729d

Browse files
committed
Merge libdispatch-913.1.4
Signed-off-by: Daniel A. Steffen <[email protected]>
1 parent 54651ca commit 1df729d

29 files changed

+1017
-201
lines changed

dispatch/queue.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ dispatch_sync_f(dispatch_queue_t queue,
223223
* @abstract
224224
* Constant to pass to dispatch_apply() or dispatch_apply_f() to request that
225225
* the system automatically use worker threads that match the configuration of
226-
* the current thread most closely.
226+
* the current thread as closely as possible.
227227
*
228228
* @discussion
229229
* When submitting a block for parallel invocation, passing this constant as the

libdispatch.xcodeproj/project.pbxproj

+4
Original file line numberDiff line numberDiff line change
@@ -741,10 +741,12 @@
741741
96DF70BD0F38FE3C0074BD99 /* once.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; lineEnding = 0; path = once.c; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.c; };
742742
B63B793F1E8F004F0060C1E1 /* dispatch_no_blocks.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dispatch_no_blocks.c; sourceTree = "<group>"; };
743743
B68330BC1EBCF6080003E71C /* dispatch_wl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dispatch_wl.c; sourceTree = "<group>"; };
744+
B69878521F06F8790088F94F /* dispatch_signals.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dispatch_signals.c; sourceTree = "<group>"; };
744745
B6AC73FD1EB10973009FB2F2 /* perf_thread_request.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = perf_thread_request.c; sourceTree = "<group>"; };
745746
B6AE9A4A1D7F53B300AC007F /* dispatch_queue_create.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dispatch_queue_create.c; sourceTree = "<group>"; };
746747
B6AE9A561D7F53C100AC007F /* perf_async_bench.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = perf_async_bench.m; sourceTree = "<group>"; };
747748
B6AE9A581D7F53CB00AC007F /* perf_bench.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = perf_bench.m; sourceTree = "<group>"; };
749+
B6FA01801F0AD522004479BF /* dispatch_pthread_root_queue.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dispatch_pthread_root_queue.c; sourceTree = "<group>"; };
748750
C00B0E0A1C5AEBBE000330B3 /* libdispatch_dyld_stub.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdispatch_dyld_stub.a; sourceTree = BUILT_PRODUCTS_DIR; };
749751
C00B0E121C5AEBF7000330B3 /* libdispatch-dyld-stub.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = "libdispatch-dyld-stub.xcconfig"; sourceTree = "<group>"; };
750752
C01866BD1C5973210040FC07 /* libdispatch.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdispatch.a; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1013,6 +1015,7 @@
10131015
6E67D9151C1768B300FC98AC /* dispatch_pingpong.c */,
10141016
6E326B441C239B61002A6505 /* dispatch_priority.c */,
10151017
6E326AB51C225477002A6505 /* dispatch_proc.c */,
1018+
B6FA01801F0AD522004479BF /* dispatch_pthread_root_queue.c */,
10161019
6E326AB31C224870002A6505 /* dispatch_qos.c */,
10171020
B6AE9A4A1D7F53B300AC007F /* dispatch_queue_create.c */,
10181021
6E67D9111C17669C00FC98AC /* dispatch_queue_finalizer.c */,
@@ -1022,6 +1025,7 @@
10221025
6E326ADC1C234396002A6505 /* dispatch_readsync.c */,
10231026
6E8E4E6D1C1A35EE0004F5CC /* dispatch_select.c */,
10241027
6E8E4E9B1C1A4EF10004F5CC /* dispatch_sema.c */,
1028+
B69878521F06F8790088F94F /* dispatch_signals.c */,
10251029
6EA2CB841C005DEF0076794A /* dispatch_source.c */,
10261030
6E326AE01C234780002A6505 /* dispatch_starfish.c */,
10271031
6EE89F3D1BFAF5B000EB140D /* dispatch_state_machine.c */,

man/dispatch_apply.3

+30-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.\" Copyright (c) 2008-2010 Apple Inc. All rights reserved.
1+
.\" Copyright (c) 2008-2017 Apple Inc. All rights reserved.
22
.Dd May 1, 2009
33
.Dt dispatch_apply 3
44
.Os Darwin
@@ -20,21 +20,32 @@ The
2020
.Fn dispatch_apply
2121
function provides data-level concurrency through a "for (;;)" loop like primitive:
2222
.Bd -literal
23-
dispatch_queue_t the_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
2423
size_t iterations = 10;
2524

2625
// 'idx' is zero indexed, just like:
2726
// for (idx = 0; idx < iterations; idx++)
2827

29-
dispatch_apply(iterations, the_queue, ^(size_t idx) {
28+
dispatch_apply(iterations, DISPATCH_APPLY_AUTO, ^(size_t idx) {
3029
printf("%zu\\n", idx);
3130
});
3231
.Ed
3332
.Pp
33+
Although any queue can be used, it is strongly recommended to use
34+
.Vt DISPATCH_APPLY_AUTO
35+
as the
36+
.Vt queue
37+
argument to both
38+
.Fn dispatch_apply
39+
and
40+
.Fn dispatch_apply_f ,
41+
as shown in the example above, since this allows the system to automatically use worker threads
42+
that match the configuration of the current thread as closely as possible.
43+
No assumptions should be made about which global concurrent queue will be used.
44+
.Pp
3445
Like a "for (;;)" loop, the
3546
.Fn dispatch_apply
3647
function is synchronous.
37-
If asynchronous behavior is desired, please wrap the call to
48+
If asynchronous behavior is desired, wrap the call to
3849
.Fn dispatch_apply
3950
with a call to
4051
.Fn dispatch_async
@@ -49,7 +60,7 @@ achieved (perhaps using a power of two search):
4960
.Bd -literal
5061
#define STRIDE 3
5162

52-
dispatch_apply(count / STRIDE, queue, ^(size_t idx) {
63+
dispatch_apply(count / STRIDE, DISPATCH_APPLY_AUTO, ^(size_t idx) {
5364
size_t j = idx * STRIDE;
5465
size_t j_stop = j + STRIDE;
5566
do {
@@ -74,12 +85,21 @@ This is in contrast to asynchronous functions which must retain both the block
7485
and target queue for the duration of the asynchronous operation (as the calling
7586
function may immediately release its interest in these objects).
7687
.Sh FUNDAMENTALS
77-
Conceptually,
7888
.Fn dispatch_apply
79-
is a convenient wrapper around
89+
and
90+
.Fn dispatch_apply_f
91+
attempt to quickly create enough worker threads to efficiently iterate work in parallel.
92+
By contrast, a loop that passes work items individually to
8093
.Fn dispatch_async
81-
and a semaphore to wait for completion.
82-
In practice, the dispatch library optimizes this function.
94+
or
95+
.Fn dispatch_async_f
96+
will incur more overhead and does not express the desired parallel execution semantics to
97+
the system, so may not create an optimal number of worker threads for a parallel workload.
98+
For this reason, prefer to use
99+
.Fn dispatch_apply
100+
or
101+
.Fn dispatch_apply_f
102+
when parallel execution is important.
83103
.Pp
84104
The
85105
.Fn dispatch_apply
@@ -99,5 +119,4 @@ use a for-loop around invocations of
99119
.Sh SEE ALSO
100120
.Xr dispatch 3 ,
101121
.Xr dispatch_async 3 ,
102-
.Xr dispatch_queue_create 3 ,
103-
.Xr dispatch_semaphore_create 3
122+
.Xr dispatch_queue_create 3

os/voucher_private.h

+16-1
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,23 @@ voucher_decrement_importance_count4CF(voucher_t _Nullable voucher);
202202
* This flag is ignored if a specific voucher object is assigned with the
203203
* dispatch_block_create_with_voucher* functions, and is equivalent to passing
204204
* the NULL voucher to these functions.
205+
*
206+
* @const DISPATCH_BLOCK_IF_LAST_RESET_QUEUE_QOS_OVERRIDE
207+
* Flag indicating that this dispatch block object should try to reset the
208+
* recorded maximum QoS of all currently enqueued items on a serial dispatch
209+
* queue at the base of a queue hierarchy.
210+
*
211+
* This is only works if the queue becomes empty by dequeuing the block in
212+
* question, and then allows that block to enqueue more work on this hierarchy
213+
* without perpetuating QoS overrides resulting from items previously executed
214+
* on the hierarchy.
215+
*
216+
* A dispatch block object created with this flag set cannot be used with
217+
* dispatch_block_wait() or dispatch_block_cancel().
205218
*/
206-
#define DISPATCH_BLOCK_NO_VOUCHER (0x40)
219+
#define DISPATCH_BLOCK_NO_VOUCHER (0x40ul)
220+
221+
#define DISPATCH_BLOCK_IF_LAST_RESET_QUEUE_QOS_OVERRIDE (0x80ul)
207222

208223
/*!
209224
* @function dispatch_block_create_with_voucher

private/private.h

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@
4343
#include <sys/cdefs.h>
4444
#endif
4545
#include <pthread.h>
46+
#if TARGET_OS_MAC
47+
#include <pthread/qos.h>
48+
#endif
4649

4750
#ifndef __DISPATCH_BUILDING_DISPATCH__
4851
#include <dispatch/dispatch.h>

private/source_private.h

+16
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ DISPATCH_SOURCE_TYPE_DECL(memorystatus);
102102
API_AVAILABLE(macos(10.8), ios(6.0)) DISPATCH_LINUX_UNAVAILABLE()
103103
DISPATCH_SOURCE_TYPE_DECL(sock);
104104

105+
/*!
106+
* @const DISPATCH_SOURCE_TYPE_NW_CHANNEL
107+
* @discussion A dispatch source that monitors events on a network channel.
108+
*/
109+
#define DISPATCH_SOURCE_TYPE_NW_CHANNEL (&_dispatch_source_type_nw_channel)
110+
API_AVAILABLE(macos(10.12), ios(10.0), tvos(10.0), watchos(3.0)) DISPATCH_LINUX_UNAVAILABLE()
111+
DISPATCH_SOURCE_TYPE_DECL(nw_channel);
105112

106113
__END_DECLS
107114

@@ -165,6 +172,15 @@ enum {
165172
DISPATCH_SOCK_NOTIFY_ACK = 0x00004000,
166173
};
167174

175+
/*!
176+
* @enum dispatch_source_nw_channel_flags_t
177+
*
178+
* @constant DISPATCH_NW_CHANNEL_FLOW_ADV_UPDATE
179+
* Received network channel flow advisory.
180+
*/
181+
enum {
182+
DISPATCH_NW_CHANNEL_FLOW_ADV_UPDATE = 0x00000001,
183+
};
168184

169185
/*!
170186
* @enum dispatch_source_vfs_flags_t

src/apply.c

+12-4
Original file line numberDiff line numberDiff line change
@@ -253,12 +253,23 @@ dispatch_apply_f(size_t iterations, dispatch_queue_t dq, void *ctxt,
253253
if (unlikely(iterations == 0)) {
254254
return;
255255
}
256-
int32_t thr_cnt = (int32_t)dispatch_hw_config(active_cpus);
257256
dispatch_thread_context_t dtctxt =
258257
_dispatch_thread_context_find(_dispatch_apply_key);
259258
size_t nested = dtctxt ? dtctxt->dtc_apply_nesting : 0;
260259
dispatch_queue_t old_dq = _dispatch_queue_get_current();
261260

261+
if (likely(dq == DISPATCH_APPLY_AUTO)) {
262+
dq = _dispatch_apply_root_queue(old_dq);
263+
}
264+
dispatch_qos_t qos = _dispatch_priority_qos(dq->dq_priority);
265+
if (unlikely(dq->do_targetq)) {
266+
// if the queue passed-in is not a root queue, use the current QoS
267+
// since the caller participates in the work anyway
268+
qos = _dispatch_qos_from_pp(_dispatch_get_priority());
269+
}
270+
int32_t thr_cnt = (int32_t)_dispatch_qos_max_parallelism(qos,
271+
DISPATCH_MAX_PARALLELISM_ACTIVE);
272+
262273
if (likely(!nested)) {
263274
nested = iterations;
264275
} else {
@@ -269,9 +280,6 @@ dispatch_apply_f(size_t iterations, dispatch_queue_t dq, void *ctxt,
269280
if (iterations < (size_t)thr_cnt) {
270281
thr_cnt = (int32_t)iterations;
271282
}
272-
if (likely(dq == DISPATCH_APPLY_AUTO)) {
273-
dq = _dispatch_apply_root_queue(old_dq);
274-
}
275283
struct dispatch_continuation_s dc = {
276284
.dc_func = (void*)func,
277285
.dc_ctxt = ctxt,

src/event/event_config.h

+24
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,25 @@
5050
#define DISPATCH_MACHPORT_DEBUG 0
5151
#endif
5252

53+
#ifndef DISPATCH_TIMER_ASSERTIONS
54+
#if DISPATCH_DEBUG
55+
#define DISPATCH_TIMER_ASSERTIONS 1
56+
#else
57+
#define DISPATCH_TIMER_ASSERTIONS 0
58+
#endif
59+
#endif
60+
61+
#if DISPATCH_TIMER_ASSERTIONS
62+
#define DISPATCH_TIMER_ASSERT(a, op, b, text) ({ \
63+
typeof(a) _a = (a); \
64+
if (unlikely(!(_a op (b)))) { \
65+
DISPATCH_CLIENT_CRASH(_a, "Timer: " text); \
66+
} \
67+
})
68+
#else
69+
#define DISPATCH_TIMER_ASSERT(a, op, b, text) ((void)0)
70+
#endif
71+
5372
#ifndef EV_VANISHED
5473
#define EV_VANISHED 0x0200
5574
#endif
@@ -105,6 +124,11 @@
105124
# ifndef VQ_DESIRED_DISK
106125
# undef HAVE_DECL_VQ_DESIRED_DISK
107126
# endif // VQ_DESIRED_DISK
127+
128+
# if !defined(EVFILT_NW_CHANNEL) && defined(__APPLE__)
129+
# define EVFILT_NW_CHANNEL (-16)
130+
# define NOTE_FLOW_ADV_UPDATE 0x1
131+
# endif
108132
#else // DISPATCH_EVENT_BACKEND_KEVENT
109133
# define EV_ADD 0x0001
110134
# define EV_DELETE 0x0002

src/event/event_kevent.c

+16-4
Original file line numberDiff line numberDiff line change
@@ -671,8 +671,9 @@ _dispatch_kq_drain(dispatch_wlh_t wlh, dispatch_kevent_t ke, int n,
671671
r = 0;
672672
} else if (flags & KEVENT_FLAG_ERROR_EVENTS) {
673673
for (i = 0, r = 0; i < n; i++) {
674-
if ((ke_out[i].flags & EV_ERROR) && (r = (int)ke_out[i].data)) {
674+
if ((ke_out[i].flags & EV_ERROR) && ke_out[i].data) {
675675
_dispatch_kevent_drain(&ke_out[i]);
676+
r = (int)ke_out[i].data;
676677
}
677678
}
678679
} else {
@@ -1407,6 +1408,17 @@ const dispatch_source_type_s _dispatch_source_type_sock = {
14071408
};
14081409
#endif // EVFILT_SOCK
14091410

1411+
#ifdef EVFILT_NW_CHANNEL
1412+
const dispatch_source_type_s _dispatch_source_type_nw_channel = {
1413+
.dst_kind = "nw_channel",
1414+
.dst_filter = EVFILT_NW_CHANNEL,
1415+
.dst_flags = DISPATCH_EV_DIRECT|EV_CLEAR|EV_VANISHED,
1416+
.dst_mask = NOTE_FLOW_ADV_UPDATE,
1417+
.dst_size = sizeof(struct dispatch_source_refs_s),
1418+
.dst_create = _dispatch_unote_create_with_fd,
1419+
.dst_merge_evt = _dispatch_source_merge_evt,
1420+
};
1421+
#endif // EVFILT_NW_CHANNEL
14101422

14111423
#if DISPATCH_USE_MEMORYSTATUS
14121424

@@ -1609,9 +1621,9 @@ _dispatch_mach_notify_source_invoke(mach_msg_header_t *hdr)
16091621
if (!tlr) {
16101622
DISPATCH_INTERNAL_CRASH(0, "message received without expected trailer");
16111623
}
1612-
if (tlr->msgh_audit.val[DISPATCH_MACH_AUDIT_TOKEN_PID] != 0) {
1613-
(void)dispatch_assume_zero(
1614-
tlr->msgh_audit.val[DISPATCH_MACH_AUDIT_TOKEN_PID]);
1624+
if (hdr->msgh_id <= MACH_NOTIFY_LAST
1625+
&& dispatch_assume_zero(tlr->msgh_audit.val[
1626+
DISPATCH_MACH_AUDIT_TOKEN_PID])) {
16151627
mach_msg_destroy(hdr);
16161628
return;
16171629
}

src/init.c

+1
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,7 @@ void
897897
_dispatch_temporary_resource_shortage(void)
898898
{
899899
sleep(1);
900+
asm(""); // prevent tailcall
900901
}
901902

902903
void *

src/inline_internal.h

+34-12
Original file line numberDiff line numberDiff line change
@@ -1740,7 +1740,7 @@ static inline dispatch_priority_t
17401740
_dispatch_root_queue_identity_assume(dispatch_queue_t assumed_rq)
17411741
{
17421742
dispatch_priority_t old_dbp = _dispatch_get_basepri();
1743-
dispatch_assert(dx_type(assumed_rq) == DISPATCH_QUEUE_GLOBAL_ROOT_TYPE);
1743+
dispatch_assert(dx_hastypeflag(assumed_rq, QUEUE_ROOT));
17441744
_dispatch_reset_basepri(assumed_rq->dq_priority);
17451745
_dispatch_queue_set_current(assumed_rq);
17461746
return old_dbp;
@@ -2108,11 +2108,25 @@ _dispatch_queue_priority_inherit_from_target(dispatch_queue_t dq,
21082108

21092109
if ((!_dispatch_priority_qos(pri) || (pri & inherited_flag)) &&
21102110
(tpri & rootqueue_flag)) {
2111+
if (_dispatch_priority_override_qos(pri) == DISPATCH_QOS_SATURATED) {
2112+
pri &= DISPATCH_PRIORITY_OVERRIDE_MASK;
2113+
} else {
2114+
pri = 0;
2115+
}
21112116
if (tpri & defaultqueue_flag) {
2112-
dq->dq_priority = 0;
2117+
// <rdar://problem/32921639> base queues need to know they target
2118+
// the default root queue so that _dispatch_queue_override_qos()
2119+
// in _dispatch_queue_class_wakeup() can fallback to QOS_DEFAULT
2120+
// if no other priority was provided.
2121+
pri |= defaultqueue_flag;
21132122
} else {
2114-
dq->dq_priority = (tpri & ~rootqueue_flag) | inherited_flag;
2123+
pri |= (tpri & ~rootqueue_flag) | inherited_flag;
21152124
}
2125+
dq->dq_priority = pri;
2126+
} else if (pri & defaultqueue_flag) {
2127+
// the DEFAULTQUEUE flag is only set on queues due to the code above,
2128+
// and must never be kept if we don't target a global root queue.
2129+
dq->dq_priority = (pri & ~defaultqueue_flag);
21162130
}
21172131
#else
21182132
(void)dq; (void)tq;
@@ -2272,7 +2286,9 @@ static inline dispatch_qos_t
22722286
_dispatch_queue_override_qos(dispatch_queue_class_t dqu, dispatch_qos_t qos)
22732287
{
22742288
if (dqu._oq->oq_priority & DISPATCH_PRIORITY_FLAG_DEFAULTQUEUE) {
2275-
return qos;
2289+
// queues targeting the default root queue use any asynchronous
2290+
// workitem priority available and fallback to QOS_DEFAULT otherwise.
2291+
return qos ? qos : DISPATCH_QOS_DEFAULT;
22762292
}
22772293
// for asynchronous workitems, queue priority is the floor for overrides
22782294
return MAX(qos, _dispatch_priority_qos(dqu._oq->oq_priority));
@@ -2338,14 +2354,20 @@ _dispatch_block_has_private_data(const dispatch_block_t block)
23382354
}
23392355

23402356
DISPATCH_ALWAYS_INLINE DISPATCH_WARN_RESULT
2341-
static inline bool
2342-
_dispatch_block_invoke_should_set_priority(dispatch_block_flags_t flags)
2343-
{
2344-
if (flags & DISPATCH_BLOCK_HAS_PRIORITY) {
2345-
return (flags & DISPATCH_BLOCK_ENFORCE_QOS_CLASS) ||
2346-
!(flags & DISPATCH_BLOCK_INHERIT_QOS_CLASS);
2347-
}
2348-
return false;
2357+
static inline pthread_priority_t
2358+
_dispatch_block_invoke_should_set_priority(dispatch_block_flags_t flags,
2359+
pthread_priority_t new_pri)
2360+
{
2361+
pthread_priority_t old_pri, p = 0; // 0 means do not change priority.
2362+
if ((flags & DISPATCH_BLOCK_HAS_PRIORITY)
2363+
&& ((flags & DISPATCH_BLOCK_ENFORCE_QOS_CLASS) ||
2364+
!(flags & DISPATCH_BLOCK_INHERIT_QOS_CLASS))) {
2365+
old_pri = _dispatch_get_priority();
2366+
new_pri &= ~_PTHREAD_PRIORITY_FLAGS_MASK;
2367+
p = old_pri & ~_PTHREAD_PRIORITY_FLAGS_MASK;
2368+
if (!p || p >= new_pri) p = 0;
2369+
}
2370+
return p;
23492371
}
23502372

23512373
DISPATCH_ALWAYS_INLINE

0 commit comments

Comments
 (0)