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