]> git.saurik.com Git - apple/libdispatch.git/commitdiff
libdispatch-84.5.5.tar.gz mac-os-x-1063 mac-os-x-1064 mac-os-x-1065 mac-os-x-1066 mac-os-x-1067 mac-os-x-1068 v84.5.5
authorApple <opensource@apple.com>
Thu, 7 Jan 2010 23:03:37 +0000 (23:03 +0000)
committerApple <opensource@apple.com>
Thu, 7 Jan 2010 23:03:37 +0000 (23:03 +0000)
src/apply.c
src/queue.c

index 2c51eb27044f0b2cb76a9b19952df7752ca2d883..88d8066bd560f32a5fea94d60eb31651a4f16d4c 100644 (file)
@@ -72,11 +72,28 @@ _dispatch_apply_serial(void *context)
 }
 
 #ifdef __BLOCKS__
+#if DISPATCH_COCOA_COMPAT
+DISPATCH_NOINLINE
+static void
+_dispatch_apply_slow(size_t iterations, dispatch_queue_t dq, void (^work)(size_t))
+{
+       struct Block_basic *bb = (void *)_dispatch_Block_copy((void *)work);
+       dispatch_apply_f(iterations, dq, bb, (void *)bb->Block_invoke);
+       Block_release(bb);
+}
+#endif
+
 void
 dispatch_apply(size_t iterations, dispatch_queue_t dq, void (^work)(size_t))
 {
+#if DISPATCH_COCOA_COMPAT
+       // Under GC, blocks transferred to other threads must be Block_copy()ed
+       // rdar://problem/7455071
+       if (dispatch_begin_thread_4GC) {
+               return _dispatch_apply_slow(iterations, dq, work);
+       }
+#endif
        struct Block_basic *bb = (void *)work;
-
        dispatch_apply_f(iterations, dq, bb, (void *)bb->Block_invoke);
 }
 #endif
index 9111a0fde436362365ac5b0c9d7426461429fe69..231dc37f154a3c99d4f2f5b81d21484a5836f947 100644 (file)
@@ -157,7 +157,10 @@ static struct dispatch_object_s *_dispatch_queue_concurrent_drain_one(dispatch_q
 static bool _dispatch_program_is_probably_callback_driven;
 
 #if DISPATCH_COCOA_COMPAT
-void (*dispatch_begin_thread_4GC)(void) = dummy_function;
+// dispatch_begin_thread_4GC having non-default value triggers GC-only slow paths and
+// is checked frequently, testing against NULL is faster than comparing for equality
+// with "dummy_function"
+void (*dispatch_begin_thread_4GC)(void) = NULL;
 void (*dispatch_end_thread_4GC)(void) = dummy_function;
 void *(*_dispatch_begin_NSAutoReleasePool)(void) = (void *)dummy_function;
 void (*_dispatch_end_NSAutoReleasePool)(void *) = (void *)dummy_function;
@@ -691,8 +694,10 @@ dispatch_async_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func)
 
 struct dispatch_barrier_sync_slow2_s {
        dispatch_queue_t dbss2_dq;
+#if DISPATCH_COCOA_COMPAT
        dispatch_function_t dbss2_func;
-       dispatch_function_t dbss2_ctxt; 
+       dispatch_function_t dbss2_ctxt;
+#endif
        dispatch_semaphore_t dbss2_sema;
 };
 
@@ -702,12 +707,16 @@ _dispatch_barrier_sync_f_slow_invoke(void *ctxt)
        struct dispatch_barrier_sync_slow2_s *dbss2 = ctxt;
 
        dispatch_assert(dbss2->dbss2_dq == dispatch_get_current_queue());
-       // ALL blocks on the main queue, must be run on the main thread
-       if (dbss2->dbss2_dq == dispatch_get_main_queue()) {
+#if DISPATCH_COCOA_COMPAT
+       // When the main queue is bound to the main thread
+       if (dbss2->dbss2_dq == &_dispatch_main_q && pthread_main_np()) {
                dbss2->dbss2_func(dbss2->dbss2_ctxt);
-       } else {
-               dispatch_suspend(dbss2->dbss2_dq);
+               dbss2->dbss2_func = NULL;
+               dispatch_semaphore_signal(dbss2->dbss2_sema);
+               return;
        }
+#endif
+       dispatch_suspend(dbss2->dbss2_dq);
        dispatch_semaphore_signal(dbss2->dbss2_sema);
 }
 
