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 overreleased 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(!dispatch_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 return _os_object_alloc_realized(vtable
, size
);
135 dispatch_retain(dispatch_object_t dou
)
137 DISPATCH_OBJECT_TFB(_dispatch_objc_retain
, dou
);
138 (void)_os_object_retain(dou
._os_obj
);
142 dispatch_release(dispatch_object_t dou
)
144 DISPATCH_OBJECT_TFB(_dispatch_objc_release
, dou
);
145 _os_object_release(dou
._os_obj
);
149 _dispatch_dealloc(dispatch_object_t dou
)
151 dispatch_queue_t tq
= dou
._do
->do_targetq
;
152 dispatch_function_t func
= dou
._do
->do_finalizer
;
153 void *ctxt
= dou
._do
->do_ctxt
;
155 _os_object_dealloc(dou
._os_obj
);
158 dispatch_async_f(tq
, ctxt
, func
);
160 _dispatch_release(tq
);
164 _dispatch_xref_dispose(dispatch_object_t dou
)
166 if (slowpath(DISPATCH_OBJECT_SUSPENDED(dou
._do
))) {
167 // Arguments for and against this assert are within 6705399
168 DISPATCH_CLIENT_CRASH("Release of a suspended object");
171 if (dx_type(dou
._do
) == DISPATCH_SOURCE_KEVENT_TYPE
) {
172 _dispatch_source_xref_dispose(dou
._ds
);
173 } else if (dou
._dq
->do_vtable
== DISPATCH_VTABLE(queue_runloop
)) {
174 _dispatch_runloop_queue_xref_dispose(dou
._dq
);
176 return _dispatch_release(dou
._os_obj
);
181 _dispatch_dispose(dispatch_object_t dou
)
183 if (slowpath(dou
._do
->do_next
!= DISPATCH_OBJECT_LISTLESS
)) {
184 DISPATCH_CRASH("Release while enqueued");
187 return _dispatch_dealloc(dou
);
191 dispatch_get_context(dispatch_object_t dou
)
193 DISPATCH_OBJECT_TFB(_dispatch_objc_get_context
, dou
);
194 if (slowpath(dou
._do
->do_ref_cnt
== DISPATCH_OBJECT_GLOBAL_REFCNT
) ||
195 slowpath(dx_type(dou
._do
) == DISPATCH_QUEUE_ROOT_TYPE
)) {
198 return dou
._do
->do_ctxt
;
202 dispatch_set_context(dispatch_object_t dou
, void *context
)
204 DISPATCH_OBJECT_TFB(_dispatch_objc_set_context
, dou
, context
);
205 if (slowpath(dou
._do
->do_ref_cnt
== DISPATCH_OBJECT_GLOBAL_REFCNT
) ||
206 slowpath(dx_type(dou
._do
) == DISPATCH_QUEUE_ROOT_TYPE
)) {
209 dou
._do
->do_ctxt
= context
;
213 dispatch_set_finalizer_f(dispatch_object_t dou
, dispatch_function_t finalizer
)
215 DISPATCH_OBJECT_TFB(_dispatch_objc_set_finalizer_f
, dou
, finalizer
);
216 if (slowpath(dou
._do
->do_ref_cnt
== DISPATCH_OBJECT_GLOBAL_REFCNT
) ||
217 slowpath(dx_type(dou
._do
) == DISPATCH_QUEUE_ROOT_TYPE
)) {
220 dou
._do
->do_finalizer
= finalizer
;
224 dispatch_suspend(dispatch_object_t dou
)
226 DISPATCH_OBJECT_TFB(_dispatch_objc_suspend
, dou
);
227 if (slowpath(dou
._do
->do_ref_cnt
== DISPATCH_OBJECT_GLOBAL_REFCNT
) ||
228 slowpath(dx_type(dou
._do
) == DISPATCH_QUEUE_ROOT_TYPE
)) {
231 // rdar://8181908 explains why we need to do an internal retain at every
233 (void)dispatch_atomic_add2o(dou
._do
, do_suspend_cnt
,
234 DISPATCH_OBJECT_SUSPEND_INTERVAL
, acquire
);
235 _dispatch_retain(dou
._do
);
240 _dispatch_resume_slow(dispatch_object_t dou
)
242 _dispatch_wakeup(dou
._do
);
243 // Balancing the retain() done in suspend() for rdar://8181908
244 _dispatch_release(dou
._do
);
248 dispatch_resume(dispatch_object_t dou
)
250 DISPATCH_OBJECT_TFB(_dispatch_objc_resume
, dou
);
251 // Global objects cannot be suspended or resumed. This also has the
252 // side effect of saturating the suspend count of an object and
253 // guarding against resuming due to overflow.
254 if (slowpath(dou
._do
->do_ref_cnt
== DISPATCH_OBJECT_GLOBAL_REFCNT
) ||
255 slowpath(dx_type(dou
._do
) == DISPATCH_QUEUE_ROOT_TYPE
)) {
258 // Check the previous value of the suspend count. If the previous
259 // value was a single suspend interval, the object should be resumed.
260 // If the previous value was less than the suspend interval, the object
261 // has been over-resumed.
262 unsigned int suspend_cnt
= dispatch_atomic_sub_orig2o(dou
._do
,
263 do_suspend_cnt
, DISPATCH_OBJECT_SUSPEND_INTERVAL
, release
);
264 if (fastpath(suspend_cnt
> DISPATCH_OBJECT_SUSPEND_INTERVAL
)) {
265 // Balancing the retain() done in suspend() for rdar://8181908
266 return _dispatch_release(dou
._do
);
268 if (fastpath(suspend_cnt
== DISPATCH_OBJECT_SUSPEND_INTERVAL
)) {
269 return _dispatch_resume_slow(dou
);
271 DISPATCH_CLIENT_CRASH("Over-resume of an object");
275 _dispatch_object_debug_attr(dispatch_object_t dou
, char* buf
, size_t bufsiz
)
277 return dsnprintf(buf
, bufsiz
, "xrefcnt = 0x%x, refcnt = 0x%x, "
278 "suspend_cnt = 0x%x, locked = %d, ", dou
._do
->do_xref_cnt
+ 1,
279 dou
._do
->do_ref_cnt
+ 1,
280 dou
._do
->do_suspend_cnt
/ DISPATCH_OBJECT_SUSPEND_INTERVAL
,
281 dou
._do
->do_suspend_cnt
& 1);