Revision: 155 http://trac.macosforge.org/projects/libdispatch/changeset/155 Author: kvv@apple.com Date: 2009-11-14 15:53:59 -0800 (Sat, 14 Nov 2009) Log Message: ----------- 10.6.2: Fix a performance regression in the dispatch_queue_pust_list fast path. <rdar://problem/7217227> Modified Paths: -------------- trunk/src/queue.c trunk/src/queue_internal.h Modified: trunk/src/queue.c =================================================================== --- trunk/src/queue.c 2009-11-14 21:24:14 UTC (rev 154) +++ trunk/src/queue.c 2009-11-14 23:53:59 UTC (rev 155) @@ -620,6 +620,22 @@ _dispatch_dispose(dq); } +DISPATCH_NOINLINE +void +_dispatch_queue_push_list_slow(dispatch_queue_t dq, struct dispatch_object_s *obj) +{ + // The queue must be retained before dq_items_head is written in order + // to ensure that the reference is still valid when _dispatch_wakeup is + // called. Otherwise, if preempted between the assignment to + // dq_items_head and _dispatch_wakeup, the blocks submitted to the + // queue may release the last reference to the queue when invoked by + // _dispatch_queue_drain. <rdar://problem/6932776> + _dispatch_retain(dq); + dq->dq_items_head = obj; + _dispatch_wakeup(dq); + _dispatch_release(dq); +} + DISPATCH_NOINLINE static void _dispatch_barrier_async_f_slow(dispatch_queue_t dq, void *context, dispatch_function_t func) Modified: trunk/src/queue_internal.h =================================================================== --- trunk/src/queue_internal.h 2009-11-14 21:24:14 UTC (rev 154) +++ trunk/src/queue_internal.h 2009-11-14 23:53:59 UTC (rev 155) @@ -95,6 +95,7 @@ void _dispatch_queue_init(dispatch_queue_t dq); void _dispatch_queue_drain(dispatch_queue_t dq); void _dispatch_queue_dispose(dispatch_queue_t dq); +void _dispatch_queue_push_list_slow(dispatch_queue_t dq, struct dispatch_object_s *obj); void _dispatch_queue_serial_drain_till_empty(dispatch_queue_t dq); void _dispatch_force_cache_cleanup(void); @@ -105,17 +106,14 @@ struct dispatch_object_s *prev, *head = _head._do, *tail = _tail._do; tail->do_next = NULL; - _dispatch_retain(dq); prev = fastpath(dispatch_atomic_xchg(&dq->dq_items_tail, tail)); if (prev) { // if we crash here with a value less than 0x1000, then we are at a known bug in client code // for example, see _dispatch_queue_dispose or _dispatch_atfork_child prev->do_next = head; } else { - dq->dq_items_head = head; - _dispatch_wakeup(dq); + _dispatch_queue_push_list_slow(dq, head); } - _dispatch_release(dq); } #define _dispatch_queue_push(x, y) _dispatch_queue_push_list((x), (y), (y))