@@ -722,8 +731,10 @@ _dispatch_barrier_sync_f_slow(dispatch_queue_t dq, void *ctxt, dispatch_function
        
        struct dispatch_barrier_sync_slow2_s dbss2 = {
                .dbss2_dq = dq,
+#if DISPATCH_COCOA_COMPAT
                .dbss2_func = func,
-               .dbss2_ctxt = ctxt,             
+               .dbss2_ctxt = ctxt,
+#endif
                .dbss2_sema = _dispatch_get_thread_semaphore(),
        };
        struct dispatch_barrier_sync_slow_s {
@@ -734,33 +745,52 @@ _dispatch_barrier_sync_f_slow(dispatch_queue_t dq, void *ctxt, dispatch_function
                .dc_ctxt = &dbss2,
        };
        
-       dispatch_queue_t old_dq = _dispatch_thread_getspecific(dispatch_queue_key);
        _dispatch_queue_push(dq, (void *)&dbss);
        dispatch_semaphore_wait(dbss2.dbss2_sema, DISPATCH_TIME_FOREVER);
+       _dispatch_put_thread_semaphore(dbss2.dbss2_sema);
 
-       if (dq != dispatch_get_main_queue()) {
-               _dispatch_thread_setspecific(dispatch_queue_key, dq);
-               func(ctxt);
-               _dispatch_workitem_inc();
-               _dispatch_thread_setspecific(dispatch_queue_key, old_dq);
-               dispatch_resume(dq);
+#if DISPATCH_COCOA_COMPAT
+       // Main queue bound to main thread
+       if (dbss2.dbss2_func == NULL) {
+               return;
        }
-       _dispatch_put_thread_semaphore(dbss2.dbss2_sema);
+#endif
+       dispatch_queue_t old_dq = _dispatch_thread_getspecific(dispatch_queue_key);
+       _dispatch_thread_setspecific(dispatch_queue_key, dq);
+       func(ctxt);
+       _dispatch_workitem_inc();
+       _dispatch_thread_setspecific(dispatch_queue_key, old_dq);
+       dispatch_resume(dq);
 }
 
 #ifdef __BLOCKS__
-void
-dispatch_barrier_sync(dispatch_queue_t dq, void (^work)(void))
+#if DISPATCH_COCOA_COMPAT
+DISPATCH_NOINLINE
+static void
+_dispatch_barrier_sync_slow(dispatch_queue_t dq, void (^work)(void))
 {
        // Blocks submitted to the main queue MUST be run on the main thread,
-       // therefore we must Block_copy in order to notify the thread-local
+       // therefore under GC we must Block_copy in order to notify the thread-local
        // garbage collector that the objects are transferring to the main thread
-       if (dq == dispatch_get_main_queue()) {
-               dispatch_block_t block = Block_copy(work);
+       // rdar://problem/7176237&7181849&7458685
+       if (dispatch_begin_thread_4GC) {
+               dispatch_block_t block = _dispatch_Block_copy(work);
                return dispatch_barrier_sync_f(dq, block, _dispatch_call_block_and_release);
-       }       
+       }
        struct Block_basic *bb = (void *)work;
+       dispatch_barrier_sync_f(dq, work, (dispatch_function_t)bb->Block_invoke);
+}
+#endif
 
+void
+dispatch_barrier_sync(dispatch_queue_t dq, void (^work)(void))
+{
+#if DISPATCH_COCOA_COMPAT
+       if (slowpath(dq == &_dispatch_main_q)) {
+               return _dispatch_barrier_sync_slow(dq, work);
+       }
+#endif
+       struct Block_basic *bb = (void *)work;
        dispatch_barrier_sync_f(dq, work, (dispatch_function_t)bb->Block_invoke);
 }
 #endif
@@ -821,9 +851,32 @@ _dispatch_sync_f_slow(dispatch_queue_t dq)
 }
 
 #ifdef __BLOCKS__
+#if DISPATCH_COCOA_COMPAT
+DISPATCH_NOINLINE
+static void
+_dispatch_sync_slow(dispatch_queue_t dq, void (^work)(void))
+{
+       // Blocks submitted to the main queue MUST be run on the main thread,
+       // therefore under GC we must Block_copy in order to notify the thread-local
+       // garbage collector that the objects are transferring to the main thread
+       // rdar://problem/7176237&7181849&7458685
+       if (dispatch_begin_thread_4GC) {
+               dispatch_block_t block = _dispatch_Block_copy(work);
+               return dispatch_sync_f(dq, block, _dispatch_call_block_and_release);
+       }
+       struct Block_basic *bb = (void *)work;
+       dispatch_sync_f(dq, work, (dispatch_function_t)bb->Block_invoke);
+}
+#endif
+
 void
 dispatch_sync(dispatch_queue_t dq, void (^work)(void))
 {
+#if DISPATCH_COCOA_COMPAT
+       if (slowpath(dq == &_dispatch_main_q)) {
+               return _dispatch_sync_slow(dq, work);
+       }
+#endif
        struct Block_basic *bb = (void *)work;
        dispatch_sync_f(dq, work, (dispatch_function_t)bb->Block_invoke);
 }
@@ -1417,7 +1470,9 @@ _dispatch_worker_thread2(void *context)
 
 #if DISPATCH_COCOA_COMPAT
        // ensure that high-level memory management techniques do not leak/crash
-       dispatch_begin_thread_4GC();
+       if (dispatch_begin_thread_4GC) {
+               dispatch_begin_thread_4GC();
+       }
        void *pool = _dispatch_begin_NSAutoReleasePool();
 #endif