2 * Copyright (c) 2008-2010 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
37 _os_object_retain_internal(_os_object_t obj
)
39 int ref_cnt
= obj
->os_obj_ref_cnt
;
40 if (slowpath(ref_cnt
== _OS_OBJECT_GLOBAL_REFCNT
)) {
41 return obj
; // global object
43 ref_cnt
= dispatch_atomic_inc2o(obj
, os_obj_ref_cnt
);
44 if (slowpath(ref_cnt
<= 0)) {
45 DISPATCH_CRASH("Resurrection of an object");
51 _os_object_release_internal(_os_object_t obj
)
53 int ref_cnt
= obj
->os_obj_ref_cnt
;
54 if (slowpath(ref_cnt
== _OS_OBJECT_GLOBAL_REFCNT
)) {
55 return; // global object
57 ref_cnt
= dispatch_atomic_dec2o(obj
, os_obj_ref_cnt
);
58 if (fastpath(ref_cnt
>= 0)) {
61 if (slowpath(ref_cnt
< -1)) {
62 DISPATCH_CRASH("Over-release of an object");
65 if (slowpath(obj
->os_obj_xref_cnt
>= 0)) {
66 DISPATCH_CRASH("Release while external references exist");
69 return _os_object_dispose(obj
);
73 _os_object_retain(_os_object_t obj
)
75 int xref_cnt
= obj
->os_obj_xref_cnt
;
76 if (slowpath(xref_cnt
== _OS_OBJECT_GLOBAL_REFCNT
)) {
77 return obj
; // global object
79 xref_cnt
= dispatch_atomic_inc2o(obj
, os_obj_xref_cnt
);
80 if (slowpath(xref_cnt
<= 0)) {
81 _OS_OBJECT_CLIENT_CRASH("Resurrection of an object");
87 _os_object_release(_os_object_t obj
)
89 int xref_cnt
= obj
->os_obj_xref_cnt
;
90 if (slowpath(xref_cnt
== _OS_OBJECT_GLOBAL_REFCNT
)) {
91 return; // global object
93 xref_cnt
= dispatch_atomic_dec2o(obj
, os_obj_xref_cnt
);
94 if (fastpath(xref_cnt
>= 0)) {
97 if (slowpath(xref_cnt
< -1)) {
98 _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
100 return _os_object_xref_dispose(obj
);
104 _os_object_retain_weak(_os_object_t obj
)
106 int xref_cnt
= obj
->os_obj_xref_cnt
;
107 if (slowpath(xref_cnt
== _OS_OBJECT_GLOBAL_REFCNT
)) {
108 return true; // global object
111 if (slowpath(xref_cnt
== -1)) {
114 if (slowpath(xref_cnt
< -1)) {
117 if (slowpath(!dispatch_atomic_cmpxchg2o(obj
, os_obj_xref_cnt
, xref_cnt
,
119 xref_cnt
= obj
->os_obj_xref_cnt
;
124 _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
128 _os_object_allows_weak_reference(_os_object_t obj
)
130 int xref_cnt
= obj
->os_obj_xref_cnt
;
131 if (slowpath(xref_cnt
== -1)) {
134 if (slowpath(xref_cnt
< -1)) {
135 _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
141 #pragma mark dispatch_object_t
144 _dispatch_alloc(const void *vtable
, size_t size
)
146 return _os_object_alloc(vtable
, size
);
150 dispatch_retain(dispatch_object_t dou
)
152 (void)_os_object_retain(dou
._os_obj
);
156 _dispatch_retain(dispatch_object_t dou
)
158 (void)_os_object_retain_internal(dou
._os_obj
);
162 dispatch_release(dispatch_object_t dou
)
164 _os_object_release(dou
._os_obj
);
168 _dispatch_release(dispatch_object_t dou
)
170 _os_object_release_internal(dou
._os_obj
);
174 _dispatch_dealloc(dispatch_object_t dou
)
176 dispatch_queue_t tq
= dou
._do
->do_targetq
;
177 dispatch_function_t func
= dou
._do
->do_finalizer
;
178 void *ctxt
= dou
._do
->do_ctxt
;
180 _os_object_dealloc(dou
._os_obj
);
183 dispatch_async_f(tq
, ctxt
, func
);
185 _dispatch_release(tq
);
189 _dispatch_xref_dispose(dispatch_object_t dou
)
191 if (slowpath(DISPATCH_OBJECT_SUSPENDED(dou
._do
))) {
192 // Arguments for and against this assert are within 6705399
193 DISPATCH_CLIENT_CRASH("Release of a suspended object");
196 if (dx_type(dou
._do
) == DISPATCH_SOURCE_KEVENT_TYPE
) {
197 _dispatch_source_xref_dispose(dou
._ds
);
199 return _dispatch_release(dou
._os_obj
);
204 _dispatch_dispose(dispatch_object_t dou
)
206 if (slowpath(dou
._do
->do_next
!= DISPATCH_OBJECT_LISTLESS
)) {
207 DISPATCH_CRASH("Release while enqueued");
210 return _dispatch_dealloc(dou
);
214 dispatch_get_context(dispatch_object_t dou
)
216 return dou
._do
->do_ctxt
;
220 dispatch_set_context(dispatch_object_t dou
, void *context
)
222 if (dou
._do
->do_ref_cnt
!= DISPATCH_OBJECT_GLOBAL_REFCNT
) {
223 dou
._do
->do_ctxt
= context
;
228 dispatch_set_finalizer_f(dispatch_object_t dou
, dispatch_function_t finalizer
)
230 dou
._do
->do_finalizer
= finalizer
;
234 dispatch_suspend(dispatch_object_t dou
)
236 if (slowpath(dou
._do
->do_ref_cnt
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) {
239 // rdar://8181908 explains why we need to do an internal retain at every
241 (void)dispatch_atomic_add2o(dou
._do
, do_suspend_cnt
,
242 DISPATCH_OBJECT_SUSPEND_INTERVAL
);
243 _dispatch_retain(dou
._do
);
248 _dispatch_resume_slow(dispatch_object_t dou
)
250 _dispatch_wakeup(dou
._do
);
251 // Balancing the retain() done in suspend() for rdar://8181908
252 _dispatch_release(dou
._do
);
256 dispatch_resume(dispatch_object_t dou
)
258 // Global objects cannot be suspended or resumed. This also has the
259 // side effect of saturating the suspend count of an object and
260 // guarding against resuming due to overflow.
261 if (slowpath(dou
._do
->do_ref_cnt
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) {
264 // Check the previous value of the suspend count. If the previous
265 // value was a single suspend interval, the object should be resumed.
266 // If the previous value was less than the suspend interval, the object
267 // has been over-resumed.
268 unsigned int suspend_cnt
= dispatch_atomic_sub2o(dou
._do
, do_suspend_cnt
,
269 DISPATCH_OBJECT_SUSPEND_INTERVAL
) +
270 DISPATCH_OBJECT_SUSPEND_INTERVAL
;
271 if (fastpath(suspend_cnt
> DISPATCH_OBJECT_SUSPEND_INTERVAL
)) {
272 // Balancing the retain() done in suspend() for rdar://8181908
273 return _dispatch_release(dou
._do
);
275 if (fastpath(suspend_cnt
== DISPATCH_OBJECT_SUSPEND_INTERVAL
)) {
276 return _dispatch_resume_slow(dou
);
278 DISPATCH_CLIENT_CRASH("Over-resume of an object");
282 _dispatch_object_debug_attr(dispatch_object_t dou
, char* buf
, size_t bufsiz
)
284 return snprintf(buf
, bufsiz
, "xrefcnt = 0x%x, refcnt = 0x%x, "
285 "suspend_cnt = 0x%x, locked = %d, ", dou
._do
->do_xref_cnt
+ 1,
286 dou
._do
->do_ref_cnt
+ 1,
287 dou
._do
->do_suspend_cnt
/ DISPATCH_OBJECT_SUSPEND_INTERVAL
,
288 dou
._do
->do_suspend_cnt
& 1);