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 dispatch_retain(dispatch_object_t dou
)
26 if (slowpath(dou
._do
->do_xref_cnt
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) {
27 return; // global object
29 if (slowpath((dispatch_atomic_inc2o(dou
._do
, do_xref_cnt
) - 1) == 0)) {
30 DISPATCH_CLIENT_CRASH("Resurrection of an object");
35 _dispatch_retain(dispatch_object_t dou
)
37 if (slowpath(dou
._do
->do_ref_cnt
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) {
38 return; // global object
40 if (slowpath((dispatch_atomic_inc2o(dou
._do
, do_ref_cnt
) - 1) == 0)) {
41 DISPATCH_CLIENT_CRASH("Resurrection of an object");
46 dispatch_release(dispatch_object_t dou
)
48 if (slowpath(dou
._do
->do_xref_cnt
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) {
52 unsigned int xref_cnt
= dispatch_atomic_dec2o(dou
._do
, do_xref_cnt
) + 1;
53 if (fastpath(xref_cnt
> 1)) {
56 if (fastpath(xref_cnt
== 1)) {
57 if (dou
._do
->do_vtable
== (void*)&_dispatch_source_kevent_vtable
) {
58 return _dispatch_source_xref_release(dou
._ds
);
60 if (slowpath(DISPATCH_OBJECT_SUSPENDED(dou
._do
))) {
61 // Arguments for and against this assert are within 6705399
62 DISPATCH_CLIENT_CRASH("Release of a suspended object");
64 return _dispatch_release(dou
._do
);
66 DISPATCH_CLIENT_CRASH("Over-release of an object");
70 _dispatch_dispose(dispatch_object_t dou
)
72 dispatch_queue_t tq
= dou
._do
->do_targetq
;
73 dispatch_function_t func
= dou
._do
->do_finalizer
;
74 void *ctxt
= dou
._do
->do_ctxt
;
76 dou
._do
->do_vtable
= (void *)0x200;
81 dispatch_async_f(tq
, ctxt
, func
);
83 _dispatch_release(tq
);
87 _dispatch_release(dispatch_object_t dou
)
89 if (slowpath(dou
._do
->do_ref_cnt
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) {
90 return; // global object
93 unsigned int ref_cnt
= dispatch_atomic_dec2o(dou
._do
, do_ref_cnt
) + 1;
94 if (fastpath(ref_cnt
> 1)) {
97 if (fastpath(ref_cnt
== 1)) {
98 if (slowpath(dou
._do
->do_next
!= DISPATCH_OBJECT_LISTLESS
)) {
99 DISPATCH_CRASH("release while enqueued");
101 if (slowpath(dou
._do
->do_xref_cnt
)) {
102 DISPATCH_CRASH("release while external references exist");
104 return dx_dispose(dou
._do
);
106 DISPATCH_CRASH("over-release");
110 dispatch_get_context(dispatch_object_t dou
)
112 return dou
._do
->do_ctxt
;
116 dispatch_set_context(dispatch_object_t dou
, void *context
)
118 if (dou
._do
->do_ref_cnt
!= DISPATCH_OBJECT_GLOBAL_REFCNT
) {
119 dou
._do
->do_ctxt
= context
;
124 dispatch_set_finalizer_f(dispatch_object_t dou
, dispatch_function_t finalizer
)
126 dou
._do
->do_finalizer
= finalizer
;
130 dispatch_suspend(dispatch_object_t dou
)
132 if (slowpath(dou
._do
->do_ref_cnt
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) {
135 // rdar://8181908 explains why we need to do an internal retain at every
137 (void)dispatch_atomic_add2o(dou
._do
, do_suspend_cnt
,
138 DISPATCH_OBJECT_SUSPEND_INTERVAL
);
139 _dispatch_retain(dou
._do
);
144 _dispatch_resume_slow(dispatch_object_t dou
)
146 _dispatch_wakeup(dou
._do
);
147 // Balancing the retain() done in suspend() for rdar://8181908
148 _dispatch_release(dou
._do
);
152 dispatch_resume(dispatch_object_t dou
)
154 // Global objects cannot be suspended or resumed. This also has the
155 // side effect of saturating the suspend count of an object and
156 // guarding against resuming due to overflow.
157 if (slowpath(dou
._do
->do_ref_cnt
== DISPATCH_OBJECT_GLOBAL_REFCNT
)) {
160 // Check the previous value of the suspend count. If the previous
161 // value was a single suspend interval, the object should be resumed.
162 // If the previous value was less than the suspend interval, the object
163 // has been over-resumed.
164 unsigned int suspend_cnt
= dispatch_atomic_sub2o(dou
._do
, do_suspend_cnt
,
165 DISPATCH_OBJECT_SUSPEND_INTERVAL
) +
166 DISPATCH_OBJECT_SUSPEND_INTERVAL
;
167 if (fastpath(suspend_cnt
> DISPATCH_OBJECT_SUSPEND_INTERVAL
)) {
168 // Balancing the retain() done in suspend() for rdar://8181908
169 return _dispatch_release(dou
._do
);
171 if (fastpath(suspend_cnt
== DISPATCH_OBJECT_SUSPEND_INTERVAL
)) {
172 return _dispatch_resume_slow(dou
);
174 DISPATCH_CLIENT_CRASH("Over-resume of an object");
178 _dispatch_object_debug_attr(dispatch_object_t dou
, char* buf
, size_t bufsiz
)
180 return snprintf(buf
, bufsiz
, "xrefcnt = 0x%x, refcnt = 0x%x, "
181 "suspend_cnt = 0x%x, locked = %d, ", dou
._do
->do_xref_cnt
,
183 dou
._do
->do_suspend_cnt
/ DISPATCH_OBJECT_SUSPEND_INTERVAL
,
184 dou
._do
->do_suspend_cnt
& 1);