Projects
Wiki     Timeline     Browser     Search     New Ticket     Bug Reports

source: trunk/src/object.c @ 215

Revision 212, 6.9 KB checked in by dsteffen@…, 21 months ago (diff)

import MountainLion? libdispatch-228.18 source drop

Line 
1/*
2 * Copyright (c) 2008-2010 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
26unsigned 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 xref_cnt + 1;
34}
35
36_os_object_t
37_os_object_retain_internal(_os_object_t obj)
38{
39        int ref_cnt = obj->os_obj_ref_cnt;
40        if (slowpath(ref_cnt == _OS_OBJECT_GLOBAL_REFCNT)) {
41                return obj; // global object
42        }
43        ref_cnt = dispatch_atomic_inc2o(obj, os_obj_ref_cnt);
44        if (slowpath(ref_cnt <= 0)) {
45                DISPATCH_CRASH("Resurrection of an object");
46        }
47        return obj;
48}
49
50void
51_os_object_release_internal(_os_object_t obj)
52{
53        int ref_cnt = obj->os_obj_ref_cnt;
54        if (slowpath(ref_cnt == _OS_OBJECT_GLOBAL_REFCNT)) {
55                return; // global object
56        }
57        ref_cnt = dispatch_atomic_dec2o(obj, os_obj_ref_cnt);
58        if (fastpath(ref_cnt >= 0)) {
59                return;
60        }
61        if (slowpath(ref_cnt < -1)) {
62                DISPATCH_CRASH("Over-release of an object");
63        }
64#if DISPATCH_DEBUG
65        if (slowpath(obj->os_obj_xref_cnt >= 0)) {
66                DISPATCH_CRASH("Release while external references exist");
67        }
68#endif
69        return _os_object_dispose(obj);
70}
71
72_os_object_t
73_os_object_retain(_os_object_t obj)
74{
75        int xref_cnt = obj->os_obj_xref_cnt;
76        if (slowpath(xref_cnt == _OS_OBJECT_GLOBAL_REFCNT)) {
77                return obj; // global object
78        }
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");
82        }
83        return obj;
84}
85
86void
87_os_object_release(_os_object_t obj)
88{
89        int xref_cnt = obj->os_obj_xref_cnt;
90        if (slowpath(xref_cnt == _OS_OBJECT_GLOBAL_REFCNT)) {
91                return; // global object
92        }
93        xref_cnt = dispatch_atomic_dec2o(obj, os_obj_xref_cnt);
94        if (fastpath(xref_cnt >= 0)) {
95                return;
96        }
97        if (slowpath(xref_cnt < -1)) {
98                _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
99        }
100        return _os_object_xref_dispose(obj);
101}
102
103bool
104_os_object_retain_weak(_os_object_t obj)
105{
106        int xref_cnt = obj->os_obj_xref_cnt;
107        if (slowpath(xref_cnt == _OS_OBJECT_GLOBAL_REFCNT)) {
108                return true; // global object
109        }
110retry:
111        if (slowpath(xref_cnt == -1)) {
112                return false;
113        }
114        if (slowpath(xref_cnt < -1)) {
115                goto overrelease;
116        }
117        if (slowpath(!dispatch_atomic_cmpxchg2o(obj, os_obj_xref_cnt, xref_cnt,
118                        xref_cnt + 1))) {
119                xref_cnt = obj->os_obj_xref_cnt;
120                goto retry;
121        }
122        return true;
123overrelease:
124        _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
125}
126
127bool
128_os_object_allows_weak_reference(_os_object_t obj)
129{
130        int xref_cnt = obj->os_obj_xref_cnt;
131        if (slowpath(xref_cnt == -1)) {
132                return false;
133        }
134        if (slowpath(xref_cnt < -1)) {
135                _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
136        }
137        return true;
138}
139
140#pragma mark -
141#pragma mark dispatch_object_t
142
143void *
144_dispatch_alloc(const void *vtable, size_t size)
145{
146        return _os_object_alloc(vtable, size);
147}
148
149void
150dispatch_retain(dispatch_object_t dou)
151{
152        (void)_os_object_retain(dou._os_obj);
153}
154
155void
156_dispatch_retain(dispatch_object_t dou)
157{
158        (void)_os_object_retain_internal(dou._os_obj);
159}
160
161void
162dispatch_release(dispatch_object_t dou)
163{
164        _os_object_release(dou._os_obj);
165}
166
167void
168_dispatch_release(dispatch_object_t dou)
169{
170        _os_object_release_internal(dou._os_obj);
171}
172
173static void
174_dispatch_dealloc(dispatch_object_t dou)
175{
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;
179
180        _os_object_dealloc(dou._os_obj);
181
182        if (func && ctxt) {
183                dispatch_async_f(tq, ctxt, func);
184        }
185        _dispatch_release(tq);
186}
187
188void
189_dispatch_xref_dispose(dispatch_object_t dou)
190{
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");
194        }
195#if !USE_OBJC
196        if (dx_type(dou._do) == DISPATCH_SOURCE_KEVENT_TYPE) {
197                _dispatch_source_xref_dispose(dou._ds);
198        }
199        return _dispatch_release(dou._os_obj);
200#endif
201}
202
203void
204_dispatch_dispose(dispatch_object_t dou)
205{
206        if (slowpath(dou._do->do_next != DISPATCH_OBJECT_LISTLESS)) {
207                DISPATCH_CRASH("Release while enqueued");
208        }
209        dx_dispose(dou._do);
210        return _dispatch_dealloc(dou);
211}
212
213void *
214dispatch_get_context(dispatch_object_t dou)
215{
216        return dou._do->do_ctxt;
217}
218
219void
220dispatch_set_context(dispatch_object_t dou, void *context)
221{
222        if (dou._do->do_ref_cnt != DISPATCH_OBJECT_GLOBAL_REFCNT) {
223                dou._do->do_ctxt = context;
224        }
225}
226
227void
228dispatch_set_finalizer_f(dispatch_object_t dou, dispatch_function_t finalizer)
229{
230        dou._do->do_finalizer = finalizer;
231}
232
233void
234dispatch_suspend(dispatch_object_t dou)
235{
236        if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
237                return;
238        }
239        // rdar://8181908 explains why we need to do an internal retain at every
240        // suspension.
241        (void)dispatch_atomic_add2o(dou._do, do_suspend_cnt,
242                        DISPATCH_OBJECT_SUSPEND_INTERVAL);
243        _dispatch_retain(dou._do);
244}
245
246DISPATCH_NOINLINE
247static void
248_dispatch_resume_slow(dispatch_object_t dou)
249{
250        _dispatch_wakeup(dou._do);
251        // Balancing the retain() done in suspend() for rdar://8181908
252        _dispatch_release(dou._do);
253}
254
255void
256dispatch_resume(dispatch_object_t dou)
257{
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)) {
262                return;
263        }
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);
274        }
275        if (fastpath(suspend_cnt == DISPATCH_OBJECT_SUSPEND_INTERVAL)) {
276                return _dispatch_resume_slow(dou);
277        }
278        DISPATCH_CLIENT_CRASH("Over-resume of an object");
279}
280
281size_t
282_dispatch_object_debug_attr(dispatch_object_t dou, char* buf, size_t bufsiz)
283{
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);
289}
Note: See TracBrowser for help on using the repository browser.