X-Git-Url: https://git.saurik.com/apple/libdispatch.git/blobdiff_plain/66adbf37b24d7fc6671f00f587979f1b51531d48..c093abd6701fa4c95f99104066f1f80a1c3c39e0:/src/object.m diff --git a/src/object.m b/src/object.m new file mode 100644 index 0000000..ea69622 --- /dev/null +++ b/src/object.m @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +#include "internal.h" + +#if USE_OBJC + +#if !__OBJC2__ +#error "Cannot build with legacy ObjC runtime" +#endif +#if _OS_OBJECT_OBJC_ARC +#error "Cannot build with ARC" +#endif + +#include +#include +#include + +#pragma mark - +#pragma mark _os_object_gc + +#if __OBJC_GC__ +#include +#include + +static dispatch_once_t _os_object_gc_pred; +static bool _os_object_have_gc; +static malloc_zone_t *_os_object_gc_zone; + +static void +_os_object_gc_init(void *ctxt DISPATCH_UNUSED) +{ + _os_object_have_gc = objc_collectingEnabled(); + if (slowpath(_os_object_have_gc)) { + _os_object_gc_zone = objc_collectableZone(); + } +} + +static _os_object_t +_os_object_make_uncollectable(_os_object_t obj) +{ + dispatch_once_f(&_os_object_gc_pred, NULL, _os_object_gc_init); + if (slowpath(_os_object_have_gc)) { + auto_zone_retain(_os_object_gc_zone, obj); + } + return obj; +} + +static _os_object_t +_os_object_make_collectable(_os_object_t obj) +{ + dispatch_once_f(&_os_object_gc_pred, NULL, _os_object_gc_init); + if (slowpath(_os_object_have_gc)) { + auto_zone_release(_os_object_gc_zone, obj); + } + return obj; +} +#else +#define _os_object_make_uncollectable(obj) (obj) +#define _os_object_make_collectable(obj) (obj) +#endif // __OBJC_GC__ + +#pragma mark - +#pragma mark _os_object_t + +void +_os_object_init(void) +{ + return _objc_init(); +} + +_os_object_t +_os_object_alloc(const void *_cls, size_t size) +{ + Class cls = _cls; + _os_object_t obj; + dispatch_assert(size >= sizeof(struct _os_object_s)); + size -= sizeof(((struct _os_object_s *)NULL)->os_obj_isa); + if (!cls) cls = [OS_OBJECT_CLASS(object) class]; + while (!fastpath(obj = class_createInstance(cls, size))) { + sleep(1); // Temporary resource shortage + } + return _os_object_make_uncollectable(obj); +} + +void +_os_object_dealloc(_os_object_t obj) +{ + [_os_object_make_collectable(obj) dealloc]; +} + +void +_os_object_xref_dispose(_os_object_t obj) +{ + [obj _xref_dispose]; +} + +void +_os_object_dispose(_os_object_t obj) +{ + [obj _dispose]; +} + +#pragma mark - +#pragma mark _os_object + +@implementation OS_OBJECT_CLASS(object) + +-(id)retain { + return _os_object_retain(self); +} + +-(oneway void)release { + return _os_object_release(self); +} + +-(NSUInteger)retainCount { + return _os_object_retain_count(self); +} + +-(BOOL)retainWeakReference { + return _os_object_retain_weak(self); +} + +-(BOOL)allowsWeakReference { + return _os_object_allows_weak_reference(self); +} + +- (void)_xref_dispose { + return _os_object_release_internal(self); +} + +- (void)_dispose { + return _os_object_dealloc(self); +} + +@end + +#pragma mark - +#pragma mark _dispatch_object + +#include + +// Force non-lazy class realization rdar://10640168 +#define DISPATCH_OBJC_LOAD() + (void)load {} + +@implementation DISPATCH_CLASS(object) + +- (id)init { + self = [super init]; + [self release]; + self = nil; + return self; +} + +- (void)_xref_dispose { + _dispatch_xref_dispose(self); + [super _xref_dispose]; +} + +- (void)_dispose { + return _dispatch_dispose(self); // calls _os_object_dealloc() +} + +- (NSString *)debugDescription { + Class nsstring = objc_lookUpClass("NSString"); + if (!nsstring) return nil; + char buf[4096]; + dx_debug((struct dispatch_object_s *)self, buf, sizeof(buf)); + return [nsstring stringWithFormat: + [nsstring stringWithUTF8String:"<%s: %s>"], + class_getName([self class]), buf]; +} + +@end + +@implementation DISPATCH_CLASS(queue) +DISPATCH_OBJC_LOAD() + +- (NSString *)description { + Class nsstring = objc_lookUpClass("NSString"); + if (!nsstring) return nil; + return [nsstring stringWithFormat: + [nsstring stringWithUTF8String:"<%s: %s[%p]>"], + class_getName([self class]), dispatch_queue_get_label(self), self]; +} + +@end + +@implementation DISPATCH_CLASS(source) +DISPATCH_OBJC_LOAD() + +- (void)_xref_dispose { + _dispatch_source_xref_dispose(self); + [super _xref_dispose]; +} + +@end + +#define DISPATCH_CLASS_IMPL(name) \ + @implementation DISPATCH_CLASS(name) \ + DISPATCH_OBJC_LOAD() \ + @end + +DISPATCH_CLASS_IMPL(semaphore) +DISPATCH_CLASS_IMPL(group) +DISPATCH_CLASS_IMPL(queue_root) +DISPATCH_CLASS_IMPL(queue_mgr) +DISPATCH_CLASS_IMPL(queue_specific_queue) +DISPATCH_CLASS_IMPL(queue_attr) +DISPATCH_CLASS_IMPL(io) +DISPATCH_CLASS_IMPL(operation) +DISPATCH_CLASS_IMPL(disk) +DISPATCH_CLASS_IMPL(data) + +#pragma mark - +#pragma mark dispatch_autorelease_pool + +#if DISPATCH_COCOA_COMPAT + +void * +_dispatch_autorelease_pool_push(void) { + return objc_autoreleasePoolPush(); +} + +void +_dispatch_autorelease_pool_pop(void *context) { + return objc_autoreleasePoolPop(context); +} + +#endif // DISPATCH_COCOA_COMPAT + +#pragma mark - +#pragma mark dispatch_client_callout + +// Abort on uncaught exceptions thrown from client callouts rdar://8577499 +#if DISPATCH_USE_CLIENT_CALLOUT && !__arm__ +// On platforms with zero-cost exceptions, use a compiler-generated catch-all +// exception handler. + +DISPATCH_NORETURN extern void objc_terminate(void); + +#undef _dispatch_client_callout +void +_dispatch_client_callout(void *ctxt, dispatch_function_t f) +{ + @try { + return f(ctxt); + } + @catch (...) { + objc_terminate(); + } +} + +#undef _dispatch_client_callout2 +void +_dispatch_client_callout2(void *ctxt, size_t i, void (*f)(void *, size_t)) +{ + @try { + return f(ctxt, i); + } + @catch (...) { + objc_terminate(); + } +} + +#endif // DISPATCH_USE_CLIENT_CALLOUT + +#endif // USE_OBJC