Projects
Wiki     Timeline     Browser     Search     New Ticket     Bug Reports

source: trunk/src/object.c @ 221

Revision 218, 7.2 KB checked in by dsteffen@…, 8 months ago (diff)

import El Capitan libdispatch-500.1.5 source drop

Line 
1/*
2 * Copyright (c) 2008-2013 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 (unsigned long)(xref_cnt + 1);
34}
35
36DISPATCH_NOINLINE
37_os_object_t
38_os_object_retain_internal(_os_object_t obj)
39{
40        return _os_object_retain_internal_inline(obj);
41}
42
43DISPATCH_NOINLINE
44void
45_os_object_release_internal(_os_object_t obj)
46{
47        return _os_object_release_internal_inline(obj);
48}
49
50DISPATCH_NOINLINE
51_os_object_t
52_os_object_retain(_os_object_t obj)
53{
54        int xref_cnt = _os_object_xrefcnt_inc(obj);
55        if (slowpath(xref_cnt <= 0)) {
56                _OS_OBJECT_CLIENT_CRASH("Resurrection of an object");
57        }
58        return obj;
59}
60
61DISPATCH_NOINLINE
62_os_object_t
63_os_object_retain_with_resurrect(_os_object_t obj)
64{
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");
68        }
69        if (slowpath(xref_cnt == 0)) {
70                _os_object_retain_internal(obj);
71        }
72        return obj;
73}
74
75DISPATCH_NOINLINE
76void
77_os_object_release(_os_object_t obj)
78{
79        int xref_cnt = _os_object_xrefcnt_dec(obj);
80        if (fastpath(xref_cnt >= 0)) {
81                return;
82        }
83        if (slowpath(xref_cnt < -1)) {
84                _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
85        }
86        return _os_object_xref_dispose(obj);
87}
88
89bool
90_os_object_retain_weak(_os_object_t obj)
91{
92        int xref_cnt = obj->os_obj_xref_cnt;
93        if (slowpath(xref_cnt == _OS_OBJECT_GLOBAL_REFCNT)) {
94                return true; // global object
95        }
96retry:
97        if (slowpath(xref_cnt == -1)) {
98                return false;
99        }
100        if (slowpath(xref_cnt < -1)) {
101                goto overrelease;
102        }
103        if (slowpath(!dispatch_atomic_cmpxchgvw2o(obj, os_obj_xref_cnt, xref_cnt,
104                        xref_cnt + 1, &xref_cnt, relaxed))) {
105                goto retry;
106        }
107        return true;
108overrelease:
109        _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
110}
111
112bool
113_os_object_allows_weak_reference(_os_object_t obj)
114{
115        int xref_cnt = obj->os_obj_xref_cnt;
116        if (slowpath(xref_cnt == -1)) {
117                return false;
118        }
119        if (slowpath(xref_cnt < -1)) {
120                _OS_OBJECT_CLIENT_CRASH("Over-release of an object");
121        }
122        return true;
123}
124
125#pragma mark -
126#pragma mark dispatch_object_t
127
128void *
129_dispatch_alloc(const void *vtable, size_t size)
130{
131        return _os_object_alloc_realized(vtable, size);
132}
133
134void
135dispatch_retain(dispatch_object_t dou)
136{
137        DISPATCH_OBJECT_TFB(_dispatch_objc_retain, dou);
138        (void)_os_object_retain(dou._os_obj);
139}
140
141void
142dispatch_release(dispatch_object_t dou)
143{
144        DISPATCH_OBJECT_TFB(_dispatch_objc_release, dou);
145        _os_object_release(dou._os_obj);
146}
147
148static void
149_dispatch_dealloc(dispatch_object_t dou)
150{
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;
154
155        _os_object_dealloc(dou._os_obj);
156
157        if (func && ctxt) {
158                dispatch_async_f(tq, ctxt, func);
159        }
160        _dispatch_release(tq);
161}
162
163void
164_dispatch_xref_dispose(dispatch_object_t dou)
165{
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");
169        }
170#if !USE_OBJC
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);
175        }
176        return _dispatch_release(dou._os_obj);
177#endif
178}
179
180void
181_dispatch_dispose(dispatch_object_t dou)
182{
183        if (slowpath(dou._do->do_next != DISPATCH_OBJECT_LISTLESS)) {
184                DISPATCH_CRASH("Release while enqueued");
185        }
186        dx_dispose(dou._do);
187        return _dispatch_dealloc(dou);
188}
189
190void *
191dispatch_get_context(dispatch_object_t dou)
192{
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)) {
196                return NULL;
197        }
198        return dou._do->do_ctxt;
199}
200
201void
202dispatch_set_context(dispatch_object_t dou, void *context)
203{
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)) {
207                return;
208        }
209        dou._do->do_ctxt = context;
210}
211
212void
213dispatch_set_finalizer_f(dispatch_object_t dou, dispatch_function_t finalizer)
214{
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)) {
218                return;
219        }
220        dou._do->do_finalizer = finalizer;
221}
222
223void
224dispatch_suspend(dispatch_object_t dou)
225{
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)) {
229                return;
230        }
231        // rdar://8181908 explains why we need to do an internal retain at every
232        // suspension.
233        (void)dispatch_atomic_add2o(dou._do, do_suspend_cnt,
234                        DISPATCH_OBJECT_SUSPEND_INTERVAL, acquire);
235        _dispatch_retain(dou._do);
236}
237
238DISPATCH_NOINLINE
239static void
240_dispatch_resume_slow(dispatch_object_t dou)
241{
242        _dispatch_wakeup(dou._do);
243        // Balancing the retain() done in suspend() for rdar://8181908
244        _dispatch_release(dou._do);
245}
246
247void
248dispatch_resume(dispatch_object_t dou)
249{
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)) {
256                return;
257        }
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);
267        }
268        if (fastpath(suspend_cnt == DISPATCH_OBJECT_SUSPEND_INTERVAL)) {
269                return _dispatch_resume_slow(dou);
270        }
271        DISPATCH_CLIENT_CRASH("Over-resume of an object");
272}
273
274size_t
275_dispatch_object_debug_attr(dispatch_object_t dou, char* buf, size_t bufsiz)
276{
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);
282}
Note: See TracBrowser for help on using the repository browser.