darwin-xnu/libkern/gen/OSAtomicOperations.c
<<
>>
Prefs
   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
  25enum {
  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 * We've since implemented a few more of these -- OSAddAtomic, OSDequeueAtomic,
  44 * OSEnqueueAtomic etc -- in assembler, either for speed or correctness.  See also the
  45 * commpage atomic operations, and the platform specific versions.
  46 * Like standards, there are a lot of atomic ops to choose from!
  47 */
  48
  49#ifndef __ppc__
  50
  51SInt32  OSAddAtomic(SInt32 amount, SInt32 * value)
  52{
  53        SInt32  oldValue;
  54        SInt32  newValue;
  55        
  56        do {
  57                oldValue = *value;
  58                newValue = oldValue + amount;
  59        } while (! OSCompareAndSwap((UInt32) oldValue, (UInt32) newValue, (UInt32 *) value));
  60        
  61        return oldValue;
  62}
  63
  64SInt32  OSIncrementAtomic(SInt32 * value)
  65{
  66        return OSAddAtomic(1, value);
  67}
  68
  69SInt32  OSDecrementAtomic(SInt32 * value)
  70{
  71        return OSAddAtomic(-1, value);
  72}
  73
  74void *  OSDequeueAtomic(void ** inList, SInt32 inOffset)
  75{
  76        void *  oldListHead;
  77        void *  newListHead;
  78        
  79        do {
  80                oldListHead = *inList;
  81                if (oldListHead == NULL) {
  82                        break;
  83                }
  84                
  85                newListHead = *(void **) (((char *) oldListHead) + inOffset);
  86        } while (! OSCompareAndSwap((UInt32)oldListHead,
  87                                        (UInt32)newListHead, (UInt32 *)inList));
  88        
  89        return oldListHead;
  90}
  91
  92void    OSEnqueueAtomic(void ** inList, void * inNewLink, SInt32 inOffset)
  93{
  94        void *  oldListHead;
  95        void *  newListHead = inNewLink;
  96        void ** newLinkNextPtr = (void **) (((char *) inNewLink) + inOffset);
  97        
  98        do {
  99                oldListHead = *inList;
 100                *newLinkNextPtr = oldListHead;
 101        } while (! OSCompareAndSwap((UInt32)oldListHead, (UInt32)newListHead,
 102                                        (UInt32 *)inList));
 103}
 104
 105#endif  /* !__ppc__ */
 106
 107static UInt32   OSBitwiseAtomic(UInt32 and_mask, UInt32 or_mask, UInt32 xor_mask, UInt32 * value)
 108{
 109        UInt32  oldValue;
 110        UInt32  newValue;
 111        
 112        do {
 113                oldValue = *value;
 114                newValue = ((oldValue & and_mask) | or_mask) ^ xor_mask;
 115        } while (! OSCompareAndSwap(oldValue, newValue, value));
 116        
 117        return oldValue;
 118}
 119
 120UInt32  OSBitAndAtomic(UInt32 mask, UInt32 * value)
 121{
 122        return OSBitwiseAtomic(mask, 0, 0, value);
 123}
 124
 125UInt32  OSBitOrAtomic(UInt32 mask, UInt32 * value)
 126{
 127        return OSBitwiseAtomic((UInt32) -1, mask, 0, value);
 128}
 129
 130UInt32  OSBitXorAtomic(UInt32 mask, UInt32 * value)
 131{
 132        return OSBitwiseAtomic((UInt32) -1, 0, mask, value);
 133}
 134
 135static Boolean OSCompareAndSwap8(UInt8 oldValue8, UInt8 newValue8, UInt8 * value8)
 136{
 137        UInt32          mask        = 0x000000ff;
 138        UInt32          alignment   = ((UInt32) value8) & (sizeof(UInt32) - 1);
 139    UInt32      shiftValues = (24 << 24) | (16 << 16) | (8 << 8);
 140    int                 shift       = (UInt32) *(((UInt8 *) &shiftValues) + alignment);
 141        UInt32 *        value32     = (UInt32 *) (value8 - alignment);
 142    UInt32      oldValue;
 143    UInt32      newValue;
 144
 145    mask <<= shift;
 146
 147    oldValue = *value32;
 148    oldValue = (oldValue & ~mask) | (oldValue8 << shift);
 149    newValue = (oldValue & ~mask) | (newValue8 << shift);
 150
 151        return OSCompareAndSwap(oldValue, newValue, value32);
 152}
 153
 154static Boolean  OSTestAndSetClear(UInt32 bit, Boolean wantSet, UInt8 * startAddress)
 155{
 156        UInt8           mask = 1;
 157        UInt8           oldValue;
 158        UInt8           wantValue;
 159        
 160        startAddress += (bit / 8);
 161        mask <<= (7 - (bit % 8));
 162        wantValue = wantSet ? mask : 0;
 163        
 164        do {
 165                oldValue = *startAddress;
 166                if ((oldValue & mask) == wantValue) {
 167                        break;
 168                }
 169        } while (! OSCompareAndSwap8(oldValue, (oldValue & ~mask) | wantValue, startAddress));
 170        
 171        return (oldValue & mask) == wantValue;
 172}
 173
 174Boolean OSTestAndSet(UInt32 bit, UInt8 * startAddress)
 175{
 176        return OSTestAndSetClear(bit, true, startAddress);
 177}
 178
 179Boolean OSTestAndClear(UInt32 bit, UInt8 * startAddress)
 180{
 181        return OSTestAndSetClear(bit, false, startAddress);
 182}
 183
 184/*
 185 * silly unaligned versions
 186 */
 187
 188SInt8   OSIncrementAtomic8(SInt8 * value)
 189{
 190        return OSAddAtomic8(1, value);
 191}
 192
 193SInt8   OSDecrementAtomic8(SInt8 * value)
 194{
 195        return OSAddAtomic8(-1, value);
 196}
 197
 198SInt8   OSAddAtomic8(SInt32 amount, SInt8 * value)
 199{
 200        SInt8   oldValue;
 201        SInt8   newValue;
 202        
 203        do {
 204                oldValue = *value;
 205                newValue = oldValue + amount;
 206        } while (! OSCompareAndSwap8((UInt8) oldValue, (UInt8) newValue, (UInt8 *) value));
 207        
 208        return oldValue;
 209}
 210
 211static UInt8    OSBitwiseAtomic8(UInt32 and_mask, UInt32 or_mask, UInt32 xor_mask, UInt8 * value)
 212{
 213        UInt8   oldValue;
 214        UInt8   newValue;
 215        
 216        do {
 217                oldValue = *value;
 218                newValue = ((oldValue & and_mask) | or_mask) ^ xor_mask;
 219        } while (! OSCompareAndSwap8(oldValue, newValue, value));
 220        
 221        return oldValue;
 222}
 223
 224UInt8   OSBitAndAtomic8(UInt32 mask, UInt8 * value)
 225{
 226        return OSBitwiseAtomic8(mask, 0, 0, value);
 227}
 228
 229UInt8   OSBitOrAtomic8(UInt32 mask, UInt8 * value)
 230{
 231        return OSBitwiseAtomic8((UInt32) -1, mask, 0, value);
 232}
 233
 234UInt8   OSBitXorAtomic8(UInt32 mask, UInt8 * value)
 235{
 236        return OSBitwiseAtomic8((UInt32) -1, 0, mask, value);
 237}
 238
 239static Boolean OSCompareAndSwap16(UInt16 oldValue16, UInt16 newValue16, UInt16 * value16)
 240{
 241        UInt32          mask        = 0x0000ffff;
 242        UInt32          alignment   = ((UInt32) value16) & (sizeof(UInt32) - 1);
 243    UInt32      shiftValues = (16 << 24) | (16 << 16);
 244    UInt32              shift       = (UInt32) *(((UInt8 *) &shiftValues) + alignment);
 245        UInt32 *        value32     = (UInt32 *) (((UInt32) value16) - alignment);
 246    UInt32      oldValue;
 247    UInt32      newValue;
 248
 249    mask <<= shift;
 250
 251    oldValue = *value32;
 252    oldValue = (oldValue & ~mask) | (oldValue16 << shift);
 253    newValue = (oldValue & ~mask) | (newValue16 << shift);
 254
 255        return OSCompareAndSwap(oldValue, newValue, value32);
 256}
 257
 258SInt16  OSIncrementAtomic16(SInt16 * value)
 259{
 260        return OSAddAtomic16(1, value);
 261}
 262
 263SInt16  OSDecrementAtomic16(SInt16 * value)
 264{
 265        return OSAddAtomic16(-1, value);
 266}
 267
 268SInt16  OSAddAtomic16(SInt32 amount, SInt16 * value)
 269{
 270        SInt16  oldValue;
 271        SInt16  newValue;
 272        
 273        do {
 274                oldValue = *value;
 275                newValue = oldValue + amount;
 276        } while (! OSCompareAndSwap16((UInt16) oldValue, (UInt16) newValue, (UInt16 *) value));
 277        
 278        return oldValue;
 279}
 280
 281static UInt16   OSBitwiseAtomic16(UInt32 and_mask, UInt32 or_mask, UInt32 xor_mask, UInt16 * value)
 282{
 283        UInt16  oldValue;
 284        UInt16  newValue;
 285        
 286        do {
 287                oldValue = *value;
 288                newValue = ((oldValue & and_mask) | or_mask) ^ xor_mask;
 289        } while (! OSCompareAndSwap16(oldValue, newValue, value));
 290        
 291        return oldValue;
 292}
 293
 294UInt16  OSBitAndAtomic16(UInt32 mask, UInt16 * value)
 295{
 296        return OSBitwiseAtomic16(mask, 0, 0, value);
 297}
 298
 299UInt16  OSBitOrAtomic16(UInt32 mask, UInt16 * value)
 300{
 301        return OSBitwiseAtomic16((UInt32) -1, mask, 0, value);
 302}
 303
 304UInt16  OSBitXorAtomic16(UInt32 mask, UInt16 * value)
 305{
 306        return OSBitwiseAtomic16((UInt32) -1, 0, mask, value);
 307}
 308
 309
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.