文件位置:libdispatch/src/object_internal.h
1. 不同结构体的类型type
enum {
_DISPATCH_CONTINUATION_TYPE = 0x00000, // meta-type for continuations
_DISPATCH_QUEUE_TYPE = 0x10000, // meta-type for queues
_DISPATCH_SOURCE_TYPE = 0x20000, // meta-type for sources
_DISPATCH_SEMAPHORE_TYPE = 0x30000, // meta-type for semaphores
_DISPATCH_ATTR_TYPE = 0x10000000, // meta-type for attribute structures
DISPATCH_CONTINUATION_TYPE = _DISPATCH_CONTINUATION_TYPE,
DISPATCH_QUEUE_ATTR_TYPE = _DISPATCH_QUEUE_TYPE | _DISPATCH_ATTR_TYPE,
DISPATCH_QUEUE_TYPE = 1 | _DISPATCH_QUEUE_TYPE,
DISPATCH_QUEUE_GLOBAL_TYPE = 2 | _DISPATCH_QUEUE_TYPE,
DISPATCH_QUEUE_MGR_TYPE = 3 | _DISPATCH_QUEUE_TYPE,
DISPATCH_SEMAPHORE_TYPE = _DISPATCH_SEMAPHORE_TYPE,
DISPATCH_SOURCE_ATTR_TYPE = _DISPATCH_SOURCE_TYPE | _DISPATCH_ATTR_TYPE,
DISPATCH_SOURCE_KEVENT_TYPE = 1 | _DISPATCH_SOURCE_TYPE,
};
注解:
continuation_type:用于封装成dispatch_continuation_t,可以当作压入队列的一个block
queue_type:队列类型;
source_type:source类型,source只是一种资源的统称,queue或者function都可以当作一种source;
semaphore_type:信号类型,消费-生产者模式;
kevent_type:用于kevent通信。
2. vtable
#define DISPATCH_VTABLE_HEADER(x) \
unsigned long const do_type; \
const char *const do_kind; \
size_t (*const do_debug)(struct x *, char *, size_t); \
struct dispatch_queue_s *(*const do_invoke)(struct x *); \
bool (*const do_probe)(struct x *); \
void (*const do_dispose)(struct x *)
#define dx_type(x) (x)->do_vtable->do_type
#define dx_kind(x) (x)->do_vtable->do_kind
#define dx_debug(x, y, z) (x)->do_vtable->do_debug((x), (y), (z))
#define dx_dispose(x) (x)->do_vtable->do_dispose(x)
#define dx_invoke(x) (x)->do_vtable->do_invoke(x)
#define dx_probe(x) (x)->do_vtable->do_probe(x)
相当于C++的模版,通过DISPATCH_VTABLE_HEADER为x结构定义一个vtable;
因为c-object中,并没有操作一类的说法,面向过程的实现,我这里称之为方法;
注释:
do_type: 这就是前文所指的type:
do_kined: char* 起到说明作用;
do_debug: debug方法
do_invoke:唤醒队列的方法;
do_dispose: dispose方法;
do_probe: probe方法,用于检测x中的一些变量是否满足条件。
不同type的结构会对应不同的vtable,vtable指示了处理的方法。
3. 头部信息
#define DISPATCH_STRUCT_HEADER(x, y) \
const struct y *do_vtable; \
struct x *volatile do_next; \
unsigned int do_ref_cnt; \
unsigned int do_xref_cnt; \
unsigned int do_suspend_cnt; \
struct dispatch_queue_s *do_targetq; \
void *do_ctxt; \
dispatch_function_t do_finalizer
头部结构体宏:
do_vatable:第二节讲到的vtable;
do_next: 链表的next;
do_ref_cnt: 引用计数;
do_xref_cnt:外部引用计数;用途?
do_suspend_cnt:suspend计数,用作暂停标志,比如延时处理的任务,设置该引用计数之后;在任务到时后,计时器处理将会将该标志位修改,然后唤醒队列调度;
dispatch_queue_s:目标队列,就是当前这个struct x在哪个队列运行;
do_ctext:上下文
4. 通用结构
struct dispatch_object_vtable_s {
DISPATCH_VTABLE_HEADER(dispatch_object_s);
};
struct dispatch_object_s {
DISPATCH_STRUCT_HEADER(dispatch_object_s, dispatch_object_vtable_s);
};
5. 方法解析
位于libdispatch/src/object.c
(1). debug
在Debug打印上,用了va_list,要想详细了解,请参看:
http://blog.csdn.net/wzwind/article/details/1666518
下面的msg只是提供打印的内容
void
dispatch_debug(dispatch_object_t obj, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
dispatch_debugv(obj, msg, ap);
va_end(ap);
}
void
dispatch_debugv(dispatch_object_t dou, const char *msg, va_list ap)
{
char buf[4096];
size_t offs;
struct dispatch_object_s *obj = DO_CAST(dou);
if (obj && obj->do_vtable->do_debug) {
offs = dx_debug(obj, buf, sizeof(buf));
} else {
offs = snprintf(buf, sizeof(buf), "NULL vtable slot");
}
snprintf(buf + offs, sizeof(buf) - offs, ": %s", msg);
_dispatch_logv(buf, ap);
}
(2). retain 与release对
获取与释放。目的: /?
#define DISPATCH_OBJECT_GLOBAL_REFCNT (~0u)
void
dispatch_retain(dispatch_object_t dou)
{
struct dispatch_object_s *obj = DO_CAST(dou);
if (obj->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
return; // global object
}
if ((dispatch_atomic_inc(&obj->do_xref_cnt) - 1) == 0) {
DISPATCH_CLIENT_CRASH("Resurrection of an object");
}
}
void
_dispatch_retain(dispatch_object_t dou)
{
struct dispatch_object_s *obj = DO_CAST(dou);
if (obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
return; // global object
}
if ((dispatch_atomic_inc(&obj->do_ref_cnt) - 1) == 0) {
DISPATCH_CLIENT_CRASH("Resurrection of an object");
}
}
void
dispatch_release(dispatch_object_t dou)
{
struct dispatch_object_s *obj = DO_CAST(dou);
unsigned int oldval;
if (obj->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
return;
}
oldval = dispatch_atomic_dec(&obj->do_xref_cnt) + 1;
if (fastpath(oldval > 1)) {
return;
}
if (oldval == 1) {
if ((uintptr_t)obj->do_vtable == (uintptr_t)&_dispatch_source_kevent_vtable) {
return _dispatch_source_xref_release((dispatch_source_t)obj);
}
if (slowpath(DISPATCH_OBJECT_SUSPENDED(obj))) {
// Arguments for and against this assert are within 6705399
DISPATCH_CLIENT_CRASH("Release of a suspended object");
}
return _dispatch_release(obj);
}
DISPATCH_CLIENT_CRASH("Over-release of an object");
}
void
_dispatch_release(dispatch_object_t dou)
{
struct dispatch_object_s *obj = DO_CAST(dou);
unsigned int oldval;
if (obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
return; // global object
}
oldval = dispatch_atomic_dec(&obj->do_ref_cnt) + 1;
if (fastpath(oldval > 1)) {
return;
}
if (oldval == 1) {
if (obj->do_next != DISPATCH_OBJECT_LISTLESS) {
DISPATCH_CRASH("release while enqueued");
}
if (obj->do_xref_cnt) {
DISPATCH_CRASH("release while external references exist");
}
return dx_dispose(obj);
}
DISPATCH_CRASH("over-release");
}
void
_dispatch_dispose(dispatch_object_t dou)
{
struct dispatch_object_s *obj = DO_CAST(dou);
dispatch_queue_t tq = obj->do_targetq;
dispatch_function_t func = obj->do_finalizer;
void *ctxt = obj->do_ctxt;
obj->do_vtable = (struct dispatch_object_vtable_s *)0x200;
free(obj);
if (func && ctxt) {
dispatch_async_f(tq, ctxt, func);
}
_dispatch_release(tq);
}
void *
dispatch_get_context(dispatch_object_t dou)
{
struct dispatch_object_s *obj = DO_CAST(dou);
return obj->do_ctxt;
}
void
dispatch_set_context(dispatch_object_t dou, void *context)
{
struct dispatch_object_s *obj = DO_CAST(dou);
if (obj->do_ref_cnt != DISPATCH_OBJECT_GLOBAL_REFCNT) {
obj->do_ctxt = context;
}
}
void
dispatch_set_finalizer_f(dispatch_object_t dou, dispatch_function_t finalizer)
{
struct dispatch_object_s *obj = DO_CAST(dou);
obj->do_finalizer = finalizer;
}
void
dispatch_suspend(dispatch_object_t dou)
{
struct dispatch_object_s *obj = DO_CAST(dou);
if (slowpath(obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
return;
}
(void)dispatch_atomic_add(&obj->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL);
}
void
dispatch_resume(dispatch_object_t dou)
{
struct dispatch_object_s *obj = DO_CAST(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(obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
return;
}
// Switch on 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.
switch (dispatch_atomic_sub(&obj->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL) + DISPATCH_OBJECT_SUSPEND_INTERVAL) {
case DISPATCH_OBJECT_SUSPEND_INTERVAL:
_dispatch_wakeup(obj);
break;
case DISPATCH_OBJECT_SUSPEND_LOCK:
case 0:
DISPATCH_CLIENT_CRASH("Over-resume of an object");
break;
default:
break;
}
}