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