Index: src/OFObject.m ================================================================== --- src/OFObject.m +++ src/OFObject.m @@ -52,11 +52,11 @@ /// \cond internal struct pre_ivar { void **memchunks; size_t memchunks_size; - int32_t retain_count; /* int32_t because atomic ops use int32_t */ + int32_t retain_count; #ifndef OF_ATOMIC_OPS of_spinlock_t retain_spinlock; #endif }; /// \endcond Index: src/atomic.h ================================================================== --- src/atomic.h +++ src/atomic.h @@ -17,10 +17,37 @@ #endif #ifdef OF_HAVE_LIBKERN_OSATOMIC_H # include #endif + +static OF_INLINE int +of_atomic_add_int(volatile int *p, int i) +{ +#if !defined(OF_THREADS) + return (*p += i); +#elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) + __asm__ ( + "lock\n\t" + "xaddl %0, %2\n\t" + "addl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return i; +#elif defined(OF_HAVE_GCC_ATOMIC_OPS) + return __sync_add_and_fetch(p, i); +#elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) + if (sizeof(int) == 4) + return OSAtomicAdd32Barrier(i, p); + else if (sizeof(int) == 8) + return OSAtomicAdd64Barrier(i, p); + else + abort(); +#endif +} static OF_INLINE int32_t of_atomic_add_32(volatile int32_t *p, int32_t i) { #if !defined(OF_THREADS) @@ -39,10 +66,65 @@ return __sync_add_and_fetch(p, i); #elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) return OSAtomicAdd32Barrier(i, p); #endif } + +static OF_INLINE void* +of_atomic_add_ptr(volatile void **p, intptr_t i) +{ +#if !defined(OF_THREADS) + return (*p += i); +#elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) + __asm__ ( + "lock\n\t" + "xaddl %0, %2\n\t" + "addl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void*)i; +#elif defined(OF_HAVE_GCC_ATOMIC_OPS) + return __sync_add_and_fetch(p, i); +#elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) + if (sizeof(void*) == 4) + return OSAtomicAdd32Barrier(i, p); + else if (sizeof(void*) == 8) + return OSAtomicAdd64Barrier(i, p); + else + abort(); +#endif +} + +static OF_INLINE int +of_atomic_sub_int(volatile int *p, int i) +{ +#if !defined(OF_THREADS) + return (*p -= i); +#elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) + __asm__ ( + "negl %0\n\t" + "lock\n\t" + "xaddl %0, %2\n\t" + "subl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return i; +#elif defined(OF_HAVE_GCC_ATOMIC_OPS) + return __sync_sub_and_fetch(p, i); +#elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) + if (sizeof(int) == 4) + return OSAtomicAdd32Barrier(-i, p); + else if (sizeof(int) == 8) + return OSAtomicAdd64Barrier(-i, p); + else + abort(); +#endif +} static OF_INLINE int32_t of_atomic_sub_32(volatile int32_t *p, int32_t i) { #if !defined(OF_THREADS) @@ -63,10 +145,68 @@ #elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) return OSAtomicAdd32Barrier(-i, p); #endif } +static OF_INLINE void* +of_atomic_sub_ptr(volatile void **p, intptr_t i) +{ +#if !defined(OF_THREADS) + return (*p -= i); +#elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) + __asm__ ( + "negl %0\n\t" + "lock\n\t" + "xaddl %0, %2\n\t" + "subl %1, %0" + : "+&r"(i) + : "r"(i), "m"(*p) + ); + + return (void*)i; +#elif defined(OF_HAVE_GCC_ATOMIC_OPS) + return __sync_sub_and_fetch(p, i); +#elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) + if (sizeof(void*) == 4) + return OSAtomicAdd32Barrier(-i, p); + else if (sizeof(void*) == 8) + return OSAtomicAdd64Barrier(-i, p); + else + abort(); +#endif +} + +static OF_INLINE int +of_atomic_inc_int(volatile int *p) +{ +#if !defined(OF_THREADS) + return ++*p; +#elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) + uint32_t i; + + __asm__ ( + "xorl %0, %0\n\t" + "incl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "incl %0" + : "=&r"(i) + : "m"(*p) + ); + + return i; +#elif defined(OF_HAVE_GCC_ATOMIC_OPS) + return __sync_add_and_fetch(p, 1); +#elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) + if (sizeof(int) == 4) + return OSAtomicIncrement32Barrier(p); + else if (sizeof(int) == 8) + return OSAtomicDecrement64Barrier(p); + else + abort(); +#endif +} static OF_INLINE int32_t of_atomic_inc_32(volatile int32_t *p) { #if !defined(OF_THREADS) return ++*p; @@ -88,10 +228,41 @@ return __sync_add_and_fetch(p, 1); #elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) return OSAtomicIncrement32Barrier(p); #endif } + +static OF_INLINE int +of_atomic_dec_int(volatile int *p) +{ +#if !defined(OF_THREADS) + return --*p; +#elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) + uint32_t i; + + __asm__ ( + "xorl %0, %0\n\t" + "decl %0\n\t" + "lock\n\t" + "xaddl %0, %1\n\t" + "decl %0" + : "=&r"(i) + : "m"(*p) + ); + + return i; +#elif defined(OF_HAVE_GCC_ATOMIC_OPS) + return __sync_sub_and_fetch(p, 1); +#elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) + if (sizeof(int) == 4) + return OSAtomicDecrement32Barrier(p); + else if (sizeof(int) == 8) + return OSAtomicDecrement64Barrier(p); + else + abort(); +#endif +} static OF_INLINE int32_t of_atomic_dec_32(volatile int32_t *p) { #if !defined(OF_THREADS) @@ -114,10 +285,42 @@ return __sync_sub_and_fetch(p, 1); #elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) return OSAtomicDecrement32Barrier(p); #endif } + +static OF_INLINE unsigned int +of_atomic_or_int(volatile unsigned int *p, unsigned int i) +{ +#if !defined(OF_THREADS) + return (*p |= i); +#elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) + __asm__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %2, %%eax\n\t" + "orl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0\n\t" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax" + ); + + return i; +#elif defined(OF_HAVE_GCC_ATOMIC_OPS) + return __sync_or_and_fetch(p, i); +#elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) + if (sizeof(int) == 4) + return OSAtomicOr32Barrier(i, p); + else if (sizeof(int) == 8) + return OSAtomicOr64Barrier(i, p); + else + abort(); +#endif +} static OF_INLINE uint32_t of_atomic_or_32(volatile uint32_t *p, uint32_t i) { #if !defined(OF_THREADS) @@ -141,10 +344,42 @@ return __sync_or_and_fetch(p, i); #elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) return OSAtomicOr32Barrier(i, p); #endif } + +static OF_INLINE unsigned int +of_atomic_and_int(volatile unsigned int *p, unsigned int i) +{ +#if !defined(OF_THREADS) + return (*p &= i); +#elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) + __asm__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %2, %%eax\n\t" + "andl %1, %0\n\t" + "lock\n\t" + "cmpxchg %0, %2\n\t" + "jne 0\n\t" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax" + ); + + return i; +#elif defined(OF_HAVE_GCC_ATOMIC_OPS) + return __sync_and_and_fetch(p, i); +#elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) + if (sizeof(int) == 4) + return OSAtomicAnd32Barrier(i, p); + else if (sizeof(int) == 8) + return OSAtomicAnd64Barrier(i, p); + else + abort(); +#endif +} static OF_INLINE uint32_t of_atomic_and_32(volatile uint32_t *p, uint32_t i) { #if !defined(OF_THREADS) @@ -168,10 +403,42 @@ return __sync_and_and_fetch(p, i); #elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) return OSAtomicAnd32Barrier(i, p); #endif } + +static OF_INLINE unsigned int +of_atomic_xor_int(volatile unsigned int *p, unsigned int i) +{ +#if !defined(OF_THREADS) + return (*p ^= i); +#elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) + __asm__ ( + "0:\n\t" + "movl %2, %0\n\t" + "movl %2, %%eax\n\t" + "xorl %1, %0\n\t" + "lock\n\t" + "cmpxchgl %0, %2\n\t" + "jne 0\n\t" + : "=&r"(i) + : "r"(i), "m"(*p) + : "eax" + ); + + return i; +#elif defined(OF_HAVE_GCC_ATOMIC_OPS) + return __sync_xor_and_fetch(p, i); +#elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) + if (sizeof(int) == 4) + return OSAtomicXor32Barrier(i, p); + else (sizeof(int) == 8) + return OSAtomicXor64Barrier(i, p); + else + abort(); +#endif +} static OF_INLINE uint32_t of_atomic_xor_32(volatile uint32_t *p, uint32_t i) { #if !defined(OF_THREADS) @@ -195,10 +462,42 @@ return __sync_xor_and_fetch(p, i); #elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) return OSAtomicXor32Barrier(i, p); #endif } + +static OF_INLINE BOOL +of_atomic_cmpswap_int(volatile int *p, int o, int n) +{ +#if !defined(OF_THREADS) + if (*p == o) { + *p = n; + return YES; + } + + return NO; +#elif defined(OF_X86_ASM) || defined(OF_AMD64_ASM) + int r; + + __asm__ ( + "lock\n\t" + "cmpxchg %2, %3\n\t" + "lahf\n\t" + "andb $64, %%ah\n\t" + "shrb $6, %%ah\n\t" + "movzx %%ah, %0\n\t" + : "=a"(r) + : "a"(o), "r"(n), "m"(*p) + ); + + return r; +#elif defined(OF_HAVE_GCC_ATOMIC_OPS) + return __sync_bool_compare_and_swap(p, o, n); +#elif defined(OF_HAVE_LIBKERN_OSATOMIC_H) + return OSAtomicCompareAndSwapIntBarrier(o, n, p); +#endif +} static OF_INLINE BOOL of_atomic_cmpswap_32(volatile int32_t *p, int32_t o, int32_t n) { #if !defined(OF_THREADS)