Tizen 2.1 base
[platform/upstream/gcd.git] / dispatch-1.0 / src / object.c
1 /*
2  * Copyright (c) 2008-2009 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_debug(dispatch_object_t obj, const char *msg, ...)
25 {
26         va_list ap;
27
28         va_start(ap, msg);
29
30         dispatch_debugv(obj, msg, ap);
31
32         va_end(ap);
33 }
34
35 void
36 dispatch_debugv(dispatch_object_t dou, const char *msg, va_list ap)
37 {
38         char buf[4096];
39         size_t offs;
40
41         struct dispatch_object_s *obj = DO_CAST(dou);
42
43         if (obj && obj->do_vtable->do_debug) {
44                 offs = dx_debug(obj, buf, sizeof(buf));
45         } else {
46                 offs = snprintf(buf, sizeof(buf), "NULL vtable slot");
47         }
48
49         snprintf(buf + offs, sizeof(buf) - offs, ": %s", msg);
50
51         _dispatch_logv(buf, ap);
52 }
53
54 void
55 dispatch_retain(dispatch_object_t dou)
56 {
57         struct dispatch_object_s *obj = DO_CAST(dou);
58
59         if (obj->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
60                 return; // global object
61         }
62         if ((dispatch_atomic_inc(&obj->do_xref_cnt) - 1) == 0) {
63                 DISPATCH_CLIENT_CRASH("Resurrection of an object");
64         }
65 }
66
67 void
68 _dispatch_retain(dispatch_object_t dou)
69 {
70         struct dispatch_object_s *obj = DO_CAST(dou);
71
72         if (obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
73                 return; // global object
74         }
75         if ((dispatch_atomic_inc(&obj->do_ref_cnt) - 1) == 0) {
76                 DISPATCH_CLIENT_CRASH("Resurrection of an object");
77         }
78 }
79
80 void
81 dispatch_release(dispatch_object_t dou)
82 {
83         struct dispatch_object_s *obj = DO_CAST(dou);
84
85         unsigned int oldval;
86
87         if (obj->do_xref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
88                 return;
89         }
90
91         oldval = dispatch_atomic_dec(&obj->do_xref_cnt) + 1;
92         
93         if (fastpath(oldval > 1)) {
94                 return;
95         }
96         if (oldval == 1) {
97                 if ((uintptr_t)obj->do_vtable == (uintptr_t)&_dispatch_source_kevent_vtable) {
98                         return _dispatch_source_xref_release((dispatch_source_t)obj);
99                 }
100                 if (slowpath(DISPATCH_OBJECT_SUSPENDED(obj))) {
101                         // Arguments for and against this assert are within 6705399
102                         DISPATCH_CLIENT_CRASH("Release of a suspended object");
103                 }
104                 return _dispatch_release(obj);
105         }
106         DISPATCH_CLIENT_CRASH("Over-release of an object");
107 }
108
109 void
110 _dispatch_dispose(dispatch_object_t dou)
111 {
112         struct dispatch_object_s *obj = DO_CAST(dou);
113
114         dispatch_queue_t tq = obj->do_targetq;
115         dispatch_function_t func = obj->do_finalizer;
116         void *ctxt = obj->do_ctxt;
117
118         obj->do_vtable = (struct dispatch_object_vtable_s *)0x200;
119
120         free(obj);
121
122         if (func && ctxt) {
123                 dispatch_async_f(tq, ctxt, func);
124         }
125         _dispatch_release(tq);
126 }
127
128 void
129 _dispatch_release(dispatch_object_t dou)
130 {
131         struct dispatch_object_s *obj = DO_CAST(dou);
132
133         unsigned int oldval;
134
135         if (obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT) {
136                 return; // global object
137         }
138
139         oldval = dispatch_atomic_dec(&obj->do_ref_cnt) + 1;
140         
141         if (fastpath(oldval > 1)) {
142                 return;
143         }
144         if (oldval == 1) {
145                 if (obj->do_next != DISPATCH_OBJECT_LISTLESS) {
146                         DISPATCH_CRASH("release while enqueued");
147                 }
148                 if (obj->do_xref_cnt) {
149                         DISPATCH_CRASH("release while external references exist");
150                 }
151
152                 return dx_dispose(obj);
153         }
154         DISPATCH_CRASH("over-release");
155 }
156
157 void *
158 dispatch_get_context(dispatch_object_t dou)
159 {
160         struct dispatch_object_s *obj = DO_CAST(dou);
161
162         return obj->do_ctxt;
163 }
164
165 void
166 dispatch_set_context(dispatch_object_t dou, void *context)
167 {
168         struct dispatch_object_s *obj = DO_CAST(dou);
169
170         if (obj->do_ref_cnt != DISPATCH_OBJECT_GLOBAL_REFCNT) {
171                 obj->do_ctxt = context;
172         }
173 }
174
175 void
176 dispatch_set_finalizer_f(dispatch_object_t dou, dispatch_function_t finalizer)
177 {
178         struct dispatch_object_s *obj = DO_CAST(dou);
179
180         obj->do_finalizer = finalizer;
181 }
182
183 void
184 dispatch_suspend(dispatch_object_t dou)
185 {
186         struct dispatch_object_s *obj = DO_CAST(dou);
187
188         if (slowpath(obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
189                 return;
190         }
191         (void)dispatch_atomic_add(&obj->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL);
192 }
193
194 void
195 dispatch_resume(dispatch_object_t dou)
196 {
197         struct dispatch_object_s *obj = DO_CAST(dou);
198
199         // Global objects cannot be suspended or resumed. This also has the
200         // side effect of saturating the suspend count of an object and
201         // guarding against resuming due to overflow.
202         if (slowpath(obj->do_ref_cnt == DISPATCH_OBJECT_GLOBAL_REFCNT)) {
203                 return;
204         }
205
206         // Switch on the previous value of the suspend count.  If the previous
207         // value was a single suspend interval, the object should be resumed.
208         // If the previous value was less than the suspend interval, the object
209         // has been over-resumed.
210         switch (dispatch_atomic_sub(&obj->do_suspend_cnt, DISPATCH_OBJECT_SUSPEND_INTERVAL) + DISPATCH_OBJECT_SUSPEND_INTERVAL) {
211         case DISPATCH_OBJECT_SUSPEND_INTERVAL:
212                 _dispatch_wakeup(obj);
213                 break;
214         case DISPATCH_OBJECT_SUSPEND_LOCK:
215         case 0:
216                 DISPATCH_CLIENT_CRASH("Over-resume of an object");
217                 break;
218         default:
219                 break;
220         }
221 }
222
223 size_t
224 dispatch_object_debug_attr(dispatch_object_t dou, char* buf, size_t bufsiz)
225 {
226         struct dispatch_object_s *obj = DO_CAST(dou);
227
228         return snprintf(buf, bufsiz, "refcnt = 0x%x, suspend_cnt = 0x%x, ",
229                                         obj->do_ref_cnt, obj->do_suspend_cnt);
230 }