#include "internal.h"
void
dispatch_debug(dispatch_object_t dou, const char *msg, ...)
{
va_list ap;
va_start(ap, msg);
dispatch_debugv(dou._do, msg, ap);
va_end(ap);
}
void
dispatch_debugv(dispatch_object_t dou, const char *msg, va_list ap)
{
char buf[4096];
size_t offs;
if (dou._do && dou._do->do_vtable->do_debug) {
offs = dx_debug(dou._do, buf, sizeof(buf));
} else {
offs = snprintf(buf, sizeof(buf), "NULL vtable slot");
}
snprintf(buf + offs, sizeof(buf) - offs, ": %s", msg);
_dispatch_logv(buf, ap);
}
void
dispatch_retain(dispatch_object_t dou)
{
if (dou._do->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
return; }
if ((dispatch_atomic_inc(&dou._do->do_xref_cnt) - 1) == 0) {
DISPATCH_CLIENT_CRASH("Resurrection of an object");
}
}
void
_dispatch_retain(dispatch_object_t dou)
{
if (dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
return; }
if ((dispatch_atomic_inc(&dou._do->do_ref_cnt) - 1) == 0) {
DISPATCH_CLIENT_CRASH("Resurrection of an object");
}
}
void
dispatch_release(dispatch_object_t dou)
{
typeof(dou._do->do_xref_cnt) oldval;
if (dou._do->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
return;
}
oldval = dispatch_atomic_dec(&dou._do->do_xref_cnt) + 1;
if (fastpath(oldval > 1)) {
return;
}
if (oldval == 1) {
#ifndef DISPATCH_NO_LEGACY
if (dou._do->do_vtable == (void*)&_dispatch_source_kevent_vtable) {
return _dispatch_source_legacy_xref_release(dou._ds);
}
#endif
if (slowpath(DISPATCH_OBJECT_SUSPENDED(dou._do))) {
DISPATCH_CLIENT_CRASH("Release of a suspended object");
}
return _dispatch_release(dou._do);
}
DISPATCH_CLIENT_CRASH("Over-release of an object");
}
void
_dispatch_dispose(dispatch_object_t dou)
{
dispatch_queue_t tq = dou._do->do_targetq;
dispatch_function_t func = dou._do->do_finalizer;
void *ctxt = dou._do->do_ctxt;
dou._do->do_vtable = (void *)0x200;
free(dou._do);
if (func && ctxt) {
dispatch_async_f(tq, ctxt, func);
}
_dispatch_release(tq);
}
void
_dispatch_release(dispatch_object_t dou)
{
typeof(dou._do->do_ref_cnt) oldval;
if (dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
return; }
oldval = dispatch_atomic_dec(&dou._do->do_ref_cnt) + 1;
if (fastpath(oldval > 1)) {
return;
}
if (oldval == 1) {
if (dou._do->do_next != DISPATCH_OBJECT_LISTLESS) {
DISPATCH_CRASH("release while enqueued");
}
if (dou._do->do_xref_cnt) {
DISPATCH_CRASH("release while external references exist");
}
return dx_dispose(dou._do);
}
DISPATCH_CRASH("over-release");
}
void *
dispatch_get_context(dispatch_object_t dou)
{
return dou._do->do_ctxt;
}
void
dispatch_set_context(dispatch_object_t dou, void *context)
{
if (dou._do->do_ref_cnt != DISPATCH_OBJECT_GLOBAL_REFCNT) {
dou._do->do_ctxt = context;
}
}
void
dispatch_set_finalizer_f(dispatch_object_t dou, dispatch_function_t finalizer)
{
dou._do->do_finalizer = finalizer;
}
void
dispatch_suspend(dispatch_object_t dou)
{
if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
return;
}
dispatch_atomic_add(&dou._do->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL);
}
void
dispatch_resume(dispatch_object_t dou)
{
if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
return;
}
switch (dispatch_atomic_sub(&dou._do->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL) + DISPATCH_OBJECT_SUSPEND_INTERVAL) {
case DISPATCH_OBJECT_SUSPEND_INTERVAL:
_dispatch_wakeup(dou._do);
break;
case 0:
DISPATCH_CLIENT_CRASH("Over-resume of an object");
break;
default:
break;
}
}
size_t
dispatch_object_debug_attr(dispatch_object_t dou, char* buf, size_t bufsiz)
{
return snprintf(buf, bufsiz, "refcnt = 0x%x, suspend_cnt = 0x%x, ",
dou._do->do_ref_cnt, dou._do->do_suspend_cnt);
}