]> git.saurik.com Git - apple/libdispatch.git/blob - src/object.m
libdispatch-339.92.1.tar.gz
[apple/libdispatch.git] / src / object.m
1 /*
2 * Copyright (c) 2011-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 #if USE_OBJC
24
25 #if !__OBJC2__
26 #error "Cannot build with legacy ObjC runtime"
27 #endif
28 #if _OS_OBJECT_OBJC_ARC
29 #error "Cannot build with ARC"
30 #endif
31
32 #include <objc/objc-internal.h>
33 #include <objc/objc-exception.h>
34
35 #pragma mark -
36 #pragma mark _os_object_gc
37
38 #if __OBJC_GC__
39 #include <objc/objc-auto.h>
40 #include <auto_zone.h>
41
42 static bool _os_object_have_gc;
43 static malloc_zone_t *_os_object_gc_zone;
44
45 static void
46 _os_object_gc_init(void)
47 {
48 _os_object_have_gc = objc_collectingEnabled();
49 if (slowpath(_os_object_have_gc)) {
50 _os_object_gc_zone = objc_collectableZone();
51 }
52 }
53
54 static _os_object_t
55 _os_object_make_uncollectable(_os_object_t obj)
56 {
57 if (slowpath(_os_object_have_gc)) {
58 auto_zone_retain(_os_object_gc_zone, obj);
59 }
60 return obj;
61 }
62
63 static _os_object_t
64 _os_object_make_collectable(_os_object_t obj)
65 {
66 if (slowpath(_os_object_have_gc)) {
67 auto_zone_release(_os_object_gc_zone, obj);
68 }
69 return obj;
70 }
71
72 #define _os_objc_gc_retain(obj) \
73 if (slowpath(_os_object_have_gc)) { \
74 return auto_zone_retain(_os_object_gc_zone, obj); \
75 }
76
77 #define _os_objc_gc_release(obj) \
78 if (slowpath(_os_object_have_gc)) { \
79 return (void)auto_zone_release(_os_object_gc_zone, obj); \
80 }
81
82 #else // __OBJC_GC__
83 #define _os_object_gc_init()
84 #define _os_object_make_uncollectable(obj) (obj)
85 #define _os_object_make_collectable(obj) (obj)
86 #define _os_objc_gc_retain(obj)
87 #define _os_objc_gc_release(obj)
88 #endif // __OBJC_GC__
89
90 #pragma mark -
91 #pragma mark _os_object_t
92
93 static inline id
94 _os_objc_alloc(Class cls, size_t size)
95 {
96 id obj;
97 size -= sizeof(((struct _os_object_s *)NULL)->os_obj_isa);
98 while (!fastpath(obj = class_createInstance(cls, size))) {
99 _dispatch_temporary_resource_shortage();
100 }
101 return obj;
102 }
103
104 void
105 _os_object_init(void)
106 {
107 _objc_init();
108 _os_object_gc_init();
109 }
110
111 _os_object_t
112 _os_object_alloc_realized(const void *cls, size_t size)
113 {
114 dispatch_assert(size >= sizeof(struct _os_object_s));
115 return _os_object_make_uncollectable(_os_objc_alloc(cls, size));
116 }
117
118 _os_object_t
119 _os_object_alloc(const void *_cls, size_t size)
120 {
121 dispatch_assert(size >= sizeof(struct _os_object_s));
122 Class cls = _cls ? [(id)_cls class] : [OS_OBJECT_CLASS(object) class];
123 return _os_object_make_uncollectable(_os_objc_alloc(cls, size));
124 }
125
126 void
127 _os_object_dealloc(_os_object_t obj)
128 {
129 [_os_object_make_collectable(obj) dealloc];
130 }
131
132 void
133 _os_object_xref_dispose(_os_object_t obj)
134 {
135 [obj _xref_dispose];
136 }
137
138 void
139 _os_object_dispose(_os_object_t obj)
140 {
141 [obj _dispose];
142 }
143
144 #pragma mark -
145 #pragma mark _os_object
146
147 @implementation OS_OBJECT_CLASS(object)
148
149 -(id)retain {
150 return _os_object_retain(self);
151 }
152
153 -(oneway void)release {
154 return _os_object_release(self);
155 }
156
157 -(NSUInteger)retainCount {
158 return _os_object_retain_count(self);
159 }
160
161 -(BOOL)retainWeakReference {
162 return _os_object_retain_weak(self);
163 }
164
165 -(BOOL)allowsWeakReference {
166 return _os_object_allows_weak_reference(self);
167 }
168
169 - (void)_xref_dispose {
170 return _os_object_release_internal(self);
171 }
172
173 - (void)_dispose {
174 return _os_object_dealloc(self);
175 }
176
177 @end
178
179 #pragma mark -
180 #pragma mark _dispatch_objc
181
182 #include <Foundation/NSString.h>
183
184 id
185 _dispatch_objc_alloc(Class cls, size_t size)
186 {
187 return _os_objc_alloc(cls, size);
188 }
189
190 void
191 _dispatch_objc_retain(dispatch_object_t dou)
192 {
193 _os_objc_gc_retain(dou);
194 return (void)[dou retain];
195 }
196
197 void
198 _dispatch_objc_release(dispatch_object_t dou)
199 {
200 _os_objc_gc_release(dou);
201 return [dou release];
202 }
203
204 void
205 _dispatch_objc_set_context(dispatch_object_t dou, void *context)
206 {
207 return [dou _setContext:context];
208 }
209
210 void *
211 _dispatch_objc_get_context(dispatch_object_t dou)
212 {
213 return [dou _getContext];
214 }
215
216 void
217 _dispatch_objc_set_finalizer_f(dispatch_object_t dou,
218 dispatch_function_t finalizer)
219 {
220 return [dou _setFinalizer:finalizer];
221 }
222
223 void
224 _dispatch_objc_set_target_queue(dispatch_object_t dou, dispatch_queue_t queue)
225 {
226 return [dou _setTargetQueue:queue];
227 }
228
229 void
230 _dispatch_objc_suspend(dispatch_object_t dou)
231 {
232 return [dou _suspend];
233 }
234
235 void
236 _dispatch_objc_resume(dispatch_object_t dou)
237 {
238 return [dou _resume];
239 }
240
241 size_t
242 _dispatch_objc_debug(dispatch_object_t dou, char* buf, size_t bufsiz)
243 {
244 NSUInteger offset = 0;
245 NSString *desc = [dou debugDescription];
246 [desc getBytes:buf maxLength:bufsiz-1 usedLength:&offset
247 encoding:NSUTF8StringEncoding options:0
248 range:NSMakeRange(0, [desc length]) remainingRange:NULL];
249 if (offset) buf[offset] = 0;
250 return offset;
251 }
252
253 #pragma mark -
254 #pragma mark _dispatch_object
255
256 // Force non-lazy class realization rdar://10640168
257 #define DISPATCH_OBJC_LOAD() + (void)load {}
258
259 @implementation DISPATCH_CLASS(object)
260
261 - (id)init {
262 self = [super init];
263 [self release];
264 self = nil;
265 return self;
266 }
267
268 - (void)_xref_dispose {
269 _dispatch_xref_dispose(self);
270 [super _xref_dispose];
271 }
272
273 - (void)_dispose {
274 return _dispatch_dispose(self); // calls _os_object_dealloc()
275 }
276
277 - (NSString *)debugDescription {
278 Class nsstring = objc_lookUpClass("NSString");
279 if (!nsstring) return nil;
280 char buf[2048];
281 struct dispatch_object_s *obj = (struct dispatch_object_s *)self;
282 if (obj->do_vtable->do_debug) {
283 dx_debug(obj, buf, sizeof(buf));
284 } else {
285 strlcpy(buf, dx_kind(obj), sizeof(buf));
286 }
287 return [nsstring stringWithFormat:
288 [nsstring stringWithUTF8String:"<%s: %s>"],
289 class_getName([self class]), buf];
290 }
291
292 @end
293
294 @implementation DISPATCH_CLASS(queue)
295 DISPATCH_OBJC_LOAD()
296
297 - (NSString *)description {
298 Class nsstring = objc_lookUpClass("NSString");
299 if (!nsstring) return nil;
300 return [nsstring stringWithFormat:
301 [nsstring stringWithUTF8String:"<%s: %s[%p]>"],
302 class_getName([self class]), dispatch_queue_get_label(self), self];
303 }
304
305 @end
306
307 @implementation DISPATCH_CLASS(source)
308 DISPATCH_OBJC_LOAD()
309
310 - (void)_xref_dispose {
311 _dispatch_source_xref_dispose(self);
312 [super _xref_dispose];
313 }
314
315 @end
316
317 @implementation DISPATCH_CLASS(queue_runloop)
318 DISPATCH_OBJC_LOAD()
319
320 - (void)_xref_dispose {
321 _dispatch_runloop_queue_xref_dispose(self);
322 [super _xref_dispose];
323 }
324
325 @end
326
327 #define DISPATCH_CLASS_IMPL(name) \
328 @implementation DISPATCH_CLASS(name) \
329 DISPATCH_OBJC_LOAD() \
330 @end
331
332 DISPATCH_CLASS_IMPL(semaphore)
333 DISPATCH_CLASS_IMPL(group)
334 DISPATCH_CLASS_IMPL(queue_root)
335 DISPATCH_CLASS_IMPL(queue_mgr)
336 DISPATCH_CLASS_IMPL(queue_specific_queue)
337 DISPATCH_CLASS_IMPL(queue_attr)
338 DISPATCH_CLASS_IMPL(mach)
339 DISPATCH_CLASS_IMPL(mach_msg)
340 DISPATCH_CLASS_IMPL(io)
341 DISPATCH_CLASS_IMPL(operation)
342 DISPATCH_CLASS_IMPL(disk)
343
344 #pragma mark -
345 #pragma mark dispatch_autorelease_pool
346
347 #if DISPATCH_COCOA_COMPAT
348
349 void *
350 _dispatch_autorelease_pool_push(void) {
351 return objc_autoreleasePoolPush();
352 }
353
354 void
355 _dispatch_autorelease_pool_pop(void *context) {
356 return objc_autoreleasePoolPop(context);
357 }
358
359 #endif // DISPATCH_COCOA_COMPAT
360
361 #pragma mark -
362 #pragma mark dispatch_client_callout
363
364 // Abort on uncaught exceptions thrown from client callouts rdar://8577499
365 #if DISPATCH_USE_CLIENT_CALLOUT && !__arm__
366 // On platforms with zero-cost exceptions, use a compiler-generated catch-all
367 // exception handler.
368
369 DISPATCH_NORETURN extern void objc_terminate(void);
370
371 #undef _dispatch_client_callout
372 void
373 _dispatch_client_callout(void *ctxt, dispatch_function_t f)
374 {
375 @try {
376 return f(ctxt);
377 }
378 @catch (...) {
379 objc_terminate();
380 }
381 }
382
383 #undef _dispatch_client_callout2
384 void
385 _dispatch_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t))
386 {
387 @try {
388 return f(ctxt, i);
389 }
390 @catch (...) {
391 objc_terminate();
392 }
393 }
394
395 #undef _dispatch_client_callout3
396 bool
397 _dispatch_client_callout3(void *ctxt, dispatch_data_t region, size_t offset,
398 const void *buffer, size_t size, dispatch_data_applier_function_t f)
399 {
400 @try {
401 return f(ctxt, region, offset, buffer, size);
402 }
403 @catch (...) {
404 objc_terminate();
405 }
406 }
407
408 #undef _dispatch_client_callout4
409 void
410 _dispatch_client_callout4(void *ctxt, dispatch_mach_reason_t reason,
411 dispatch_mach_msg_t dmsg, mach_error_t error,
412 dispatch_mach_handler_function_t f)
413 {
414 @try {
415 return f(ctxt, reason, dmsg, error);
416 }
417 @catch (...) {
418 objc_terminate();
419 }
420 }
421
422 #endif // DISPATCH_USE_CLIENT_CALLOUT
423
424 #endif // USE_OBJC