예제 #1
0
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");
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
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;
}
예제 #5
0
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);
}
예제 #6
0
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;
}