X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..cc9f6e38162d3c1bf6ca97536c2477f476c8e01b:/libkern/gen/OSAtomicOperations.c?ds=inline diff --git a/libkern/gen/OSAtomicOperations.c b/libkern/gen/OSAtomicOperations.c index 735fa2ac3..4a1e7beb0 100644 --- a/libkern/gen/OSAtomicOperations.c +++ b/libkern/gen/OSAtomicOperations.c @@ -39,6 +39,11 @@ enum { * which I wrote for NuKernel in a previous life with a different last name...) * * native Boolean CompareAndSwap(UInt32 oldValue, UInt32 newValue, UInt32 * oldValuePtr); + * + * We've since implemented a few more of these -- OSAddAtomic, OSDequeueAtomic, + * OSEnqueueAtomic etc -- in assembler, either for speed or correctness. See also the + * commpage atomic operations, and the platform specific versions. + * Like standards, there are a lot of atomic ops to choose from! */ #ifndef __ppc__ @@ -66,6 +71,37 @@ SInt32 OSDecrementAtomic(SInt32 * value) return OSAddAtomic(-1, value); } +void * OSDequeueAtomic(void ** inList, SInt32 inOffset) +{ + void * oldListHead; + void * newListHead; + + do { + oldListHead = *inList; + if (oldListHead == NULL) { + break; + } + + newListHead = *(void **) (((char *) oldListHead) + inOffset); + } while (! OSCompareAndSwap((UInt32)oldListHead, + (UInt32)newListHead, (UInt32 *)inList)); + + return oldListHead; +} + +void OSEnqueueAtomic(void ** inList, void * inNewLink, SInt32 inOffset) +{ + void * oldListHead; + void * newListHead = inNewLink; + void ** newLinkNextPtr = (void **) (((char *) inNewLink) + inOffset); + + do { + oldListHead = *inList; + *newLinkNextPtr = oldListHead; + } while (! OSCompareAndSwap((UInt32)oldListHead, (UInt32)newListHead, + (UInt32 *)inList)); +} + #endif /* !__ppc__ */ static UInt32 OSBitwiseAtomic(UInt32 and_mask, UInt32 or_mask, UInt32 xor_mask, UInt32 * value) @@ -96,45 +132,23 @@ UInt32 OSBitXorAtomic(UInt32 mask, UInt32 * value) return OSBitwiseAtomic((UInt32) -1, 0, mask, value); } - -static Boolean OSCompareAndSwap8(UInt8 oldValue8, UInt8 newValue8, UInt8 * value8) +static Boolean OSCompareAndSwap8(UInt8 oldValue8, UInt8 newValue8, UInt8 * value8) { - UInt32 mask = 0x000000ff; - UInt32 newbits = (UInt32) newValue8; - int shift; - UInt32 alignment = ((UInt32) value8) & (sizeof(UInt32) - 1); - UInt32 oldValue; - UInt32 newValue; - UInt32 * value; - - switch (alignment) { - default: - // assert(false); - case 0: - value = (UInt32 *) value8; - shift = 24; - break; - case 1: - value = (UInt32 *) (value8 + 1); - shift = 16; - break; - case 2: - value = (UInt32 *) (value8 + 2); - shift = 8; - break; - case 3: - value = (UInt32 *) (value8 + 3); - shift = 0; - break; - } + UInt32 mask = 0x000000ff; + UInt32 alignment = ((UInt32) value8) & (sizeof(UInt32) - 1); + UInt32 shiftValues = (24 << 24) | (16 << 16) | (8 << 8); + int shift = (UInt32) *(((UInt8 *) &shiftValues) + alignment); + UInt32 * value32 = (UInt32 *) (value8 - alignment); + UInt32 oldValue; + UInt32 newValue; - mask <<= shift; - newbits <<= shift; - - oldValue = *value; - newValue = (oldValue & ~mask) | (newbits & mask); - - return OSCompareAndSwap(oldValue, newValue, value); + mask <<= shift; + + oldValue = *value32; + oldValue = (oldValue & ~mask) | (oldValue8 << shift); + newValue = (oldValue & ~mask) | (newValue8 << shift); + + return OSCompareAndSwap(oldValue, newValue, value32); } static Boolean OSTestAndSetClear(UInt32 bit, Boolean wantSet, UInt8 * startAddress) @@ -167,37 +181,6 @@ Boolean OSTestAndClear(UInt32 bit, UInt8 * startAddress) return OSTestAndSetClear(bit, false, startAddress); } -void * OSDequeueAtomic(void ** inList, SInt32 inOffset) -{ - void * oldListHead; - void * newListHead; - - do { - oldListHead = *inList; - if (oldListHead == NULL) { - break; - } - - newListHead = *(void **) (((char *) oldListHead) + inOffset); - } while (! OSCompareAndSwap((UInt32)oldListHead, - (UInt32)newListHead, (UInt32 *)inList)); - - return oldListHead; -} - -void OSEnqueueAtomic(void ** inList, void * inNewLink, SInt32 inOffset) -{ - void * oldListHead; - void * newListHead = inNewLink; - void ** newLinkNextPtr = (void **) (((char *) inNewLink) + inOffset); - - do { - oldListHead = *inList; - *newLinkNextPtr = oldListHead; - } while (! OSCompareAndSwap((UInt32)oldListHead, (UInt32)newListHead, - (UInt32 *)inList)); -} - /* * silly unaligned versions */ @@ -253,34 +236,23 @@ UInt8 OSBitXorAtomic8(UInt32 mask, UInt8 * value) return OSBitwiseAtomic8((UInt32) -1, 0, mask, value); } - -static Boolean OSCompareAndSwap16(UInt16 oldValue16, UInt16 newValue16, UInt16 * value16) +static Boolean OSCompareAndSwap16(UInt16 oldValue16, UInt16 newValue16, UInt16 * value16) { - UInt32 mask = 0x0000ffff; - UInt32 newbits = (UInt32) newValue16; - int shift; - UInt32 alignment = ((UInt32) value16) & (sizeof(UInt32) - 1); - UInt32 oldValue; - UInt32 newValue; - UInt32 * value; - - if (alignment == 2) { - value = (UInt32 *) (value16 - 1); - shift = 0; - } - else { - // assert(alignment == 0); - value = (UInt32 *) value16; - shift = 16; - } - - mask <<= shift; - newbits <<= shift; - - oldValue = *value; - newValue = (oldValue & ~mask) | (newbits & mask); - - return OSCompareAndSwap(oldValue, newValue, value); + UInt32 mask = 0x0000ffff; + UInt32 alignment = ((UInt32) value16) & (sizeof(UInt32) - 1); + UInt32 shiftValues = (16 << 24) | (16 << 16); + UInt32 shift = (UInt32) *(((UInt8 *) &shiftValues) + alignment); + UInt32 * value32 = (UInt32 *) (((UInt32) value16) - alignment); + UInt32 oldValue; + UInt32 newValue; + + mask <<= shift; + + oldValue = *value32; + oldValue = (oldValue & ~mask) | (oldValue16 << shift); + newValue = (oldValue & ~mask) | (newValue16 << shift); + + return OSCompareAndSwap(oldValue, newValue, value32); } SInt16 OSIncrementAtomic16(SInt16 * value)