Permalink
Browse files

10.6.2: Always run dispatch_sync blocks on the current thread to bett…

…er support

the thread-local garbage collector. <rdar://problem/7181849>

git-svn-id: https://svn.macosforge.org/repository/libdispatch/trunk@156 5710d607-3af0-45f8-8f96-4508d4f60227
  • Loading branch information...
1 parent 112d333 commit e64e4b962e1f356d7561e7a6103b424f335d85f6 @kvanvechten kvanvechten committed Nov 14, 2009
Showing with 32 additions and 12 deletions.
  1. +32 −12 src/queue.c
View
@@ -716,8 +716,9 @@ dispatch_async_f(dispatch_queue_t dq, void *ctxt, dispatch_function_t func)
}
struct dispatch_barrier_sync_slow2_s {
+ dispatch_queue_t dbss2_dq;
dispatch_function_t dbss2_func;
- dispatch_function_t dbss2_ctxt;
+ dispatch_function_t dbss2_ctxt;
dispatch_semaphore_t dbss2_sema;
};
@@ -726,17 +727,29 @@ _dispatch_barrier_sync_f_slow_invoke(void *ctxt)
{
struct dispatch_barrier_sync_slow2_s *dbss2 = ctxt;
- dbss2->dbss2_func(dbss2->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()) {
+ dbss2->dbss2_func(dbss2->dbss2_ctxt);
+ } else {
+ dispatch_suspend(dbss2->dbss2_dq);
+ }
dispatch_semaphore_signal(dbss2->dbss2_sema);
}
DISPATCH_NOINLINE
static void
_dispatch_barrier_sync_f_slow(dispatch_queue_t dq, void *ctxt, dispatch_function_t func)
{
+
+ // It's preferred to execute synchronous blocks on the current thread
+ // due to thread-local side effects, garbage collection, etc. However,
+ // blocks submitted to the main thread MUST be run on the main thread
+
struct dispatch_barrier_sync_slow2_s dbss2 = {
+ .dbss2_dq = dq,
.dbss2_func = func,
- .dbss2_ctxt = ctxt,
+ .dbss2_ctxt = ctxt,
.dbss2_sema = _dispatch_get_thread_semaphore(),
};
struct dispatch_barrier_sync_slow_s {
@@ -746,17 +759,17 @@ _dispatch_barrier_sync_f_slow(dispatch_queue_t dq, void *ctxt, dispatch_function
.dc_func = _dispatch_barrier_sync_f_slow_invoke,
.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);
- while (dispatch_semaphore_wait(dbss2.dbss2_sema, dispatch_time(0, 3ull * NSEC_PER_SEC))) {
- if (DISPATCH_OBJECT_SUSPENDED(dq)) {
- continue;
- }
- if (_dispatch_queue_trylock(dq)) {
- _dispatch_queue_drain(dq);
- _dispatch_queue_unlock(dq);
- }
+ 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);
}
_dispatch_put_thread_semaphore(dbss2.dbss2_sema);
}
@@ -765,6 +778,13 @@ _dispatch_barrier_sync_f_slow(dispatch_queue_t dq, void *ctxt, dispatch_function
void
dispatch_barrier_sync(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
+ // garbage collector that the objects are transferring to the main thread
+ if (dq == dispatch_get_main_queue()) {
+ dispatch_block_t block = 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);

0 comments on commit e64e4b9

Please sign in to comment.