2 * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
4 * @APPLE_APACHE_LICENSE_HEADER_START@
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
18 * @APPLE_APACHE_LICENSE_HEADER_END@
24 dispatch_debug(dispatch_object_t obj, const char *msg, ...)
30 dispatch_debugv(obj, msg, ap);
36 dispatch_debugv(dispatch_object_t dou, const char *msg, va_list ap)
41 struct dispatch_object_s *obj = DO_CAST(dou);
43 if (obj && obj->do_vtable->do_debug) {
44 offs = dx_debug(obj, buf, sizeof(buf));
46 offs = snprintf(buf, sizeof(buf), "NULL vtable slot");
49 snprintf(buf + offs, sizeof(buf) - offs, ": %s", msg);
51 _dispatch_logv(buf, ap);
55 dispatch_retain(dispatch_object_t dou)
57 struct dispatch_object_s *obj = DO_CAST(dou);
59 if (obj->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
60 return; // global object
62 if ((dispatch_atomic_inc(&obj->do_xref_cnt) - 1) == 0) {
63 DISPATCH_CLIENT_CRASH("Resurrection of an object");
68 _dispatch_retain(dispatch_object_t dou)
70 struct dispatch_object_s *obj = DO_CAST(dou);
72 if (obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
73 return; // global object
75 if ((dispatch_atomic_inc(&obj->do_ref_cnt) - 1) == 0) {
76 DISPATCH_CLIENT_CRASH("Resurrection of an object");
81 dispatch_release(dispatch_object_t dou)
83 struct dispatch_object_s *obj = DO_CAST(dou);
87 if (obj->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
91 oldval = dispatch_atomic_dec(&obj->do_xref_cnt) + 1;
93 if (fastpath(oldval > 1)) {
97 if ((uintptr_t)obj->do_vtable == (uintptr_t)&_dispatch_source_kevent_vtable) {
98 return _dispatch_source_xref_release((dispatch_source_t)obj);
100 if (slowpath(DISPATCH_OBJECT_SUSPENDED(obj))) {
101 // Arguments for and against this assert are within 6705399
102 DISPATCH_CLIENT_CRASH("Release of a suspended object");
104 return _dispatch_release(obj);
106 DISPATCH_CLIENT_CRASH("Over-release of an object");
110 _dispatch_dispose(dispatch_object_t dou)
112 struct dispatch_object_s *obj = DO_CAST(dou);
114 dispatch_queue_t tq = obj->do_targetq;
115 dispatch_function_t func = obj->do_finalizer;
116 void *ctxt = obj->do_ctxt;
118 obj->do_vtable = (struct dispatch_object_vtable_s *)0x200;
123 dispatch_async_f(tq, ctxt, func);
125 _dispatch_release(tq);
129 _dispatch_release(dispatch_object_t dou)
131 struct dispatch_object_s *obj = DO_CAST(dou);
135 if (obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
136 return; // global object
139 oldval = dispatch_atomic_dec(&obj->do_ref_cnt) + 1;
141 if (fastpath(oldval > 1)) {
145 if (obj->do_next != DISPATCH_OBJECT_LISTLESS) {
146 DISPATCH_CRASH("release while enqueued");
148 if (obj->do_xref_cnt) {
149 DISPATCH_CRASH("release while external references exist");
152 return dx_dispose(obj);
154 DISPATCH_CRASH("over-release");
158 dispatch_get_context(dispatch_object_t dou)
160 struct dispatch_object_s *obj = DO_CAST(dou);
166 dispatch_set_context(dispatch_object_t dou, void *context)
168 struct dispatch_object_s *obj = DO_CAST(dou);
170 if (obj->do_ref_cnt != DISPATCH_OBJECT_GLOBAL_REFCNT) {
171 obj->do_ctxt = context;
176 dispatch_set_finalizer_f(dispatch_object_t dou, dispatch_function_t finalizer)
178 struct dispatch_object_s *obj = DO_CAST(dou);
180 obj->do_finalizer = finalizer;
184 dispatch_suspend(dispatch_object_t dou)
186 struct dispatch_object_s *obj = DO_CAST(dou);
188 if (slowpath(obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
191 (void)dispatch_atomic_add(&obj->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL);
195 dispatch_resume(dispatch_object_t dou)
197 struct dispatch_object_s *obj = DO_CAST(dou);
199 // Global objects cannot be suspended or resumed. This also has the
200 // side effect of saturating the suspend count of an object and
201 // guarding against resuming due to overflow.
202 if (slowpath(obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
206 // Switch on the previous value of the suspend count. If the previous
207 // value was a single suspend interval, the object should be resumed.
208 // If the previous value was less than the suspend interval, the object
209 // has been over-resumed.
210 switch (dispatch_atomic_sub(&obj->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL) + DISPATCH_OBJECT_SUSPEND_INTERVAL) {
211 case DISPATCH_OBJECT_SUSPEND_INTERVAL:
212 _dispatch_wakeup(obj);
214 case DISPATCH_OBJECT_SUSPEND_LOCK:
216 DISPATCH_CLIENT_CRASH("Over-resume of an object");
224 dispatch_object_debug_attr(dispatch_object_t dou, char* buf, size_t bufsiz)
226 struct dispatch_object_s *obj = DO_CAST(dou);
228 return snprintf(buf, bufsiz, "refcnt = 0x%x, suspend_cnt = 0x%x, ",
229 obj->do_ref_cnt, obj->do_suspend_cnt);