guard.cc revision 253159
1232950Stheraven/* 2232950Stheraven * Copyright 2010-2012 PathScale, Inc. All rights reserved. 3232950Stheraven * 4232950Stheraven * Redistribution and use in source and binary forms, with or without 5232950Stheraven * modification, are permitted provided that the following conditions are met: 6232950Stheraven * 7232950Stheraven * 1. Redistributions of source code must retain the above copyright notice, 8232950Stheraven * this list of conditions and the following disclaimer. 9232950Stheraven * 10232950Stheraven * 2. Redistributions in binary form must reproduce the above copyright notice, 11232950Stheraven * this list of conditions and the following disclaimer in the documentation 12232950Stheraven * and/or other materials provided with the distribution. 13232950Stheraven * 14232950Stheraven * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS 15232950Stheraven * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16232950Stheraven * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17232950Stheraven * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 18232950Stheraven * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19232950Stheraven * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20232950Stheraven * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21232950Stheraven * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22232950Stheraven * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23232950Stheraven * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24232950Stheraven * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25232950Stheraven */ 26232950Stheraven 27227825Stheraven/** 28227825Stheraven * guard.cc: Functions for thread-safe static initialisation. 29227825Stheraven * 30227825Stheraven * Static values in C++ can be initialised lazily their first use. This file 31227825Stheraven * contains functions that are used to ensure that two threads attempting to 32227825Stheraven * initialize the same static do not call the constructor twice. This is 33227825Stheraven * important because constructors can have side effects, so calling the 34227825Stheraven * constructor twice may be very bad. 35227825Stheraven * 36227825Stheraven * Statics that require initialisation are protected by a 64-bit value. Any 37227825Stheraven * platform that can do 32-bit atomic test and set operations can use this 38227825Stheraven * value as a low-overhead lock. Because statics (in most sane code) are 39227825Stheraven * accessed far more times than they are initialised, this lock implementation 40227825Stheraven * is heavily optimised towards the case where the static has already been 41227825Stheraven * initialised. 42227825Stheraven */ 43227825Stheraven#include <stdint.h> 44253159Stheraven#include <stdlib.h> 45253159Stheraven#include <stdio.h> 46227825Stheraven#include <pthread.h> 47227972Stheraven#include <assert.h> 48253159Stheraven#include "atomic.h" 49227825Stheraven 50253159Stheraven// Older GCC doesn't define __LITTLE_ENDIAN__ 51253159Stheraven#ifndef __LITTLE_ENDIAN__ 52253159Stheraven // If __BYTE_ORDER__ is defined, use that instead 53253159Stheraven# ifdef __BYTE_ORDER__ 54253159Stheraven# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 55253159Stheraven# define __LITTLE_ENDIAN__ 56253159Stheraven# endif 57253159Stheraven // x86 and ARM are the most common little-endian CPUs, so let's have a 58253159Stheraven // special case for them (ARM is already special cased). Assume everything 59253159Stheraven // else is big endian. 60253159Stheraven# elif defined(__x86_64) || defined(__i386) 61253159Stheraven# define __LITTLE_ENDIAN__ 62253159Stheraven# endif 63253159Stheraven#endif 64253159Stheraven 65253159Stheraven 66253159Stheraven/* 67253159Stheraven * The least significant bit of the guard variable indicates that the object 68253159Stheraven * has been initialised, the most significant bit is used for a spinlock. 69253159Stheraven */ 70227972Stheraven#ifdef __arm__ 71227972Stheraven// ARM ABI - 32-bit guards. 72253159Stheraventypedef uint32_t guard_t; 73253159Stheravenstatic const uint32_t LOCKED = ((guard_t)1) << 31; 74253159Stheravenstatic const uint32_t INITIALISED = 1; 75253159Stheraven#else 76253159Stheraventypedef uint64_t guard_t; 77253159Stheraven# if defined(__LITTLE_ENDIAN__) 78253159Stheravenstatic const guard_t LOCKED = ((guard_t)1) << 63; 79253159Stheravenstatic const guard_t INITIALISED = 1; 80253159Stheraven# else 81253159Stheravenstatic const guard_t LOCKED = 1; 82253159Stheravenstatic const guard_t INITIALISED = ((guard_t)1) << 56; 83253159Stheraven# endif 84253159Stheraven#endif 85227972Stheraven 86227825Stheraven/** 87227972Stheraven * Acquires a lock on a guard, returning 0 if the object has already been 88227972Stheraven * initialised, and 1 if it has not. If the object is already constructed then 89227972Stheraven * this function just needs to read a byte from memory and return. 90227972Stheraven */ 91253159Stheravenextern "C" int __cxa_guard_acquire(volatile guard_t *guard_object) 92227972Stheraven{ 93253159Stheraven // Not an atomic read, doesn't establish a happens-before relationship, but 94253159Stheraven // if one is already established and we end up seeing an initialised state 95253159Stheraven // then it's a fast path, otherwise we'll do something more expensive than 96253159Stheraven // this test anyway... 97253159Stheraven if ((INITIALISED == *guard_object)) { return 0; } 98253159Stheraven // Spin trying to do the initialisation 99253159Stheraven while (1) 100227972Stheraven { 101253159Stheraven // Loop trying to move the value of the guard from 0 (not 102253159Stheraven // locked, not initialised) to the locked-uninitialised 103253159Stheraven // position. 104253159Stheraven switch (__sync_val_compare_and_swap(guard_object, 0, LOCKED)) 105227972Stheraven { 106253159Stheraven // If the old value was 0, we succeeded, so continue 107253159Stheraven // initialising 108253159Stheraven case 0: 109253159Stheraven return 1; 110253159Stheraven // If this was already initialised, return and let the caller skip 111253159Stheraven // initialising it again. 112253159Stheraven case INITIALISED: 113253159Stheraven return 0; 114253159Stheraven // If it is locked by another thread, relinquish the CPU and try 115253159Stheraven // again later. 116253159Stheraven case LOCKED: 117253159Stheraven case LOCKED | INITIALISED: 118253159Stheraven sched_yield(); 119253159Stheraven break; 120253159Stheraven // If it is some other value, then something has gone badly wrong. 121253159Stheraven // Give up. 122253159Stheraven default: 123253159Stheraven fprintf(stderr, "Invalid state detected attempting to lock static initialiser.\n"); 124253159Stheraven abort(); 125227972Stheraven } 126227972Stheraven } 127253159Stheraven //__builtin_unreachable(); 128227972Stheraven return 0; 129227972Stheraven} 130227972Stheraven 131227972Stheraven/** 132227972Stheraven * Releases the lock without marking the object as initialised. This function 133227972Stheraven * is called if initialising a static causes an exception to be thrown. 134227972Stheraven */ 135253159Stheravenextern "C" void __cxa_guard_abort(volatile guard_t *guard_object) 136227972Stheraven{ 137253159Stheraven __attribute__((unused)) 138253159Stheraven bool reset = __sync_bool_compare_and_swap(guard_object, LOCKED, 0); 139253159Stheraven assert(reset); 140227972Stheraven} 141227972Stheraven/** 142227972Stheraven * Releases the guard and marks the object as initialised. This function is 143227972Stheraven * called after successful initialisation of a static. 144227972Stheraven */ 145253159Stheravenextern "C" void __cxa_guard_release(volatile guard_t *guard_object) 146227972Stheraven{ 147253159Stheraven __attribute__((unused)) 148253159Stheraven bool reset = __sync_bool_compare_and_swap(guard_object, LOCKED, INITIALISED); 149253159Stheraven assert(reset); 150227972Stheraven} 151227972Stheraven 152227972Stheraven 153