void dispatch_resume(dispatch_object_t dou) { DISPATCH_OBJECT_TFB(_dispatch_objc_resume, dou); // Global objects cannot be suspended or resumed. This also has the // side effect of saturating the suspend count of an object and // guarding against resuming due to overflow. if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) || slowpath(dx_type(dou._do) == DISPATCH_QUEUE_ROOT_TYPE)) { return; } // Check the previous value of the suspend count. If the previous // value was a single suspend interval, the object should be resumed. // If the previous value was less than the suspend interval, the object // has been over-resumed. unsigned int suspend_cnt = dispatch_atomic_sub_orig2o(dou._do, do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL, relaxed); if (fastpath(suspend_cnt > DISPATCH_OBJECT_SUSPEND_INTERVAL)) { // Balancing the retain() done in suspend() for rdar://8181908 return _dispatch_release(dou._do); } if (fastpath(suspend_cnt == DISPATCH_OBJECT_SUSPEND_INTERVAL)) { return _dispatch_resume_slow(dou); } DISPATCH_CLIENT_CRASH("Over-resume of an object"); }
void dispatch_set_finalizer_f(dispatch_object_t dou, dispatch_function_t finalizer) { DISPATCH_OBJECT_TFB(_dispatch_objc_set_finalizer_f, dou, finalizer); if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) || slowpath(dx_type(dou._do) == DISPATCH_QUEUE_ROOT_TYPE)) { return; } dou._do->do_finalizer = finalizer; }
void dispatch_set_context(dispatch_object_t dou, void *context) { DISPATCH_OBJECT_TFB(_dispatch_objc_set_context, dou, context); if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) || slowpath(dx_type(dou._do) == DISPATCH_QUEUE_ROOT_TYPE)) { return; } dou._do->do_ctxt = context; }
void * dispatch_get_context(dispatch_object_t dou) { DISPATCH_OBJECT_TFB(_dispatch_objc_get_context, dou); if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) || slowpath(dx_type(dou._do) == DISPATCH_QUEUE_ROOT_TYPE)) { return NULL; } return dou._do->do_ctxt; }
void dispatch_suspend(dispatch_object_t dou) { DISPATCH_OBJECT_TFB(_dispatch_objc_suspend, dou); if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) || slowpath(dx_type(dou._do) == DISPATCH_QUEUE_ROOT_TYPE)) { return; } // rdar://8181908 explains why we need to do an internal retain at every // suspension. (void)dispatch_atomic_add2o(dou._do, do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL, relaxed); _dispatch_retain(dou._do); }
void _dispatch_xref_dispose(dispatch_object_t dou) { if (slowpath(DISPATCH_OBJECT_SUSPENDED(dou._do))) { // Arguments for and against this assert are within 6705399 DISPATCH_CLIENT_CRASH("Release of a suspended object"); } #if !USE_OBJC if (dx_type(dou._do) == DISPATCH_SOURCE_KEVENT_TYPE) { _dispatch_source_xref_dispose(dou._ds); } else if (dou._dq->do_vtable == DISPATCH_VTABLE(queue_runloop)) { _dispatch_runloop_queue_xref_dispose(dou._dq); } return _dispatch_release(dou._os_obj); #endif }
static inline dispatch_introspection_queue_function_s _dispatch_introspection_continuation_get_info(dispatch_queue_t dq, dispatch_continuation_t dc, unsigned long *type) { void *ctxt = dc->dc_ctxt; dispatch_function_t func = dc->dc_func; pthread_t waiter = NULL; bool apply = false; long flags = (long)dc->do_vtable; if (flags & DISPATCH_OBJ_SYNC_SLOW_BIT) { waiter = pthread_from_mach_thread_np((mach_port_t)dc->dc_data); if (flags & DISPATCH_OBJ_BARRIER_BIT) { dc = dc->dc_ctxt; dq = dc->dc_data; } ctxt = dc->dc_ctxt; func = dc->dc_func; } if (func == _dispatch_sync_recurse_invoke) { dc = dc->dc_ctxt; dq = dc->dc_data; ctxt = dc->dc_ctxt; func = dc->dc_func; } else if (func == _dispatch_async_redirect_invoke) { dq = dc->dc_data; dc = dc->dc_other; ctxt = dc->dc_ctxt; func = dc->dc_func; flags = (long)dc->do_vtable; } else if (func == _dispatch_mach_barrier_invoke) { dq = dq->do_targetq; ctxt = dc->dc_data; func = dc->dc_other; } else if (func == _dispatch_apply_invoke || func == _dispatch_apply_redirect_invoke) { dispatch_apply_t da = ctxt; if (da->da_todo) { dc = da->da_dc; if (func == _dispatch_apply_redirect_invoke) { dq = dc->dc_data; } ctxt = dc->dc_ctxt; func = dc->dc_func; apply = true; } } if (func == _dispatch_call_block_and_release) { *type = dispatch_introspection_queue_item_type_block; func = _dispatch_Block_invoke(ctxt); } else { *type = dispatch_introspection_queue_item_type_function; } dispatch_introspection_queue_function_s diqf= { .continuation = dc, .target_queue = dq, .context = ctxt, .function = func, .group = flags & DISPATCH_OBJ_GROUP_BIT ? dc->dc_data : NULL, .waiter = waiter, .barrier = flags & DISPATCH_OBJ_BARRIER_BIT, .sync = flags & DISPATCH_OBJ_SYNC_SLOW_BIT, .apply = apply, }; return diqf; } static inline dispatch_introspection_object_s _dispatch_introspection_object_get_info(dispatch_object_t dou) { dispatch_introspection_object_s dio = { .object = dou._dc, .target_queue = dou._do->do_targetq, .type = (void*)dou._do->do_vtable, .kind = dx_kind(dou._do), }; return dio; } DISPATCH_USED inline dispatch_introspection_queue_s dispatch_introspection_queue_get_info(dispatch_queue_t dq) { bool global = (dq->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) || (dq->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT); uint16_t width = dq->dq_width; if (width > 1 && width != DISPATCH_QUEUE_WIDTH_MAX) width /= 2; dispatch_introspection_queue_s diq = { .queue = dq, .target_queue = dq->do_targetq, .label = dq->dq_label, .serialnum = dq->dq_serialnum, .width = width, .suspend_count = dq->do_suspend_cnt / 2, .enqueued = (dq->do_suspend_cnt & 1) && !global, .barrier = (dq->dq_running & 1) && !global, .draining = (dq->dq_items_head == (void*)~0ul) || (!dq->dq_items_head && dq->dq_items_tail), .global = global, .main = (dq == &_dispatch_main_q), }; return diq; } static inline dispatch_introspection_source_s _dispatch_introspection_source_get_info(dispatch_source_t ds) { dispatch_source_refs_t dr = ds->ds_refs; dispatch_continuation_t dc = dr->ds_handler[DS_EVENT_HANDLER]; void *ctxt = NULL; dispatch_function_t handler = NULL; bool hdlr_is_block = false; if (dc) { ctxt = dc->dc_ctxt; handler = dc->dc_func; hdlr_is_block = ((long)dc->do_vtable & DISPATCH_OBJ_BLOCK_RELEASE_BIT); } bool after = (handler == _dispatch_after_timer_callback); if (after && !(ds->ds_atomic_flags & DSF_CANCELED)) { dc = ctxt; ctxt = dc->dc_ctxt; handler = dc->dc_func; hdlr_is_block = (handler == _dispatch_call_block_and_release); if (hdlr_is_block) { handler = _dispatch_Block_invoke(ctxt); } } dispatch_introspection_source_s dis = { .source = ds, .target_queue = ds->do_targetq, .type = ds->ds_dkev ? (unsigned long)ds->ds_dkev->dk_kevent.filter : 0, .handle = ds->ds_dkev ? (unsigned long)ds->ds_dkev->dk_kevent.ident : 0, .context = ctxt, .handler = handler, .suspend_count = ds->do_suspend_cnt / 2, .enqueued = (ds->do_suspend_cnt & 1), .handler_is_block = hdlr_is_block, .timer = ds->ds_is_timer, .after = after, }; return dis; } static inline dispatch_introspection_queue_thread_s _dispatch_introspection_thread_get_info(dispatch_introspection_thread_t dit) { dispatch_introspection_queue_thread_s diqt = { .object = (void*)dit, .thread = dit->thread, }; if (dit->queue && *dit->queue) { diqt.queue = dispatch_introspection_queue_get_info(*dit->queue); } return diqt; } DISPATCH_USED inline dispatch_introspection_queue_item_s dispatch_introspection_queue_item_get_info(dispatch_queue_t dq, dispatch_continuation_t dc) { dispatch_introspection_queue_item_s diqi; if (DISPATCH_OBJ_IS_VTABLE(dc)) { dispatch_object_t dou = (dispatch_object_t)dc; unsigned long type = dx_type(dou._do); unsigned long metatype = type & _DISPATCH_META_TYPE_MASK; if (metatype == _DISPATCH_QUEUE_TYPE && type != DISPATCH_QUEUE_SPECIFIC_TYPE) { diqi.type = dispatch_introspection_queue_item_type_queue; diqi.queue = dispatch_introspection_queue_get_info(dou._dq); } else if (metatype == _DISPATCH_SOURCE_TYPE && type != DISPATCH_MACH_CHANNEL_TYPE) { diqi.type = dispatch_introspection_queue_item_type_source; diqi.source = _dispatch_introspection_source_get_info(dou._ds); } else { diqi.type = dispatch_introspection_queue_item_type_object; diqi.object = _dispatch_introspection_object_get_info(dou._do); } } else { diqi.function = _dispatch_introspection_continuation_get_info(dq, dc, &diqi.type); } return diqi; }