xref: /freebsd/contrib/libcxxrt/guard.cc (revision 7819a911ff5132b34996c8b09b2a024cd10fd4fb)
194e3ee44SDavid Chisnall /*
294e3ee44SDavid Chisnall  * Copyright 2010-2012 PathScale, Inc. All rights reserved.
3bfffb66eSDimitry Andric  * Copyright 2021 David Chisnall. All rights reserved.
494e3ee44SDavid Chisnall  *
594e3ee44SDavid Chisnall  * Redistribution and use in source and binary forms, with or without
694e3ee44SDavid Chisnall  * modification, are permitted provided that the following conditions are met:
794e3ee44SDavid Chisnall  *
894e3ee44SDavid Chisnall  * 1. Redistributions of source code must retain the above copyright notice,
994e3ee44SDavid Chisnall  *    this list of conditions and the following disclaimer.
1094e3ee44SDavid Chisnall  *
1194e3ee44SDavid Chisnall  * 2. Redistributions in binary form must reproduce the above copyright notice,
1294e3ee44SDavid Chisnall  *    this list of conditions and the following disclaimer in the documentation
1394e3ee44SDavid Chisnall  *    and/or other materials provided with the distribution.
1494e3ee44SDavid Chisnall  *
1594e3ee44SDavid Chisnall  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
1694e3ee44SDavid Chisnall  * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
1794e3ee44SDavid Chisnall  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1894e3ee44SDavid Chisnall  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
1994e3ee44SDavid Chisnall  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2094e3ee44SDavid Chisnall  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2194e3ee44SDavid Chisnall  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
2294e3ee44SDavid Chisnall  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2394e3ee44SDavid Chisnall  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2494e3ee44SDavid Chisnall  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2594e3ee44SDavid Chisnall  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2694e3ee44SDavid Chisnall  */
2794e3ee44SDavid Chisnall 
287a984708SDavid Chisnall /**
297a984708SDavid Chisnall  * guard.cc: Functions for thread-safe static initialisation.
307a984708SDavid Chisnall  *
317a984708SDavid Chisnall  * Static values in C++ can be initialised lazily their first use.  This file
327a984708SDavid Chisnall  * contains functions that are used to ensure that two threads attempting to
337a984708SDavid Chisnall  * initialize the same static do not call the constructor twice.  This is
347a984708SDavid Chisnall  * important because constructors can have side effects, so calling the
357a984708SDavid Chisnall  * constructor twice may be very bad.
367a984708SDavid Chisnall  *
377a984708SDavid Chisnall  * Statics that require initialisation are protected by a 64-bit value.  Any
387a984708SDavid Chisnall  * platform that can do 32-bit atomic test and set operations can use this
397a984708SDavid Chisnall  * value as a low-overhead lock.  Because statics (in most sane code) are
407a984708SDavid Chisnall  * accessed far more times than they are initialised, this lock implementation
417a984708SDavid Chisnall  * is heavily optimised towards the case where the static has already been
427a984708SDavid Chisnall  * initialised.
437a984708SDavid Chisnall  */
44bfffb66eSDimitry Andric #include "atomic.h"
45bfffb66eSDimitry Andric #include <assert.h>
46bfffb66eSDimitry Andric #include <pthread.h>
477a984708SDavid Chisnall #include <stdint.h>
484bab9fd9SDavid Chisnall #include <stdlib.h>
497a984708SDavid Chisnall 
504bab9fd9SDavid Chisnall // Older GCC doesn't define __LITTLE_ENDIAN__
514bab9fd9SDavid Chisnall #ifndef __LITTLE_ENDIAN__
524bab9fd9SDavid Chisnall // If __BYTE_ORDER__ is defined, use that instead
534bab9fd9SDavid Chisnall #	ifdef __BYTE_ORDER__
544bab9fd9SDavid Chisnall #		if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
554bab9fd9SDavid Chisnall #			define __LITTLE_ENDIAN__
564bab9fd9SDavid Chisnall #		endif
574bab9fd9SDavid Chisnall // x86 and ARM are the most common little-endian CPUs, so let's have a
584bab9fd9SDavid Chisnall // special case for them (ARM is already special cased).  Assume everything
594bab9fd9SDavid Chisnall // else is big endian.
604bab9fd9SDavid Chisnall #	elif defined(__x86_64) || defined(__i386)
614bab9fd9SDavid Chisnall #		define __LITTLE_ENDIAN__
624bab9fd9SDavid Chisnall #	endif
634bab9fd9SDavid Chisnall #endif
644bab9fd9SDavid Chisnall 
654bab9fd9SDavid Chisnall /*
66bfffb66eSDimitry Andric  * The Itanium C++ ABI defines guard words that are 64-bit (32-bit on AArch32)
67bfffb66eSDimitry Andric  * values with one bit defined to indicate that the guarded variable is and
68bfffb66eSDimitry Andric  * another bit to indicate that it's currently locked (initialisation in
69bfffb66eSDimitry Andric  * progress).  The bit to use depends on the byte order of the target.
70bfffb66eSDimitry Andric  *
71bfffb66eSDimitry Andric  * On many 32-bit platforms, 64-bit atomics are unavailable (or slow) and so we
72*7819a911SDimitry Andric  * treat the two halves of the 64-bit word as independent values and establish
73*7819a911SDimitry Andric  * an ordering on them such that the guard word is never modified unless the
74*7819a911SDimitry Andric  * lock word is in the locked state.  This means that we can do double-checked
75*7819a911SDimitry Andric  * locking by loading the guard word and, if it is not initialised, trying to
76*7819a911SDimitry Andric  * transition the lock word from the unlocked to locked state, and then
77*7819a911SDimitry Andric  * manipulate the guard word.
784bab9fd9SDavid Chisnall  */
79bfffb66eSDimitry Andric namespace
80bfffb66eSDimitry Andric {
81bfffb66eSDimitry Andric 	/**
82bfffb66eSDimitry Andric 	 * The state of the guard variable when an attempt is made to lock it.
83bfffb66eSDimitry Andric 	 */
84bfffb66eSDimitry Andric 	enum class GuardState
85bfffb66eSDimitry Andric 	{
86bfffb66eSDimitry Andric 		/**
87bfffb66eSDimitry Andric 		 * The lock is not held but is not needed because initialisation is
88bfffb66eSDimitry Andric 		 * one.
89bfffb66eSDimitry Andric 		 */
90bfffb66eSDimitry Andric 		InitDone,
91bfffb66eSDimitry Andric 
92bfffb66eSDimitry Andric 		/**
93bfffb66eSDimitry Andric 		 * Initialisation is not done but the lock is held by the caller.
94bfffb66eSDimitry Andric 		 */
95bfffb66eSDimitry Andric 		InitLockSucceeded,
96bfffb66eSDimitry Andric 
97bfffb66eSDimitry Andric 		/**
98bfffb66eSDimitry Andric 		 * Attempting to acquire the lock failed.
99bfffb66eSDimitry Andric 		 */
100bfffb66eSDimitry Andric 		InitLockFailed
101bfffb66eSDimitry Andric 	};
102bfffb66eSDimitry Andric 
103bfffb66eSDimitry Andric 	/**
104bfffb66eSDimitry Andric 	 * Class encapsulating a single atomic word being used to represent the
105bfffb66eSDimitry Andric 	 * guard.  The word size is defined by the type of `GuardWord`.  The bit
106bfffb66eSDimitry Andric 	 * used to indicate the locked state is `1<<LockedBit`, the bit used to
107bfffb66eSDimitry Andric 	 * indicate the initialised state is `1<<InitBit`.
108bfffb66eSDimitry Andric 	 */
109bfffb66eSDimitry Andric 	template<typename GuardWord, int LockedBit, int InitBit>
110bfffb66eSDimitry Andric 	struct SingleWordGuard
111bfffb66eSDimitry Andric 	{
112bfffb66eSDimitry Andric 		/**
113bfffb66eSDimitry Andric 		 * The value indicating that the lock bit is set (and no other bits).
114bfffb66eSDimitry Andric 		 */
115bfffb66eSDimitry Andric 		static constexpr GuardWord locked = static_cast<GuardWord>(1)
116bfffb66eSDimitry Andric 		                                    << LockedBit;
117bfffb66eSDimitry Andric 
118bfffb66eSDimitry Andric 		/**
119bfffb66eSDimitry Andric 		 * The value indicating that the initialised bit is set (and all other
120bfffb66eSDimitry Andric 		 * bits are zero).
121bfffb66eSDimitry Andric 		 */
122bfffb66eSDimitry Andric 		static constexpr GuardWord initialised = static_cast<GuardWord>(1)
123bfffb66eSDimitry Andric 		                                         << InitBit;
124bfffb66eSDimitry Andric 
125bfffb66eSDimitry Andric 		/**
126bfffb66eSDimitry Andric 		 * The guard variable.
127bfffb66eSDimitry Andric 		 */
128bfffb66eSDimitry Andric 		atomic<GuardWord> val;
129bfffb66eSDimitry Andric 
130bfffb66eSDimitry Andric 		public:
131bfffb66eSDimitry Andric 		/**
132bfffb66eSDimitry Andric 		 * Release the lock and set the initialised state.  In the single-word
133bfffb66eSDimitry Andric 		 * implementation here, these are both done by a single store.
134bfffb66eSDimitry Andric 		 */
unlock__anone6a749c70111::SingleWordGuard135bfffb66eSDimitry Andric 		void unlock(bool isInitialised)
136bfffb66eSDimitry Andric 		{
137bfffb66eSDimitry Andric 			val.store(isInitialised ? initialised : 0, memory_order::release);
138bfffb66eSDimitry Andric #ifndef NDEBUG
139bfffb66eSDimitry Andric 			GuardWord init_state = initialised;
140bfffb66eSDimitry Andric 			assert(*reinterpret_cast<uint8_t*>(&init_state) != 0);
141bfffb66eSDimitry Andric #endif
142bfffb66eSDimitry Andric 		}
143bfffb66eSDimitry Andric 
144bfffb66eSDimitry Andric 		/**
145bfffb66eSDimitry Andric 		 * Try to acquire the lock.  This has a tri-state return, indicating
146bfffb66eSDimitry Andric 		 * either that the lock was acquired, it wasn't acquired because it was
147bfffb66eSDimitry Andric 		 * contended, or it wasn't acquired because the guarded variable is
148bfffb66eSDimitry Andric 		 * already initialised.
149bfffb66eSDimitry Andric 		 */
try_lock__anone6a749c70111::SingleWordGuard150bfffb66eSDimitry Andric 		GuardState try_lock()
151bfffb66eSDimitry Andric 		{
152bfffb66eSDimitry Andric 			GuardWord old = 0;
153bfffb66eSDimitry Andric 			// Try to acquire the lock, assuming that we are in the state where
154bfffb66eSDimitry Andric 			// the lock is not held and the variable is not initialised (so the
155bfffb66eSDimitry Andric 			// expected value is 0).
156bfffb66eSDimitry Andric 			if (val.compare_exchange(old, locked))
157bfffb66eSDimitry Andric 			{
158bfffb66eSDimitry Andric 				return GuardState::InitLockSucceeded;
159bfffb66eSDimitry Andric 			}
160bfffb66eSDimitry Andric 			// If the CAS failed and the old value indicates that this is
161bfffb66eSDimitry Andric 			// initialised, return that initialisation is done and skip further
162bfffb66eSDimitry Andric 			// retries.
163bfffb66eSDimitry Andric 			if (old == initialised)
164bfffb66eSDimitry Andric 			{
165bfffb66eSDimitry Andric 				return GuardState::InitDone;
166bfffb66eSDimitry Andric 			}
167bfffb66eSDimitry Andric 			// Otherwise, report failure.
168bfffb66eSDimitry Andric 			return GuardState::InitLockFailed;
169bfffb66eSDimitry Andric 		}
170bfffb66eSDimitry Andric 
171bfffb66eSDimitry Andric 		/**
172bfffb66eSDimitry Andric 		 * Check whether the guard indicates that the variable is initialised.
173bfffb66eSDimitry Andric 		 */
is_initialised__anone6a749c70111::SingleWordGuard174bfffb66eSDimitry Andric 		bool is_initialised()
175bfffb66eSDimitry Andric 		{
176bfffb66eSDimitry Andric 			return (val.load(memory_order::acquire) & initialised) ==
177bfffb66eSDimitry Andric 			       initialised;
178bfffb66eSDimitry Andric 		}
179bfffb66eSDimitry Andric 	};
180bfffb66eSDimitry Andric 
181bfffb66eSDimitry Andric 	/**
182bfffb66eSDimitry Andric 	 * Class encapsulating using two 32-bit atomic values to represent a 64-bit
183bfffb66eSDimitry Andric 	 * guard variable.
184bfffb66eSDimitry Andric 	 */
185bfffb66eSDimitry Andric 	template<int LockedBit, int InitBit>
186bfffb66eSDimitry Andric 	class DoubleWordGuard
187bfffb66eSDimitry Andric 	{
188bfffb66eSDimitry Andric 		/**
189bfffb66eSDimitry Andric 		 * The value of `lock_word` when the lock is held.
190bfffb66eSDimitry Andric 		 */
191bfffb66eSDimitry Andric 		static constexpr uint32_t locked = static_cast<uint32_t>(1)
192bfffb66eSDimitry Andric 		                                   << LockedBit;
193bfffb66eSDimitry Andric 
194bfffb66eSDimitry Andric 		/**
195bfffb66eSDimitry Andric 		 * The value of `init_word` when the guarded variable is initialised.
196bfffb66eSDimitry Andric 		 */
197bfffb66eSDimitry Andric 		static constexpr uint32_t initialised = static_cast<uint32_t>(1)
198bfffb66eSDimitry Andric 		                                        << InitBit;
199bfffb66eSDimitry Andric 
200bfffb66eSDimitry Andric 		/**
201bfffb66eSDimitry Andric 		 * The word used for the initialised flag.  This is always the first
202bfffb66eSDimitry Andric 		 * word irrespective of endian because the generated code compares the
203bfffb66eSDimitry Andric 		 * first byte in memory against 0.
204bfffb66eSDimitry Andric 		 */
205bfffb66eSDimitry Andric 		atomic<uint32_t> init_word;
206bfffb66eSDimitry Andric 
207bfffb66eSDimitry Andric 		/**
208bfffb66eSDimitry Andric 		 * The word used for the lock.
209bfffb66eSDimitry Andric 		 */
210bfffb66eSDimitry Andric 		atomic<uint32_t> lock_word;
211bfffb66eSDimitry Andric 
212bfffb66eSDimitry Andric 		public:
213bfffb66eSDimitry Andric 		/**
214bfffb66eSDimitry Andric 		 * Try to acquire the lock.  This has a tri-state return, indicating
215bfffb66eSDimitry Andric 		 * either that the lock was acquired, it wasn't acquired because it was
216bfffb66eSDimitry Andric 		 * contended, or it wasn't acquired because the guarded variable is
217bfffb66eSDimitry Andric 		 * already initialised.
218bfffb66eSDimitry Andric 		 */
try_lock()219bfffb66eSDimitry Andric 		GuardState try_lock()
220bfffb66eSDimitry Andric 		{
221bfffb66eSDimitry Andric 			uint32_t old = 0;
222bfffb66eSDimitry Andric 			// Try to acquire the lock
223bfffb66eSDimitry Andric 			if (lock_word.compare_exchange(old, locked))
224bfffb66eSDimitry Andric 			{
225bfffb66eSDimitry Andric 				// If we succeeded, check if initialisation has happened.  In
226bfffb66eSDimitry Andric 				// this version, we don't have atomic manipulation of both the
227bfffb66eSDimitry Andric 				// lock and initialised bits together.  Instead, we have an
228bfffb66eSDimitry Andric 				// ordering rule that the initialised bit is only ever updated
229bfffb66eSDimitry Andric 				// with the lock held.
230bfffb66eSDimitry Andric 				if (is_initialised())
231bfffb66eSDimitry Andric 				{
232bfffb66eSDimitry Andric 					// If another thread did manage to initialise this, release
233bfffb66eSDimitry Andric 					// the lock and notify the caller that initialisation is
234bfffb66eSDimitry Andric 					// done.
235*7819a911SDimitry Andric 					lock_word.store(0, memory_order::release);
236bfffb66eSDimitry Andric 					return GuardState::InitDone;
237bfffb66eSDimitry Andric 				}
238bfffb66eSDimitry Andric 				return GuardState::InitLockSucceeded;
239bfffb66eSDimitry Andric 			}
240bfffb66eSDimitry Andric 			return GuardState::InitLockFailed;
241bfffb66eSDimitry Andric 		}
242bfffb66eSDimitry Andric 
243bfffb66eSDimitry Andric 		/**
244bfffb66eSDimitry Andric 		 * Set the initialised state and release the lock.  In this
245bfffb66eSDimitry Andric 		 * implementation, this is ordered, not atomic: the initialise bit is
246bfffb66eSDimitry Andric 		 * set while the lock is held.
247bfffb66eSDimitry Andric 		 */
unlock(bool isInitialised)248bfffb66eSDimitry Andric 		void unlock(bool isInitialised)
249bfffb66eSDimitry Andric 		{
250bfffb66eSDimitry Andric 			init_word.store(isInitialised ? initialised : 0,
251bfffb66eSDimitry Andric 			                  memory_order::release);
252bfffb66eSDimitry Andric 			lock_word.store(0, memory_order::release);
253bfffb66eSDimitry Andric 			assert((*reinterpret_cast<uint8_t*>(this) != 0) == isInitialised);
254bfffb66eSDimitry Andric 		}
255bfffb66eSDimitry Andric 
256bfffb66eSDimitry Andric 		/**
257bfffb66eSDimitry Andric 		 * Return whether the guarded variable is initialised.
258bfffb66eSDimitry Andric 		 */
is_initialised()259bfffb66eSDimitry Andric 		bool is_initialised()
260bfffb66eSDimitry Andric 		{
261bfffb66eSDimitry Andric 			return (init_word.load(memory_order::acquire) & initialised) ==
262bfffb66eSDimitry Andric 			       initialised;
263bfffb66eSDimitry Andric 		}
264bfffb66eSDimitry Andric 	};
265bfffb66eSDimitry Andric 
266bfffb66eSDimitry Andric 	// Check that the two implementations are the correct size.
267bfffb66eSDimitry Andric 	static_assert(sizeof(SingleWordGuard<uint32_t, 31, 0>) == sizeof(uint32_t),
268bfffb66eSDimitry Andric 	              "Single-word 32-bit guard must be 32 bits");
269bfffb66eSDimitry Andric 	static_assert(sizeof(SingleWordGuard<uint64_t, 63, 0>) == sizeof(uint64_t),
270bfffb66eSDimitry Andric 	              "Single-word 64-bit guard must be 64 bits");
271bfffb66eSDimitry Andric 	static_assert(sizeof(DoubleWordGuard<31, 0>) == sizeof(uint64_t),
272bfffb66eSDimitry Andric 	              "Double-word guard must be 64 bits");
273bfffb66eSDimitry Andric 
2747a984708SDavid Chisnall #ifdef __arm__
275bfffb66eSDimitry Andric 	/**
276bfffb66eSDimitry Andric 	 * The Arm PCS defines a variant of the Itanium ABI with 32-bit lock words.
277bfffb66eSDimitry Andric 	 */
278bfffb66eSDimitry Andric 	using Guard = SingleWordGuard<uint32_t, 31, 0>;
279f2dc4184SDimitry Andric #elif defined(_LP64)
2804bab9fd9SDavid Chisnall #	if defined(__LITTLE_ENDIAN__)
281bfffb66eSDimitry Andric 	/**
282bfffb66eSDimitry Andric 	 * On little-endian 64-bit platforms the guard word is a single 64-bit
283bfffb66eSDimitry Andric 	 * atomic with the lock in the high bit and the initialised flag in the low
284bfffb66eSDimitry Andric 	 * bit.
285bfffb66eSDimitry Andric 	 */
286bfffb66eSDimitry Andric 	using Guard = SingleWordGuard<uint64_t, 63, 0>;
2874bab9fd9SDavid Chisnall #	else
288bfffb66eSDimitry Andric 	/**
289bfffb66eSDimitry Andric 	 * On bit-endian 64-bit platforms, the guard word is a single 64-bit atomic
290bfffb66eSDimitry Andric 	 * with the lock in the low bit and the initialised bit in the highest
291bfffb66eSDimitry Andric 	 * byte.
292bfffb66eSDimitry Andric 	 */
293bfffb66eSDimitry Andric 	using Guard = SingleWordGuard<uint64_t, 0, 56>;
2944bab9fd9SDavid Chisnall #	endif
295f2dc4184SDimitry Andric #else
296f2dc4184SDimitry Andric #	if defined(__LITTLE_ENDIAN__)
297bfffb66eSDimitry Andric 	/**
298bfffb66eSDimitry Andric 	 * 32-bit platforms use the same layout as 64-bit.
299bfffb66eSDimitry Andric 	 */
300bfffb66eSDimitry Andric 	using Guard = DoubleWordGuard<31, 0>;
301f2dc4184SDimitry Andric #	else
302bfffb66eSDimitry Andric 	/**
303bfffb66eSDimitry Andric 	 * 32-bit platforms use the same layout as 64-bit.
304bfffb66eSDimitry Andric 	 */
305bfffb66eSDimitry Andric 	using Guard = DoubleWordGuard<0, 24>;
3064bab9fd9SDavid Chisnall #	endif
307f2dc4184SDimitry Andric #endif
308bfffb66eSDimitry Andric 
309bfffb66eSDimitry Andric } // namespace
3107a984708SDavid Chisnall 
3117a984708SDavid Chisnall /**
3127a984708SDavid Chisnall  * Acquires a lock on a guard, returning 0 if the object has already been
3137a984708SDavid Chisnall  * initialised, and 1 if it has not.  If the object is already constructed then
3147a984708SDavid Chisnall  * this function just needs to read a byte from memory and return.
3157a984708SDavid Chisnall  */
__cxa_guard_acquire(Guard * guard_object)316bfffb66eSDimitry Andric extern "C" int __cxa_guard_acquire(Guard *guard_object)
3177a984708SDavid Chisnall {
318bfffb66eSDimitry Andric 	// Check if this is already initialised.  If so, we don't have to do
319bfffb66eSDimitry Andric 	// anything.
320bfffb66eSDimitry Andric 	if (guard_object->is_initialised())
32156aaed38SDimitry Andric 	{
32225482379SDimitry Andric 		return 0;
32356aaed38SDimitry Andric 	}
324bfffb66eSDimitry Andric 	// Spin trying to acquire the lock.  If we fail to acquire the lock the
325bfffb66eSDimitry Andric 	// first time then another thread will *probably* initialise it, but if the
326bfffb66eSDimitry Andric 	// constructor throws an exception then we may have to try again in this
327bfffb66eSDimitry Andric 	// thread.
328bfffb66eSDimitry Andric 	for (;;)
329bfffb66eSDimitry Andric 	{
330bfffb66eSDimitry Andric 		// Try to acquire the lock.
331bfffb66eSDimitry Andric 		switch (guard_object->try_lock())
332bfffb66eSDimitry Andric 		{
333bfffb66eSDimitry Andric 			// If we failed to acquire the lock but another thread has
334bfffb66eSDimitry Andric 			// initialised the lock while we were waiting, return immediately
335bfffb66eSDimitry Andric 			// indicating that initialisation is not required.
336bfffb66eSDimitry Andric 			case GuardState::InitDone:
33725482379SDimitry Andric 				return 0;
338bfffb66eSDimitry Andric 			// If we acquired the lock, return immediately to start
339bfffb66eSDimitry Andric 			// initialisation.
340bfffb66eSDimitry Andric 			case GuardState::InitLockSucceeded:
341bfffb66eSDimitry Andric 				return 1;
342bfffb66eSDimitry Andric 			// If we didn't acquire the lock, pause and retry.
343bfffb66eSDimitry Andric 			case GuardState::InitLockFailed:
344bfffb66eSDimitry Andric 				break;
345bfffb66eSDimitry Andric 		}
3467a984708SDavid Chisnall 		sched_yield();
3477a984708SDavid Chisnall 	}
3484bab9fd9SDavid Chisnall }
3497a984708SDavid Chisnall 
3507a984708SDavid Chisnall /**
3517a984708SDavid Chisnall  * Releases the lock without marking the object as initialised.  This function
3527a984708SDavid Chisnall  * is called if initialising a static causes an exception to be thrown.
3537a984708SDavid Chisnall  */
__cxa_guard_abort(Guard * guard_object)354bfffb66eSDimitry Andric extern "C" void __cxa_guard_abort(Guard *guard_object)
3557a984708SDavid Chisnall {
356bfffb66eSDimitry Andric 	guard_object->unlock(false);
3577a984708SDavid Chisnall }
358bfffb66eSDimitry Andric 
3597a984708SDavid Chisnall /**
3607a984708SDavid Chisnall  * Releases the guard and marks the object as initialised.  This function is
3617a984708SDavid Chisnall  * called after successful initialisation of a static.
3627a984708SDavid Chisnall  */
__cxa_guard_release(Guard * guard_object)363bfffb66eSDimitry Andric extern "C" void __cxa_guard_release(Guard *guard_object)
3647a984708SDavid Chisnall {
365bfffb66eSDimitry Andric 	guard_object->unlock(true);
3667a984708SDavid Chisnall }
367