1/* 2 * Copyright (c) 2012-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 <Foundation/NSString.h> 33 34@interface DISPATCH_CLASS(data) () 35- (id)initWithBytes:(void *)bytes length:(NSUInteger)length copy:(BOOL)copy 36 freeWhenDone:(BOOL)freeBytes bytesAreVM:(BOOL)vm; 37- (BOOL)_bytesAreVM; 38@end 39 40@interface DISPATCH_CLASS(data_empty) : DISPATCH_CLASS(data) 41@end 42 43@implementation DISPATCH_CLASS(data) 44 45+ (id)allocWithZone:(NSZone *) DISPATCH_UNUSED zone { 46 return _dispatch_objc_alloc(self, sizeof(struct dispatch_data_s)); 47} 48 49- (id)init { 50 return [self initWithBytes:NULL length:0 copy:NO freeWhenDone:NO 51 bytesAreVM:NO]; 52} 53 54- (id)initWithBytes:(void *)bytes length:(NSUInteger)length copy:(BOOL)copy 55 freeWhenDone:(BOOL)freeBytes bytesAreVM:(BOOL)vm { 56 dispatch_block_t destructor; 57 if (copy) { 58 destructor = DISPATCH_DATA_DESTRUCTOR_DEFAULT; 59 } else if (freeBytes) { 60 if (vm) { 61 destructor = DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE; 62 } else { 63 destructor = DISPATCH_DATA_DESTRUCTOR_FREE; 64 } 65 } else { 66 destructor = DISPATCH_DATA_DESTRUCTOR_NONE; 67 } 68 dispatch_data_init(self, bytes, length, destructor); 69 return self; 70} 71 72#define _dispatch_data_objc_dispose(selector) \ 73 struct dispatch_data_s *dd = (void*)self; \ 74 _dispatch_data_dispose(self); \ 75 dispatch_queue_t tq = dd->do_targetq; \ 76 dispatch_function_t func = dd->finalizer; \ 77 void *ctxt = dd->ctxt; \ 78 [super selector]; \ 79 if (func && ctxt) { \ 80 if (!tq) { \ 81 tq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);\ 82 } \ 83 dispatch_async_f(tq, ctxt, func); \ 84 } \ 85 if (tq) { \ 86 _dispatch_release(tq); \ 87 } 88 89- (void)dealloc { 90 _dispatch_data_objc_dispose(dealloc); 91} 92 93- (void)finalize { 94 _dispatch_data_objc_dispose(finalize); 95} 96 97- (BOOL)_bytesAreVM { 98 struct dispatch_data_s *dd = (void*)self; 99 return dd->destructor == DISPATCH_DATA_DESTRUCTOR_VM_DEALLOCATE; 100} 101 102- (void)_setContext:(void*)context { 103 struct dispatch_data_s *dd = (void*)self; 104 dd->ctxt = context; 105} 106 107- (void*)_getContext { 108 struct dispatch_data_s *dd = (void*)self; 109 return dd->ctxt; 110} 111 112- (void)_setFinalizer:(dispatch_function_t)finalizer { 113 struct dispatch_data_s *dd = (void*)self; 114 dd->finalizer = finalizer; 115} 116 117- (void)_setTargetQueue:(dispatch_queue_t)queue { 118 struct dispatch_data_s *dd = (void*)self; 119 _dispatch_retain(queue); 120 dispatch_queue_t prev; 121 prev = dispatch_atomic_xchg2o(dd, do_targetq, queue, release); 122 if (prev) _dispatch_release(prev); 123} 124 125- (NSString *)debugDescription { 126 Class nsstring = objc_lookUpClass("NSString"); 127 if (!nsstring) return nil; 128 char buf[2048]; 129 _dispatch_data_debug(self, buf, sizeof(buf)); 130 return [nsstring stringWithFormat: 131 [nsstring stringWithUTF8String:"<%s: %s>"], 132 class_getName([self class]), buf]; 133} 134 135@end 136 137@implementation DISPATCH_CLASS(data_empty) 138 139// Force non-lazy class realization rdar://10640168 140+ (void)load { 141} 142 143- (id)retain { 144 return (id)self; 145} 146 147- (oneway void)release { 148} 149 150- (id)autorelease { 151 return (id)self; 152} 153 154- (NSUInteger)retainCount { 155 return ULONG_MAX; 156} 157 158+ (id)allocWithZone:(NSZone *) DISPATCH_UNUSED zone { 159 return (id)&_dispatch_data_empty; 160} 161 162- (void)_setContext:(void*) DISPATCH_UNUSED context { 163} 164 165- (void*)_getContext { 166 return NULL; 167} 168 169- (void)_setFinalizer:(dispatch_function_t) DISPATCH_UNUSED finalizer { 170} 171 172- (void)_setTargetQueue:(dispatch_queue_t) DISPATCH_UNUSED queue { 173} 174 175@end 176 177#endif // USE_OBJC 178