2 * Copyright (c) 2008-2013 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 #pragma mark _os_object_t
27 _os_object_retain_count(_os_object_t obj
)
29 int xref_cnt
= obj
->os_obj_xref_cnt
;
30 if (slowpath(xref_cnt
== _OS_OBJECT_GLOBAL_REFCNT
)) {
31 return ULONG_MAX
; // global object
33 return (unsigned long)(xref_cnt
+ 1);
38 _os_object_retain_internal(_os_object_t obj
)
40 return _os_object_retain_internal_inline(obj
);
45 _os_object_release_internal(_os_object_t obj
)
47 return _os_object_release_internal_inline(obj
);
52 _os_object_retain(_os_object_t obj
)
54 int xref_cnt
= _os_object_xrefcnt_inc(obj
);
55 if (slowpath(xref_cnt
<= 0)) {
56 _OS_OBJECT_CLIENT_CRASH("Resurrection of an object");
63 _os_object_retain_with_resurrect(_os_object_t obj
)
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");
69 if (slowpath(xref_cnt
== 0)) {
70 _os_object_retain_internal(obj
);
77 _os_object_release(_os_object_t obj
)
79 int xref_cnt
= _os_object_xrefcnt_dec(obj
);
80 if (fastpath(xref_cnt
>= 0)) {
83 if (slowpath(xref_cnt
< -1)) {
84 _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
86 return _os_object_xref_dispose(obj
);
90 _os_object_retain_weak(_os_object_t obj
)
92 int xref_cnt
= obj
->os_obj_xref_cnt
;
93 if (slowpath(xref_cnt
== _OS_OBJECT_GLOBAL_REFCNT
)) {
94 return true; // global object
97 if (slowpath(xref_cnt
== -1)) {
100 if (slowpath(xref_cnt
< -1)) {
103 if (slowpath(!os_atomic_cmpxchgvw2o(obj
, os_obj_xref_cnt
, xref_cnt
,
104 xref_cnt
+ 1, &xref_cnt
, relaxed
))) {
109 _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
113 _os_object_allows_weak_reference(_os_object_t obj
)
115 int xref_cnt
= obj
->os_obj_xref_cnt
;
116 if (slowpath(xref_cnt
== -1)) {
119 if (slowpath(xref_cnt
< -1)) {
120 _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
126 #pragma mark dispatch_object_t
129 _dispatch_alloc(const void *vtable
, size_t size
)
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
;
138 return _os_object_alloc_realized(vtable
, size
);
143 dispatch_retain(dispatch_object_t dou
)
145 DISPATCH_OBJECT_TFB(_dispatch_objc_retain
, dou
);
146 (void)_os_object_retain(dou
._os_obj
);
150 dispatch_release(dispatch_object_t dou
)
152 DISPATCH_OBJECT_TFB(_dispatch_objc_release
, dou
);
153 _os_object_release(dou
._os_obj
);
157 _dispatch_dealloc(dispatch_object_t dou
)
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
;
166 _os_object_dealloc(dou
._os_obj
);
169 dispatch_async_f(tq
, ctxt
, func
);
171 _dispatch_release_tailcall(tq
);
176 _dispatch_xref_dispose(dispatch_object_t dou
)
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
);
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
);
187 return _dispatch_release_tailcall(dou
._os_obj
);
192 _dispatch_dispose(dispatch_object_t dou
)
194 if (slowpath(dou
._do
->do_next
!= DISPATCH_OBJECT_LISTLESS
)) {
195 DISPATCH_INTERNAL_CRASH(dou
._do
->do_next
, "Release while enqueued");
198 return _dispatch_dealloc(dou
);
202 dispatch_get_context(dispatch_object_t dou
)
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
))) {
209 return dou
._do
->do_ctxt
;
213 dispatch_set_context(dispatch_object_t dou
, void *context
)
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
))) {
220 dou
._do
->do_ctxt
= context
;
224 dispatch_set_finalizer_f(dispatch_object_t dou
, dispatch_function_t finalizer
)
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
))) {
231 dou
._do
->do_finalizer
= finalizer
;
235 dispatch_set_target_queue(dispatch_object_t dou
, dispatch_queue_t tq
)
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
))) {
243 tq
= _dispatch_get_root_queue(_DISPATCH_QOS_CLASS_DEFAULT
, false);
245 _dispatch_object_set_target_queue_inline(dou
._do
, tq
);
250 dispatch_activate(dispatch_object_t dou
)
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);
259 dispatch_suspend(dispatch_object_t dou
)
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
);
268 dispatch_resume(dispatch_object_t dou
)
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);
277 _dispatch_object_debug_attr(dispatch_object_t dou
, char* buf
, size_t bufsiz
)
279 return dsnprintf(buf
, bufsiz
, "xrefcnt = 0x%x, refcnt = 0x%x, ",
280 dou
._do
->do_xref_cnt
+ 1, dou
._do
->do_ref_cnt
+ 1);