|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: ! 23: #include <libkern/OSAtomic.h> ! 24: ! 25: enum { ! 26: false = 0, ! 27: true = 1 ! 28: }; ! 29: #define NULL 0L ! 30: ! 31: ! 32: /* ! 33: * atomic operations ! 34: * these are _the_ atomic operations, currently cast atop CompareAndSwap, ! 35: * which is implemented in assembler. if we are worried about the cost of ! 36: * this layering (we shouldn't be), then all this stuff could be ! 37: * implemented in assembler, as it is in MacOS8/9 ! 38: * (derived from SuperMario/NativeLibs/IO/DriverServices/Synchronization.s, ! 39: * which I wrote for NuKernel in a previous life with a different last name...) ! 40: * ! 41: * native Boolean CompareAndSwap(UInt32 oldValue, UInt32 newValue, UInt32 * oldValuePtr); ! 42: */ ! 43: ! 44: #ifndef __ppc__ ! 45: ! 46: SInt32 OSAddAtomic(SInt32 amount, SInt32 * value) ! 47: { ! 48: SInt32 oldValue; ! 49: SInt32 newValue; ! 50: ! 51: do { ! 52: oldValue = *value; ! 53: newValue = oldValue + amount; ! 54: } while (! OSCompareAndSwap((UInt32) oldValue, (UInt32) newValue, (UInt32 *) value)); ! 55: ! 56: return oldValue; ! 57: } ! 58: ! 59: SInt32 OSIncrementAtomic(SInt32 * value) ! 60: { ! 61: return OSAddAtomic(1, value); ! 62: } ! 63: ! 64: SInt32 OSDecrementAtomic(SInt32 * value) ! 65: { ! 66: return OSAddAtomic(-1, value); ! 67: } ! 68: ! 69: #endif /* !__ppc__ */ ! 70: ! 71: static UInt32 OSBitwiseAtomic(UInt32 and_mask, UInt32 or_mask, UInt32 xor_mask, UInt32 * value) ! 72: { ! 73: UInt32 oldValue; ! 74: UInt32 newValue; ! 75: ! 76: do { ! 77: oldValue = *value; ! 78: newValue = ((oldValue & and_mask) | or_mask) ^ xor_mask; ! 79: } while (! OSCompareAndSwap(oldValue, newValue, value)); ! 80: ! 81: return oldValue; ! 82: } ! 83: ! 84: UInt32 OSBitAndAtomic(UInt32 mask, UInt32 * value) ! 85: { ! 86: return OSBitwiseAtomic(mask, 0, 0, value); ! 87: } ! 88: ! 89: UInt32 OSBitOrAtomic(UInt32 mask, UInt32 * value) ! 90: { ! 91: return OSBitwiseAtomic((UInt32) -1, mask, 0, value); ! 92: } ! 93: ! 94: UInt32 OSBitXorAtomic(UInt32 mask, UInt32 * value) ! 95: { ! 96: return OSBitwiseAtomic((UInt32) -1, 0, mask, value); ! 97: } ! 98: ! 99: ! 100: static Boolean OSCompareAndSwap8(UInt8 oldValue8, UInt8 newValue8, UInt8 * value8) ! 101: { ! 102: UInt32 mask = 0x000000ff; ! 103: UInt32 newbits = (UInt32) newValue8; ! 104: int shift; ! 105: UInt32 alignment = ((UInt32) value8) & (sizeof(UInt32) - 1); ! 106: UInt32 oldValue; ! 107: UInt32 newValue; ! 108: UInt32 * value; ! 109: ! 110: switch (alignment) { ! 111: default: ! 112: // assert(false); ! 113: case 0: ! 114: value = (UInt32 *) value8; ! 115: shift = 24; ! 116: break; ! 117: case 1: ! 118: value = (UInt32 *) (value8 + 1); ! 119: shift = 16; ! 120: break; ! 121: case 2: ! 122: value = (UInt32 *) (value8 + 2); ! 123: shift = 8; ! 124: break; ! 125: case 3: ! 126: value = (UInt32 *) (value8 + 3); ! 127: shift = 0; ! 128: break; ! 129: } ! 130: ! 131: mask <<= shift; ! 132: newbits <<= shift; ! 133: ! 134: oldValue = *value; ! 135: newValue = (oldValue & ~mask) | (newbits & mask); ! 136: ! 137: return OSCompareAndSwap(oldValue, newValue, value); ! 138: } ! 139: ! 140: static Boolean OSTestAndSetClear(UInt32 bit, Boolean wantSet, UInt8 * startAddress) ! 141: { ! 142: UInt8 mask = 1; ! 143: UInt8 oldValue; ! 144: UInt8 wantValue; ! 145: ! 146: startAddress += (bit / 8); ! 147: mask <<= (7 - (bit % 8)); ! 148: wantValue = wantSet ? mask : 0; ! 149: ! 150: do { ! 151: oldValue = *startAddress; ! 152: if ((oldValue & mask) == wantValue) { ! 153: break; ! 154: } ! 155: } while (! OSCompareAndSwap8(oldValue, (oldValue & ~mask) | wantValue, startAddress)); ! 156: ! 157: return (oldValue & mask) == wantValue; ! 158: } ! 159: ! 160: Boolean OSTestAndSet(UInt32 bit, UInt8 * startAddress) ! 161: { ! 162: return OSTestAndSetClear(bit, true, startAddress); ! 163: } ! 164: ! 165: Boolean OSTestAndClear(UInt32 bit, UInt8 * startAddress) ! 166: { ! 167: return OSTestAndSetClear(bit, false, startAddress); ! 168: } ! 169: ! 170: void * OSDequeueAtomic(void ** inList, SInt32 inOffset) ! 171: { ! 172: void * oldListHead; ! 173: void * newListHead; ! 174: ! 175: do { ! 176: oldListHead = *inList; ! 177: if (oldListHead == NULL) { ! 178: break; ! 179: } ! 180: ! 181: newListHead = *(void **) (((char *) oldListHead) + inOffset); ! 182: } while (! OSCompareAndSwap((UInt32)oldListHead, ! 183: (UInt32)newListHead, (UInt32 *)inList)); ! 184: ! 185: return oldListHead; ! 186: } ! 187: ! 188: void OSEnqueueAtomic(void ** inList, void * inNewLink, SInt32 inOffset) ! 189: { ! 190: void * oldListHead; ! 191: void * newListHead = inNewLink; ! 192: void ** newLinkNextPtr = (void **) (((char *) inNewLink) + inOffset); ! 193: ! 194: do { ! 195: oldListHead = *inList; ! 196: *newLinkNextPtr = oldListHead; ! 197: } while (! OSCompareAndSwap((UInt32)oldListHead, (UInt32)newListHead, ! 198: (UInt32 *)inList)); ! 199: } ! 200: ! 201: /* ! 202: * silly unaligned versions ! 203: */ ! 204: ! 205: SInt8 OSIncrementAtomic8(SInt8 * value) ! 206: { ! 207: return OSAddAtomic8(1, value); ! 208: } ! 209: ! 210: SInt8 OSDecrementAtomic8(SInt8 * value) ! 211: { ! 212: return OSAddAtomic8(-1, value); ! 213: } ! 214: ! 215: SInt8 OSAddAtomic8(SInt32 amount, SInt8 * value) ! 216: { ! 217: SInt8 oldValue; ! 218: SInt8 newValue; ! 219: ! 220: do { ! 221: oldValue = *value; ! 222: newValue = oldValue + amount; ! 223: } while (! OSCompareAndSwap8((UInt8) oldValue, (UInt8) newValue, (UInt8 *) value)); ! 224: ! 225: return oldValue; ! 226: } ! 227: ! 228: static UInt8 OSBitwiseAtomic8(UInt32 and_mask, UInt32 or_mask, UInt32 xor_mask, UInt8 * value) ! 229: { ! 230: UInt8 oldValue; ! 231: UInt8 newValue; ! 232: ! 233: do { ! 234: oldValue = *value; ! 235: newValue = ((oldValue & and_mask) | or_mask) ^ xor_mask; ! 236: } while (! OSCompareAndSwap8(oldValue, newValue, value)); ! 237: ! 238: return oldValue; ! 239: } ! 240: ! 241: UInt8 OSBitAndAtomic8(UInt32 mask, UInt8 * value) ! 242: { ! 243: return OSBitwiseAtomic8(mask, 0, 0, value); ! 244: } ! 245: ! 246: UInt8 OSBitOrAtomic8(UInt32 mask, UInt8 * value) ! 247: { ! 248: return OSBitwiseAtomic8((UInt32) -1, mask, 0, value); ! 249: } ! 250: ! 251: UInt8 OSBitXorAtomic8(UInt32 mask, UInt8 * value) ! 252: { ! 253: return OSBitwiseAtomic8((UInt32) -1, 0, mask, value); ! 254: } ! 255: ! 256: ! 257: static Boolean OSCompareAndSwap16(UInt16 oldValue16, UInt16 newValue16, UInt16 * value16) ! 258: { ! 259: UInt32 mask = 0x0000ffff; ! 260: UInt32 newbits = (UInt32) newValue16; ! 261: int shift; ! 262: UInt32 alignment = ((UInt32) value16) & (sizeof(UInt32) - 1); ! 263: UInt32 oldValue; ! 264: UInt32 newValue; ! 265: UInt32 * value; ! 266: ! 267: if (alignment == 2) { ! 268: value = (UInt32 *) (value16 - 1); ! 269: shift = 0; ! 270: } ! 271: else { ! 272: // assert(alignment == 0); ! 273: value = (UInt32 *) value16; ! 274: shift = 16; ! 275: } ! 276: ! 277: mask <<= shift; ! 278: newbits <<= shift; ! 279: ! 280: oldValue = *value; ! 281: newValue = (oldValue & ~mask) | (newbits & mask); ! 282: ! 283: return OSCompareAndSwap(oldValue, newValue, value); ! 284: } ! 285: ! 286: SInt16 OSIncrementAtomic16(SInt16 * value) ! 287: { ! 288: return OSAddAtomic16(1, value); ! 289: } ! 290: ! 291: SInt16 OSDecrementAtomic16(SInt16 * value) ! 292: { ! 293: return OSAddAtomic16(-1, value); ! 294: } ! 295: ! 296: SInt16 OSAddAtomic16(SInt32 amount, SInt16 * value) ! 297: { ! 298: SInt16 oldValue; ! 299: SInt16 newValue; ! 300: ! 301: do { ! 302: oldValue = *value; ! 303: newValue = oldValue + amount; ! 304: } while (! OSCompareAndSwap16((UInt16) oldValue, (UInt16) newValue, (UInt16 *) value)); ! 305: ! 306: return oldValue; ! 307: } ! 308: ! 309: static UInt16 OSBitwiseAtomic16(UInt32 and_mask, UInt32 or_mask, UInt32 xor_mask, UInt16 * value) ! 310: { ! 311: UInt16 oldValue; ! 312: UInt16 newValue; ! 313: ! 314: do { ! 315: oldValue = *value; ! 316: newValue = ((oldValue & and_mask) | or_mask) ^ xor_mask; ! 317: } while (! OSCompareAndSwap16(oldValue, newValue, value)); ! 318: ! 319: return oldValue; ! 320: } ! 321: ! 322: UInt16 OSBitAndAtomic16(UInt32 mask, UInt16 * value) ! 323: { ! 324: return OSBitwiseAtomic16(mask, 0, 0, value); ! 325: } ! 326: ! 327: UInt16 OSBitOrAtomic16(UInt32 mask, UInt16 * value) ! 328: { ! 329: return OSBitwiseAtomic16((UInt32) -1, mask, 0, value); ! 330: } ! 331: ! 332: UInt16 OSBitXorAtomic16(UInt32 mask, UInt16 * value) ! 333: { ! 334: return OSBitwiseAtomic16((UInt32) -1, 0, mask, value); ! 335: } ! 336:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.