]> git.saurik.com Git - apple/libdispatch.git/blob - src/object.c
libdispatch-187.9.tar.gz
[apple/libdispatch.git] / src / object.c
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 void
24 dispatch_retain(dispatch_object_t dou)
25 {
26 if (slowpath(dou._do->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
27 return; // global object
28 }
29 if (slowpath((dispatch_atomic_inc2o(dou._do, do_xref_cnt) - 1) == 0)) {
30 DISPATCH_CLIENT_CRASH("Resurrection of an object");
31 }
32 }
33
34 void
35 _dispatch_retain(dispatch_object_t dou)
36 {
37 if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
38 return; // global object
39 }
40 if (slowpath((dispatch_atomic_inc2o(dou._do, do_ref_cnt) - 1) == 0)) {
41 DISPATCH_CLIENT_CRASH("Resurrection of an object");
42 }
43 }
44
45 void
46 dispatch_release(dispatch_object_t dou)
47 {
48 if (slowpath(dou._do->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
49 return;
50 }
51
52 unsigned int xref_cnt = dispatch_atomic_dec2o(dou._do, do_xref_cnt) + 1;
53 if (fastpath(xref_cnt > 1)) {
54 return;
55 }
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);
59 }
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");
63 }
64 return _dispatch_release(dou._do);
65 }
66 DISPATCH_CLIENT_CRASH("Over-release of an object");
67 }
68
69 void
70 _dispatch_dispose(dispatch_object_t dou)
71 {
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;
75
76 dou._do->do_vtable = (void *)0x200;
77
78 free(dou._do);
79
80 if (func && ctxt) {
81 dispatch_async_f(tq, ctxt, func);
82 }
83 _dispatch_release(tq);
84 }
85
86 void
87 _dispatch_release(dispatch_object_t dou)
88 {
89 if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
90 return; // global object
91 }
92
93 unsigned int ref_cnt = dispatch_atomic_dec2o(dou._do, do_ref_cnt) + 1;
94 if (fastpath(ref_cnt > 1)) {
95 return;
96 }
97 if (fastpath(ref_cnt == 1)) {
98 if (slowpath(dou._do->do_next != DISPATCH_OBJECT_LISTLESS)) {
99 DISPATCH_CRASH("release while enqueued");
100 }
101 if (slowpath(dou._do->do_xref_cnt)) {
102 DISPATCH_CRASH("release while external references exist");
103 }
104 return dx_dispose(dou._do);
105 }
106 DISPATCH_CRASH("over-release");
107 }
108
109 void *
110 dispatch_get_context(dispatch_object_t dou)
111 {
112 return dou._do->do_ctxt;
113 }
114
115 void
116 dispatch_set_context(dispatch_object_t dou, void *context)
117 {
118 if (dou._do->do_ref_cnt != DISPATCH_OBJECT_GLOBAL_REFCNT) {
119 dou._do->do_ctxt = context;
120 }
121 }
122
123 void
124 dispatch_set_finalizer_f(dispatch_object_t dou, dispatch_function_t finalizer)
125 {
126 dou._do->do_finalizer = finalizer;
127 }
128
129 void
130 dispatch_suspend(dispatch_object_t dou)
131 {
132 if (slowpath(dou._do->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
133 return;
134 }
135 // rdar://8181908 explains why we need to do an internal retain at every
136 // suspension.
137 (void)dispatch_atomic_add2o(dou._do, do_suspend_cnt,
138 DISPATCH_OBJECT_SUSPEND_INTERVAL);
139 _dispatch_retain(dou._do);
140 }
141
142 DISPATCH_NOINLINE
143 static void
144 _dispatch_resume_slow(dispatch_object_t dou)
145 {
146 _dispatch_wakeup(dou._do);
147 // Balancing the retain() done in suspend() for rdar://8181908
148 _dispatch_release(dou._do);
149 }
150
151 void
152 dispatch_resume(dispatch_object_t dou)
153 {
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)) {
158 return;
159 }
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);
170 }
171 if (fastpath(suspend_cnt == DISPATCH_OBJECT_SUSPEND_INTERVAL)) {
172 return _dispatch_resume_slow(dou);
173 }
174 DISPATCH_CLIENT_CRASH("Over-resume of an object");
175 }
176
177 size_t
178 _dispatch_object_debug_attr(dispatch_object_t dou, char* buf, size_t bufsiz)
179 {
180 return snprintf(buf, bufsiz, "xrefcnt = 0x%x, refcnt = 0x%x, "
181 "suspend_cnt = 0x%x, locked = %d, ", dou._do->do_xref_cnt,
182 dou._do->do_ref_cnt,
183 dou._do->do_suspend_cnt / DISPATCH_OBJECT_SUSPEND_INTERVAL,
184 dou._do->do_suspend_cnt & 1);
185 }
186