diff --git a/GNUmakefile b/GNUmakefile index 1f84ca4..094f4d6 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -9,9 +9,6 @@ include $(GNUSTEP_MAKEFILES)/common.make LIBRARY_NAME = libobjc - -SUBPROJECTS = toydispatch - libobjc_VERSION = 4 libobjc_OBJC_FILES = \ @@ -40,7 +37,8 @@ libobjc_C_FILES = \ sarray2.c\ selector_table.c\ sendmsg2.c\ - statics_loader.c + statics_loader.c\ + toydispatch.c ifneq ($(enable_legacy), no) libobjc_C_FILES += legacy_malloc.c @@ -60,14 +58,15 @@ libobjc_HEADER_FILES = \ runtime.h\ slot.h\ objc.h\ - objc-api.h + objc-api.h\ + toydispatch.h endif ifneq ($(tdd), no) libobjc_CPPFLAGS += -DTYPE_DEPENDENT_DISPATCH endif -libobjc_LIBRARIES_DEPEND_UPON += -lpthread -ltoydispatch +libobjc_LIBRARIES_DEPEND_UPON += -lpthread # Deprecated functions are only deprecated for external use, not for us because # we are special, precious, little flowers. @@ -75,9 +74,9 @@ libobjc_CPPFLAGS += -D__OBJC_RUNTIME_INTERNAL__=1 -D_XOPEN_SOURCE=500 # Note to Riccardo. Please do not 'fix' C99isms in this. The new ABI is only # useful on compilers that support C99 (currently only clang), so there is no # benefit from supporting platforms with no C99 compiler. -libobjc_CFLAGS += -std=c99 -g -fexceptions -fno-inline -libobjc_OBJCFLAGS += $(libobjc_CFLAGS) -libobjc_LDFLAGS += -g +libobjc_CFLAGS += -std=c99 -g -fexceptions #-fvisibility=hidden +libobjc_OBJCFLAGS += $(libobjc_CFLAGS) $(libobjc_CFLAGS) +libobjc_LDFLAGS += -g libobjc_LIB_DIRS += -L toydispatch/obj libobjc_CFLAGS += -O3 diff --git a/Makefile b/Makefile index 120b03a..7638821 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ VERSION = 4 #CC=clang CFLAGS += -std=c99 -fPIC -CPPFLAGS += -DTYPE_DEPENDENT_DISPATCH +CPPFLAGS += -DTYPE_DEPENDENT_DISPATCH -DGNUSTEP CPPFLAGS += -D__OBJC_RUNTIME_INTERNAL__=1 -D_XOPEN_SOURCE=500 PREFIX?= /usr/local diff --git a/Makefile.clang b/Makefile.clang new file mode 100644 index 0000000..d7de476 --- /dev/null +++ b/Makefile.clang @@ -0,0 +1,79 @@ +.POSIX: + +.SUFFIXES: .c .bc .m + +VERSION = 4 + +#CC=clang + +CFLAGS += -fPIC +CPPFLAGS += -DTYPE_DEPENDENT_DISPATCH -DGNUSTEP +CPPFLAGS += -D__OBJC_RUNTIME_INTERNAL__=1 -D_XOPEN_SOURCE=500 + +PREFIX?= /usr/local +LIB_DIR= ${PREFIX}/lib +HEADER_DIR= ${PREFIX}/include + +OBJECTS = \ + NSBlocks.bc\ + Protocol2.bc\ + abi_version.bc\ + blocks_runtime.bc\ + caps.bc\ + category_loader.bc\ + class_table.bc\ + dtable.bc\ + eh_personality.bc\ + encoding2.bc\ + hash_table.bc\ + hooks.bc\ + ivar.bc\ + legacy_malloc.bc\ + loader.bc\ + mutation.bc\ + properties.bc\ + protocol.bc\ + runtime.bc\ + sarray2.bc\ + selector_table.bc\ + sendmsg2.bc\ + statics_loader.bc\ + sync.bc\ + toydispatch.bc + +all: libobjc.so.$(VERSION) libobjc.a + +libobjc.so.$(VERSION): libobjc.o + @echo Linking shared library... + @ld -shared -o $@ libobjc.o + +libobjc.a: libobjc.o + @echo Linking static library... + @ld -r -s -o $@ libobjc.o + +libobjc.o: libobjc.bc + llc -O3 -filetype=obj -o libobjc.o libobjc.bc + +libobjc.bc: $(OBJECTS) + @echo Linking bitcode... + pwd + llvm-ld -internalize-public-api-file=../exports.txt -link-as-library -native -o libobjc.bc $(OBJECTS) + +.c.bc: obj + clang $(CPPFLAGS) $(CFLAGS) -emit-llvm -c $< -o $@ + +.m.bc: obj + clang $(CPPFLAGS) $(CFLAGS) -emit-llvm -c $< -o $@ + +obj: + mkdir obj + +install: all + install -m 444 libobjc.so.$(VERSION) $(LIB_DIR) + install -m 444 libobjc.a $(LIB_DIR) + ln -sf $(LIB_DIR)/libobjc.so.$(VERSION) $(LIB_DIR)/libobjc.so + install -d $(HEADER_DIR)/objc + install -m 444 objc/*.h $(HEADER_DIR)/objc + +clean: + rm -f obj/* diff --git a/Protocol2.m b/Protocol2.m index 717c6a4..707e9b3 100644 --- a/Protocol2.m +++ b/Protocol2.m @@ -15,6 +15,11 @@ { return protocol_conformsToProtocol(self, p); } +- (id)retain +{ + return self; +} +- (void)release {} @end @implementation Protocol2 + (void)load diff --git a/blocks_runtime.m b/blocks_runtime.m index 5a315e9..2eb2595 100644 --- a/blocks_runtime.m +++ b/blocks_runtime.m @@ -29,6 +29,9 @@ #include #include #include +#include + +#define fprintf(...) /* Makes the compiler happy even without Foundation */ @interface Dummy @@ -36,10 +39,24 @@ - (void)release; @end -// Descriptor attributes -enum { +static void *_HeapBlockByRef = (void*)1; + +/** + * Block descriptor flags. + */ +enum block_flags +{ + /** + * The block descriptor contains copy and dispose helpers. + */ BLOCK_HAS_COPY_DISPOSE = (1 << 25), - BLOCK_HAS_CTOR = (1 << 26), // helpers have C++ code + /** + * The helpers have C++ code. + */ + BLOCK_HAS_CTOR = (1 << 26), + /** + * Block is stored in global memory and does not need to be copied. + */ BLOCK_IS_GLOBAL = (1 << 28), /** * Block function uses a calling convention that returns a structure via a @@ -49,13 +66,36 @@ enum { /** * Block has an Objective-C type encoding. */ - BLOCK_HAS_SIGNATURE = (1 << 30) + BLOCK_HAS_SIGNATURE = (1 << 30), + /** + * Mask for the reference count in byref structure's flags field. The low + * 3 bytes are reserved for the reference count, the top byte for the + * flags. + */ + BLOCK_REFCOUNT_MASK = 0x00ffffffff }; -// _Block_object_assign() and _Block_object_dispose() flag helpers. -enum { - BLOCK_FIELD_IS_OBJECT = 3, // id, NSObject, __attribute__((NSObject)), block, ... - BLOCK_FIELD_IS_BLOCK = 7, // a block variable +/** + * Flags used in the final argument to _Block_object_assign() and + * _Block_object_dispose(). These indicate the type of copy or dispose to + * perform. + */ +enum +{ + /** + * The value is of some id-like type, and should be copied as an + * Objective-C object: i.e. by sending -retain or via the GC assign + * functions in GC mode (not yet supported). + */ + BLOCK_FIELD_IS_OBJECT = 3, + /** + * The field is a block. This must be copied by the block copy functions. + */ + BLOCK_FIELD_IS_BLOCK = 7, + /** + * The field is an indirect reference to a variable declared with the + * __block storage qualifier. + */ BLOCK_FIELD_IS_BYREF = 8, // the on stack structure holding the __block variable BLOCK_FIELD_IS_WEAK = 16, // declared __weak @@ -68,6 +108,9 @@ enum { */ struct block_descriptor_copydispose { + /** + * Reserved for future use. Currently always 0. + */ unsigned long int reserved; /** Size of the block. */ unsigned long int size; @@ -91,6 +134,9 @@ struct block_descriptor_copydispose */ struct block_descriptor { + /** + * Reserved for future use, currently always 0. + */ unsigned long int reserved; /** Size of the block. */ unsigned long int size; @@ -101,27 +147,86 @@ struct block_descriptor }; // Helper structure -struct psy_block_literal { - void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock +struct block_literal +{ + /** + * Class pointer. Always initialised to &_NSConcreteStackBlock for blocks + * that are created on the stack or &_NSConcreteGlobalBlock for blocks that + * are created in global storage. + */ + void *isa; + /** + * Flags. See the block_flags enumerated type for possible values. + */ int flags; + /** + * Reserved - always initialised to 0 by the compiler. Used for the + * reference count in this implementation. + */ int reserved; + /** + * The function that implements the block. The first argument is this + * structure, the subsequent arguments are the block's explicit parameters. + * If the BLOCK_USE_SRET flag is set, there is an additional hidden + * argument, which is a pointer to the space on the stack allocated to hold + * the return value. + */ void (*invoke)(void *, ...); + /** + * The block's descriptor. This is either block_descriptor or + * block_descriptor_copydispose, depending on whether the + * BLOCK_HAS_COPY_DISPOSE flag is set. + */ struct block_descriptor_copydispose *descriptor; + /** + * Block variables are appended to this structure. + */ }; -// Helper structure -struct psy_block_byref_obj { - void *isa; // uninitialized - struct psy_block_byref_obj *forwarding; +/** + * Structure used for on-stack variables that are referenced by blocks. + */ +struct block_byref_obj +{ + /** + * Class pointer. Currently unused and always NULL. Could be used in the + * future to support introspection. + */ + void *isa; + /** + * The pointer to the structure that contains the real version of the data. + * All accesses go via this pointer. If an on-stack byref structure is + * copied to the heap, then its forwarding pointer should point to the heap + * version. Otherwise it should point to itself. + */ + struct block_byref_obj *forwarding; + /** + * Flags and reference count. + */ int flags; //refcount; + /** + * Size of this structure. + */ int size; - void (*byref_keep)(struct psy_block_byref_obj *dst, const struct psy_block_byref_obj *src); - void (*byref_dispose)(struct psy_block_byref_obj *); + /** + * Copy function. + */ + void (*byref_keep)(struct block_byref_obj *dst, const struct block_byref_obj *src); + /** + * Dispose function. + */ + void (*byref_dispose)(struct block_byref_obj *); + /** + * __block-qualified variables are copied here. + */ }; +/** + * Returns the Objective-C type encoding for the block. + */ const char *block_getType_np(void *b) { - struct psy_block_literal *block = b; + struct block_literal *block = b; if ((NULL == block) || !(block->flags & BLOCK_HAS_SIGNATURE)) { return NULL; @@ -133,6 +238,33 @@ const char *block_getType_np(void *b) return block->descriptor->encoding; } +static int increment24(int *ref) +{ + int old = *ref; + int val = old & BLOCK_REFCOUNT_MASK; + // FIXME: We should gracefully handle refcount overflow, but for now we + // just give up + assert(val < BLOCK_REFCOUNT_MASK); + if (!__sync_bool_compare_and_swap(ref, old, old+1)) + { + return increment24(ref); + } + return val + 1; +} + +static int decrement24(int *ref) +{ + int old = *ref; + int val = old & BLOCK_REFCOUNT_MASK; + // FIXME: We should gracefully handle refcount overflow, but for now we + // just give up + assert(val > 0); + if (!__sync_bool_compare_and_swap(ref, old, old-1)) + { + return decrement24(ref); + } + return val - 1; +} /* Certain field types require runtime assistance when being copied to the * heap. The following function is used to copy fields of types: blocks, @@ -143,48 +275,70 @@ const char *block_getType_np(void *b) */ void _Block_object_assign(void *destAddr, const void *object, const int flags) { + fprintf(stderr, "assign: %d\n", flags); //printf("Copying %x to %x with flags %x\n", object, destAddr, flags); // FIXME: Needs to be implemented - if(flags & BLOCK_FIELD_IS_WEAK) + //if(flags & BLOCK_FIELD_IS_WEAK) { } - else + //else { if(flags & BLOCK_FIELD_IS_BYREF) { - const struct psy_block_byref_obj *src = object; - struct psy_block_byref_obj **dst = destAddr; + struct block_byref_obj *src = (struct block_byref_obj *)object; + struct block_byref_obj **dst = destAddr; - /* I followed Apple's specs saying byref's "flags" field should - * represent the refcount but it still contains real flag, so this - * is a little hack... - */ - if((src->flags & ~BLOCK_HAS_COPY_DISPOSE) == 0) + if ((src->flags & BLOCK_REFCOUNT_MASK) == 0) { *dst = malloc(src->size); + fprintf(stderr, "Copying %d bytes to %p\n", src->size, *dst); memcpy(*dst, src, src->size); - if (src->forwarding == src) + (*dst)->isa = _HeapBlockByRef; + // Refcount must be two; one for the copy and one for the + // on-stack version that will point to it. + (*dst)->flags += 2; + if ((size_t)src->size >= sizeof(struct block_byref_obj)) { - (*dst)->forwarding = *dst; + src->byref_keep(*dst, src); } - if((size_t)src->size >= sizeof(struct psy_block_byref_obj)) + (*dst)->forwarding = *dst; + // Concurrency. If we try copying the same byref structure + // from two threads simultaneously, we could end up with two + // versions on the heap that are unaware of each other. That + // would be bad. So we first set up the copy, then try to do + // an atomic compare-and-exchange to point the old version at + // it. If the forwarding pointer in src has changed, then we + // recover - clean up and then return the structure that the + // other thread created. + /* + if (!__sync_bool_compare_and_swap(&src->forwarding, src, *dst)) { - src->byref_keep(*dst, src); + if((size_t)src->size >= sizeof(struct block_byref_obj)) + { + src->byref_dispose(*dst); + } + free(*dst); + *dst = src->forwarding; } + */ } - else *dst = (struct psy_block_byref_obj*)src; - - (*dst)->flags++; + else + { + *dst = (struct block_byref_obj*)src; + } + increment24(&(*dst)->flags); + fprintf(stderr, "Flags for block: %p: %d\n", *dst, (*dst)->flags); } else if((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) { - struct psy_block_literal *src = (struct psy_block_literal*)object; - struct psy_block_literal **dst = destAddr; + struct block_literal *src = (struct block_literal*)object; + struct block_literal **dst = destAddr; *dst = Block_copy(src); } else if((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) { + fprintf(stderr, "-retain\n"); id src = (id)object; id *dst = destAddr; *dst = [src retain]; @@ -200,32 +354,61 @@ void _Block_object_assign(void *destAddr, const void *object, const int flags) */ void _Block_object_dispose(const void *object, const int flags) { + fprintf(stderr, "Dispose %p, Flags: %d\n", object, flags); // FIXME: Needs to be implemented - if(flags & BLOCK_FIELD_IS_WEAK) + //if(flags & BLOCK_FIELD_IS_WEAK) { } - else + //else { if(flags & BLOCK_FIELD_IS_BYREF) { - struct psy_block_byref_obj *src = - (struct psy_block_byref_obj*)object; - - src->flags--; - if((src->flags & ~BLOCK_HAS_COPY_DISPOSE) == 0) + struct block_byref_obj *src = + (struct block_byref_obj*)object; + if (src->isa == _HeapBlockByRef) { - if((size_t)src->size >= sizeof(struct psy_block_byref_obj)) - src->byref_dispose(src); - - free(src); + fprintf(stderr, "refcount %d\n", src->flags); + int refcount = decrement24(&src->flags); + if (refcount == 0) + { + if (0 != src->byref_dispose) + { + src->byref_dispose(src); + } + free(src); + } + } + else + { + fprintf(stderr, "src: %p\n", src); + fprintf(stderr, "forwarding: %p\n", src->forwarding); + fprintf(stderr, "dispose: %p\n", src->byref_dispose); + void *var = src+1; + id obj = *(id*)var; + fprintf(stderr, "Cleaning up %p\n" ,obj); + // Call nontrivial destructors, but don't + if (0 != src->byref_dispose) + { + //fprintf(stderr, "Calling byref dispose\n"); + //src->byref_dispose(src); + //src->byref_dispose(0); + //fprintf(stderr, "Called byref dispose\n"); + } + // If this block has been promoted to the heap, decrement its + // reference count / destroy it if the heap version is already + // dead. + if (src->forwarding != src) + { + _Block_object_dispose(src->forwarding, flags | BLOCK_BYREF_CALLER); + } } } - else if((flags & ~BLOCK_BYREF_CALLER) == BLOCK_FIELD_IS_BLOCK) + else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) { - struct psy_block_literal *src = (struct psy_block_literal*)object; + struct block_literal *src = (struct block_literal*)object; Block_release(src); } - else if((flags & ~BLOCK_BYREF_CALLER) == BLOCK_FIELD_IS_OBJECT) + else if((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) { id src = (id)object; [src release]; @@ -233,44 +416,31 @@ void _Block_object_dispose(const void *object, const int flags) } } -struct StackBlockClass { - void *isa; // initialized to &_NSConcreteStackBlock or &_NSConcreteGlobalBlock - int flags; - int reserved; - void (*invoke)(void *, ...); - struct { - unsigned long int reserved; // NULL - unsigned long int size; // sizeof(struct Block_literal_1) - // optional helper functions - void (*copy_helper)(void *dst, void *src); - void (*dispose_helper)(void *src); - } *descriptor; -}; - // Copy a block to the heap if it's still on the stack or increments its retain count. void *_Block_copy(void *src) { - struct StackBlockClass *self = src; - struct StackBlockClass *ret = self; + fprintf(stderr, "_Block_copy()\n"); + struct block_literal *self = src; + struct block_literal *ret = self; - extern void _NSConcreteStackBlock __attribute__((weak)); + extern void _NSConcreteStackBlock; + fprintf(stderr, "isa %p stack block %p\n", self->isa, &_NSConcreteStackBlock); // If the block is Global, there's no need to copy it on the heap. if(self->isa == &_NSConcreteStackBlock) { + fprintf(stderr, "reserved: %d\n", self->reserved); + fprintf(stderr, "block flags: %d\n", self->flags); if(self->reserved == 0) { ret = malloc(self->descriptor->size); + memcpy(ret, self, self->descriptor->size); if(self->flags & BLOCK_HAS_COPY_DISPOSE) { - memcpy(self, ret, sizeof(struct StackBlockClass)); + fprintf(stderr, "_Block_copy() calling copy helper\n"); self->descriptor->copy_helper(ret, self); } - else - { - memcpy(self, ret, self->descriptor->size); - } } ret->reserved++; } @@ -280,9 +450,9 @@ void *_Block_copy(void *src) // Release a block and frees the memory when the retain count hits zero. void _Block_release(void *src) { - struct StackBlockClass *self = src; + struct block_literal *self = src; - extern void _NSConcreteStackBlock __attribute__((weak)); + extern void _NSConcreteStackBlock; if(self->isa == &_NSConcreteStackBlock && // A Global block doesn't need to be released self->reserved > 0) // If false, then it's not allocated on the heap, we won't release auto memory ! diff --git a/exports.txt b/exports.txt new file mode 100644 index 0000000..bcf08c4 --- /dev/null +++ b/exports.txt @@ -0,0 +1,174 @@ +.objc_sel_nameautorelease +.objc_sel_namecopy +.objc_sel_namedealloc +.objc_sel_namerelease +.objc_sel_nameretain +_Block_copy +_Block_object_assign +_Block_object_dispose +_Block_release +_NSConcreteGlobalBlock +_NSConcreteStackBlock +__gnu_objc_personality_v0 +__objc_class_name_Object +__objc_class_name_Protocol +__objc_class_name_Protocol2 +__objc_class_name___ObjC_Protocol_Holder_Ugly_Hack +__objc_exec_class +__objc_id_typeinfo +__objc_msg_forward2 +__objc_msg_forward3 +__objc_responds_to +__objc_runtime_mutex +__objc_runtime_threads_alive +__objc_sync_init +__objc_uninstalled_dtable +__objc_update_dispatch_table_for_class +_objc_class_for_boxing_foreign_exception +_objc_load_callback +_objc_lookup_class +_objc_selector_type_mismatch +_objc_unexpected_exception +block_getType_np +class_addIvar +class_addMethod +class_addProtocol +class_conformsToProtocol +class_copyIvarList +class_copyMethodList +class_copyPropertyList +class_copyProtocolList +class_createInstance +class_getClassMethod +class_getClassVariable +class_getInstanceMethod +class_getInstanceSize +class_getInstanceVariable +class_getIvarLayout +class_getMethodImplementation +class_getMethodImplementation_stret +class_getName +class_getProperty +class_getSuperclass +class_getVersion +class_getWeakIvarLayout +class_isMetaClass +class_pose_as +class_replaceMethod +class_respondsToSelector +class_setIvarLayout +class_setSuperclass +class_setVersion +class_setWeakIvarLayout +class_table_get_safe +class_table_insert +class_table_internal_create +get_imp +ivar_getName +ivar_getOffset +ivar_getTypeEncoding +method_copyArgumentType +method_copyReturnType +method_exchangeImplementations +method_getArgumentType +method_getImplementation +method_getName +method_getNumberOfArguments +method_getReturnType +method_getTypeEncoding +method_get_number_of_arguments +method_setImplementation +objc_aligned_size +objc_alignof_type +objc_allocateClassPair +objc_atomic_malloc +objc_calloc +objc_check_abi_version +objc_collect_garbage_data +objc_compute_ivar_offsets +objc_copy_dtable_for_class +objc_create_block_classes_as_subclasses_of +objc_disposeClassPair +objc_enumerationMutation +objc_exception_throw +objc_free +objc_getClass +objc_getClassList +objc_getMetaClass +objc_getProperty +objc_getProtocol +objc_getRequiredClass +objc_get_class +objc_get_meta_class +objc_get_slot +objc_get_type_qualifiers +objc_init_buffered_statics +objc_init_load_messages_table +objc_init_protocols +objc_init_statics +objc_layout_structure +objc_layout_structure_get_info +objc_layout_structure_next_member +objc_load_buffered_categories +objc_load_class +objc_lookUpClass +objc_lookup_class +objc_malloc +objc_msg_lookup +objc_msg_lookup_sender +objc_msg_lookup_super +objc_msg_profile +objc_msg_sender +objc_msg_sendv +objc_next_class +objc_plane_lookup +objc_promoted_size +objc_proxy_lookup +objc_realloc +objc_registerClassPair +objc_setProperty +objc_sizeof_type +objc_skip_argspec +objc_skip_type_qualifiers +objc_skip_typespec +objc_slot_lookup_super +objc_sync_enter +objc_sync_exit +objc_test_capability +objc_valloc +object_getClass +object_getClassName +object_getIndexedIvars +object_setClass +property_getName +protocol_conformsToProtocol +protocol_copyMethodDescriptionList +protocol_copyPropertyList +protocol_copyProtocolList +protocol_create +protocol_for_name +protocol_getMethodDescription +protocol_getName +protocol_getProperty +protocol_isEqual +sel_copyTypedSelectors_np +sel_copyTypes_np +sel_eq +sel_getName +sel_getType_np +sel_getUid +sel_get_any_typed_uid +sel_get_any_uid +sel_get_name +sel_get_type +sel_get_typed_uid +sel_get_uid +sel_isEqual +sel_is_mapped +sel_registerName +sel_registerTypedName_np +sel_register_name +sel_register_typed_name +selector_create +toy_dispatch_async_f +toy_dispatch_queue_create diff --git a/hash_table.c b/hash_table.c index 29e4924..be63579 100644 --- a/hash_table.c +++ b/hash_table.c @@ -1,4 +1,4 @@ -#include "toydispatch/toydispatch.h" +#include "objc/toydispatch.h" static dispatch_queue_t garbage_queue; diff --git a/toydispatch/toydispatch.c b/toydispatch.c similarity index 99% rename from toydispatch/toydispatch.c rename to toydispatch.c index b80a942..c6c6970 100644 --- a/toydispatch/toydispatch.c +++ b/toydispatch.c @@ -1,7 +1,7 @@ #include #include #define __TOY_DISPATCH__ -#include "toydispatch.h" +#include "objc/toydispatch.h" /** * Amount of total space in the ring buffer. Must be a power of two. diff --git a/toydispatch/toydispatch.h b/toydispatch/toydispatch.h deleted file mode 100644 index e89b9ad..0000000 --- a/toydispatch/toydispatch.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * toydispatch implements a (tiny) subset of the libdispatch interfaces. It - * can produce FIFO work queues, but not concurrent ones (although queues are - * concurrent with respect to each other, as with libdispatch). Unlike - * libdispatch, queues all run on the same system thread. This is less - * efficient, so the real libdispatch should be used on platforms where it is - * available. - * - * Toydispatch symbol names are prefixed with toy_ so programs can be linked to - * both libdispatch and toydispatch. - */ - -/* If the real libdispatch exists, use that instead of the toy one. */ -#if !defined(__has_include) -#define __has_include(x) 0 -#endif -#if __has_include() && !defined(__TOY_DISPATCH__) -# include -#else - -/** - * Function type for functions that can be added to dispatch queues. - */ -typedef void (*dispatch_function_t)(void *); - -typedef struct dispatch_queue * dispatch_queue_t; - -#define dispatch_queue_create toy_dispatch_queue_create -/** - * Create a new queue. Both parameters are ignored by toydispatch. - */ -dispatch_queue_t dispatch_queue_create(const char *label, - void *attr); - -#define dispatch_async_f toy_dispatch_async_f -/** - * Add a function to the queue. - */ -void dispatch_async_f(dispatch_queue_t queue, void *context, - dispatch_function_t work); - -#define dispatch_release toy_dispatch_release -void dispatch_release(dispatch_queue_t queue); - -#define dispatch_retain toy_dispatch_retain -void dispatch_retain(dispatch_queue_t queue); -#endif