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