]> git.saurik.com Git - apple/libdispatch.git/blob - src/object.c
libdispatch-703.30.5.tar.gz
[apple/libdispatch.git] / src / object.c
1 /*
2 * Copyright (c) 2008-2013 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 #pragma mark -
24 #pragma mark _os_object_t
25
26 unsigned long
27 _os_object_retain_count(_os_object_t obj)
28 {
29 int xref_cnt = obj->os_obj_xref_cnt;
30 if (slowpath(xref_cnt == _OS_OBJECT_GLOBAL_REFCNT)) {
31 return ULONG_MAX; // global object
32 }
33 return (unsigned long)(xref_cnt + 1);
34 }
35
36 DISPATCH_NOINLINE
37 _os_object_t
38 _os_object_retain_internal(_os_object_t obj)
39 {
40 return _os_object_retain_internal_inline(obj);
41 }
42
43 DISPATCH_NOINLINE
44 void
45 _os_object_release_internal(_os_object_t obj)
46 {
47 return _os_object_release_internal_inline(obj);
48 }
49
50 DISPATCH_NOINLINE
51 _os_object_t
52 _os_object_retain(_os_object_t obj)
53 {
54 int xref_cnt = _os_object_xrefcnt_inc(obj);
55 if (slowpath(xref_cnt <= 0)) {
56 _OS_OBJECT_CLIENT_CRASH("Resurrection of an object");
57 }
58 return obj;
59 }
60
61 DISPATCH_NOINLINE
62 _os_object_t
63 _os_object_retain_with_resurrect(_os_object_t obj)
64 {
65 int xref_cnt = _os_object_xrefcnt_inc(obj);
66 if (slowpath(xref_cnt < 0)) {
67 _OS_OBJECT_CLIENT_CRASH("Resurrection of an over-released object");
68 }
69 if (slowpath(xref_cnt == 0)) {
70 _os_object_retain_internal(obj);
71 }
72 return obj;
73 }
74
75 DISPATCH_NOINLINE
76 void
77 _os_object_release(_os_object_t obj)
78 {
79 int xref_cnt = _os_object_xrefcnt_dec(obj);
80 if (fastpath(xref_cnt >= 0)) {
81 return;
82 }
83 if (slowpath(xref_cnt < -1)) {
84 _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
85 }
86 return _os_object_xref_dispose(obj);
87 }
88
89 bool
90 _os_object_retain_weak(_os_object_t obj)
91 {
92 int xref_cnt = obj->os_obj_xref_cnt;
93 if (slowpath(xref_cnt == _OS_OBJECT_GLOBAL_REFCNT)) {
94 return true; // global object
95 }
96 retry:
97 if (slowpath(xref_cnt == -1)) {
98 return false;
99 }
100 if (slowpath(xref_cnt < -1)) {
101 goto overrelease;
102 }
103 if (slowpath(!os_atomic_cmpxchgvw2o(obj, os_obj_xref_cnt, xref_cnt,
104 xref_cnt + 1, &xref_cnt, relaxed))) {
105 goto retry;
106 }
107 return true;
108 overrelease:
109 _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
110 }
111
112 bool
113 _os_object_allows_weak_reference(_os_object_t obj)
114 {
115 int xref_cnt = obj->os_obj_xref_cnt;
116 if (slowpath(xref_cnt == -1)) {
117 return false;
118 }
119 if (slowpath(xref_cnt < -1)) {
120 _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
121 }
122 return true;
123 }
124
125 #pragma mark -
126 #pragma mark dispatch_object_t
127
128 void *
129 _dispatch_alloc(const void *vtable, size_t size)
130 {
131 #if OS_OBJECT_HAVE_OBJC1
132 const struct dispatch_object_vtable_s *_vtable = vtable;
133 dispatch_object_t dou;
134 dou._os_obj = _os_object_alloc_realized(_vtable->_os_obj_objc_isa, size);
135 dou._do->do_vtable = vtable;
136 return dou._do;
137 #else
138 return _os_object_alloc_realized(vtable, size);
139 #endif
140 }
141
142 void
143 dispatch_retain(dispatch_object_t dou)
144 {
145 DISPATCH_OBJECT_TFB(_dispatch_objc_retain, dou);
146 (void)_os_object_retain(dou._os_obj);
147 }
148
149 void
150 dispatch_release(dispatch_object_t dou)
151 {
152 DISPATCH_OBJECT_TFB(_dispatch_objc_release, dou);
153 _os_object_release(dou._os_obj);
154 }
155
156 static void
157 _dispatch_dealloc(dispatch_object_t dou)
158 {
159 dispatch_queue_t tq = dou._do->do_targetq;
160 dispatch_function_t func = dou._do->do_finalizer;
161 void *ctxt = dou._do->do_ctxt;
162 #if OS_OBJECT_HAVE_OBJC1
163 // so that ddt doesn't pick up bad objects when malloc reuses this memory
164 dou._do->do_vtable = NULL;
165 #endif
166 _os_object_dealloc(dou._os_obj);
167
168 if (func && ctxt) {
169 dispatch_async_f(tq, ctxt, func);
170 }
171 _dispatch_release_tailcall(tq);
172 }
173
174 #if !USE_OBJC
175 void
176 _dispatch_xref_dispose(dispatch_object_t dou)
177 {
178 unsigned long metatype = dx_metatype(dou._do);
179 if (metatype == _DISPATCH_QUEUE_TYPE || metatype == _DISPATCH_SOURCE_TYPE) {
180 _dispatch_queue_xref_dispose(dou._dq);
181 }
182 if (dx_type(dou._do) == DISPATCH_SOURCE_KEVENT_TYPE) {
183 _dispatch_source_xref_dispose(dou._ds);
184 } else if (dx_type(dou._do) == DISPATCH_QUEUE_RUNLOOP_TYPE) {
185 _dispatch_runloop_queue_xref_dispose(dou._dq);
186 }
187 return _dispatch_release_tailcall(dou._os_obj);
188 }
189 #endif
190
191 void
192 _dispatch_dispose(dispatch_object_t dou)
193 {
194 if (slowpath(dou._do->do_next != DISPATCH_OBJECT_LISTLESS)) {
195 DISPATCH_INTERNAL_CRASH(dou._do->do_next, "Release while enqueued");
196 }
197 dx_dispose(dou._do);
198 return _dispatch_dealloc(dou);
199 }
200
201 void *
202 dispatch_get_context(dispatch_object_t dou)
203 {
204 DISPATCH_OBJECT_TFB(_dispatch_objc_get_context, dou);
205 if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) ||
206 slowpath(dx_hastypeflag(dou._do, QUEUE_ROOT))) {
207 return NULL;
208 }
209 return dou._do->do_ctxt;
210 }
211
212 void
213 dispatch_set_context(dispatch_object_t dou, void *context)
214 {
215 DISPATCH_OBJECT_TFB(_dispatch_objc_set_context, dou, context);
216 if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) ||
217 slowpath(dx_hastypeflag(dou._do, QUEUE_ROOT))) {
218 return;
219 }
220 dou._do->do_ctxt = context;
221 }
222
223 void
224 dispatch_set_finalizer_f(dispatch_object_t dou, dispatch_function_t finalizer)
225 {
226 DISPATCH_OBJECT_TFB(_dispatch_objc_set_finalizer_f, dou, finalizer);
227 if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) ||
228 slowpath(dx_hastypeflag(dou._do, QUEUE_ROOT))) {
229 return;
230 }
231 dou._do->do_finalizer = finalizer;
232 }
233
234 void
235 dispatch_set_target_queue(dispatch_object_t dou, dispatch_queue_t tq)
236 {
237 DISPATCH_OBJECT_TFB(_dispatch_objc_set_target_queue, dou, tq);
238 if (dx_vtable(dou._do)->do_set_targetq) {
239 dx_vtable(dou._do)->do_set_targetq(dou._do, tq);
240 } else if (dou._do->do_ref_cnt != DISPATCH_OBJECT_GLOBAL_REFCNT &&
241 !slowpath(dx_hastypeflag(dou._do, QUEUE_ROOT))) {
242 if (slowpath(!tq)) {
243 tq = _dispatch_get_root_queue(_DISPATCH_QOS_CLASS_DEFAULT, false);
244 }
245 _dispatch_object_set_target_queue_inline(dou._do, tq);
246 }
247 }
248
249 void
250 dispatch_activate(dispatch_object_t dou)
251 {
252 DISPATCH_OBJECT_TFB(_dispatch_objc_activate, dou);
253 if (dx_vtable(dou._do)->do_resume) {
254 dx_vtable(dou._do)->do_resume(dou._do, true);
255 }
256 }
257
258 void
259 dispatch_suspend(dispatch_object_t dou)
260 {
261 DISPATCH_OBJECT_TFB(_dispatch_objc_suspend, dou);
262 if (dx_vtable(dou._do)->do_suspend) {
263 dx_vtable(dou._do)->do_suspend(dou._do);
264 }
265 }
266
267 void
268 dispatch_resume(dispatch_object_t dou)
269 {
270 DISPATCH_OBJECT_TFB(_dispatch_objc_resume, dou);
271 if (dx_vtable(dou._do)->do_resume) {
272 dx_vtable(dou._do)->do_resume(dou._do, false);
273 }
274 }
275
276 size_t
277 _dispatch_object_debug_attr(dispatch_object_t dou, char* buf, size_t bufsiz)
278 {
279 return dsnprintf(buf, bufsiz, "xrefcnt = 0x%x, refcnt = 0x%x, ",
280 dou._do->do_xref_cnt + 1, dou._do->do_ref_cnt + 1);
281 }