]> git.saurik.com Git - apple/libdispatch.git/blob - src/object.c
libdispatch-84.5.3.tar.gz
[apple/libdispatch.git] / src / object.c
1 /*
2 * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
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
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
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.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20
21 #include "internal.h"
22
23
24 void
25 dispatch_debug(dispatch_object_t dou, const char *msg, ...)
26 {
27 va_list ap;
28
29 va_start(ap, msg);
30
31 dispatch_debugv(dou._do, msg, ap);
32
33 va_end(ap);
34 }
35
36 void
37 dispatch_debugv(dispatch_object_t dou, const char *msg, va_list ap)
38 {
39 char buf[4096];
40 size_t offs;
41
42 if (dou._do && dou._do->do_vtable->do_debug) {
43 offs = dx_debug(dou._do, buf, sizeof(buf));
44 } else {
45 offs = snprintf(buf, sizeof(buf), "NULL vtable slot");
46 }
47
48 snprintf(buf + offs, sizeof(buf) - offs, ": %s", msg);
49
50 _dispatch_logv(buf, ap);
51 }
52
53 void
54 dispatch_retain(dispatch_object_t dou)
55 {
56 if (dou._do->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
57 return; // global object
58 }
59 if ((dispatch_atomic_inc(&dou._do->do_xref_cnt) - 1) == 0) {
60 DISPATCH_CLIENT_CRASH("Resurrection of an object");
61 }
62 }
63
64 void
65 _dispatch_retain(dispatch_object_t dou)
66 {
67 if (dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
68 return; // global object
69 }
70 if ((dispatch_atomic_inc(&dou._do->do_ref_cnt) - 1) == 0) {
71 DISPATCH_CLIENT_CRASH("Resurrection of an object");
72 }
73 }
74
75 void
76 dispatch_release(dispatch_object_t dou)
77 {
78 typeof(dou._do->do_xref_cnt) oldval;
79
80 if (dou._do->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
81 return;
82 }
83
84 oldval = dispatch_atomic_dec(&dou._do->do_xref_cnt) + 1;
85
86 if (fastpath(oldval > 1)) {
87 return;
88 }
89 if (oldval == 1) {
90 #ifndef DISPATCH_NO_LEGACY
91 if (dou._do->do_vtable == (void*)&_dispatch_source_kevent_vtable) {
92 return _dispatch_source_legacy_xref_release(dou._ds);
93 }
94 #endif
95 if (slowpath(DISPATCH_OBJECT_SUSPENDED(dou._do))) {
96 // Arguments for and against this assert are within 6705399
97 DISPATCH_CLIENT_CRASH("Release of a suspended object");
98 }
99 return _dispatch_release(dou._do);
100 }
101 DISPATCH_CLIENT_CRASH("Over-release of an object");
102 }
103
104 void
105 _dispatch_dispose(dispatch_object_t dou)
106 {
107 dispatch_queue_t tq = dou._do->do_targetq;
108 dispatch_function_t func = dou._do->do_finalizer;
109 void *ctxt = dou._do->do_ctxt;
110
111 dou._do->do_vtable = (void *)0x200;
112
113 free(dou._do);
114
115 if (func && ctxt) {
116 dispatch_async_f(tq, ctxt, func);
117 }
118 _dispatch_release(tq);
119 }
120
121 void
122 _dispatch_release(dispatch_object_t dou)
123 {
124 typeof(dou._do->do_ref_cnt) oldval;
125
126 if (dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
127 return; // global object
128 }
129
130 oldval = dispatch_atomic_dec(&dou._do->do_ref_cnt) + 1;
131
132 if (fastpath(oldval > 1)) {
133 return;
134 }
135 if (oldval == 1) {
136 if (dou._do->do_next != DISPATCH_OBJECT_LISTLESS) {
137 DISPATCH_CRASH("release while enqueued");
138 }
139 if (dou._do->do_xref_cnt) {
140 DISPATCH_CRASH("release while external references exist");
141 }
142
143 return dx_dispose(dou._do);
144 }
145 DISPATCH_CRASH("over-release");
146 }
147
148 void *
149 dispatch_get_context(dispatch_object_t dou)
150 {
151 return dou._do->do_ctxt;
152 }
153
154 void
155 dispatch_set_context(dispatch_object_t dou, void *context)
156 {
157 if (dou._do->do_ref_cnt != DISPATCH_OBJECT_GLOBAL_REFCNT) {
158 dou._do->do_ctxt = context;
159 }
160 }
161
162 void
163 dispatch_set_finalizer_f(dispatch_object_t dou, dispatch_function_t finalizer)
164 {
165 dou._do->do_finalizer = finalizer;
166 }
167
168 void
169 dispatch_suspend(dispatch_object_t dou)
170 {
171 if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
172 return;
173 }
174 dispatch_atomic_add(&dou._do->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL);
175 }
176
177 void
178 dispatch_resume(dispatch_object_t dou)
179 {
180 if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
181 return;
182 }
183 switch (dispatch_atomic_sub(&dou._do->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL) + DISPATCH_OBJECT_SUSPEND_INTERVAL) {
184 case DISPATCH_OBJECT_SUSPEND_INTERVAL:
185 _dispatch_wakeup(dou._do);
186 break;
187 case 0:
188 DISPATCH_CLIENT_CRASH("Over-resume of an object");
189 break;
190 default:
191 break;
192 }
193 }
194
195 size_t
196 dispatch_object_debug_attr(dispatch_object_t dou, char* buf, size_t bufsiz)
197 {
198 return snprintf(buf, bufsiz, "refcnt = 0x%x, suspend_cnt = 0x%x, ",
199 dou._do->do_ref_cnt, dou._do->do_suspend_cnt);
200 }