genode/base-hw/src/base/singleton.h
Norman Feske 71cd7b9d2e base-hw: Avoid early calls of cmpxchg
This patch eliminates calls of 'cmpxchg' prior enabling the MMU. This is
needed because the 'ldrex' and 'strex' instructions do not always work
with MMU and L1 cache disabled, i.e., on Raspberry Pi.
2013-05-15 20:47:46 +02:00

54 lines
1.8 KiB
C++

/*
* \brief Helper for creating singleton objects
* \author Norman Feske
* \date 2013-05-14
*
* Before enabling the MMU on ARM, the 'cmpxchg' implementation is not always
* guaranteed to work. For example, on the Raspberry Pi, the 'ldrex' as used by
* 'cmpxchg' causes the machine to reboot. After enabling the MMU, everything
* is fine. Hence, we need to avoid executing 'cmpxchg' prior this point.
* Unfortunately, 'cmpxchg' is implicitly called each time when creating a
* singleton object via a local-static object pattern. In this case, the
* compiler generates code that calls the '__cxa_guard_acquire' function of the
* C++ runtime, which, in turn, relies 'cmpxchg' for synchronization.
*
* The utility provided herein is an alternative way to create single object
* instances without implicitly calling 'cmpxchg'. Because object creation is
* not synchronized via a spin lock, it must not be used in scenarios where
* multiple threads may contend.
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SINGLETON_H_
#define _SINGLETON_H_
inline void *operator new(Genode::size_t, void *at) { return at; }
template <typename T, int ALIGN = 2, typename... Args>
static inline T *unsynchronized_singleton(Args... args)
{
/*
* Each instantiation of the function template with a different type 'T'
* yields a dedicated instance of the local static variables, thereby
* creating the living space for the singleton objects.
*/
static bool initialized;
static int inst[sizeof(T)/sizeof(int) + 1] __attribute__((aligned(ALIGN)));
/* execute constructor on first call */
if (!initialized) {
initialized = true;
new (&inst) T(args...);
}
return reinterpret_cast<T *>(inst);
}
#endif /* _SINGLETON_H_ */