// ***************************************************************************** // * This file is part of the FreeFileSync project. It is distributed under * // * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 * // * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved * // ***************************************************************************** #ifndef GLOBALS_H_8013740213748021573485 #define GLOBALS_H_8013740213748021573485 #include #include #include "scope_guard.h" namespace zen { //solve static destruction order fiasco by providing shared ownership and serialized access to global variables template class Global { public: Global() { static_assert(std::is_trivially_destructible::value, "this memory needs to live forever"); } explicit Global(std::unique_ptr&& newInst) { set(std::move(newInst)); } ~Global() { set(nullptr); } std::shared_ptr get() //=> return std::shared_ptr to let instance life time be handled by caller (MT usage!) { while (pod.spinLock.exchange(true)) ; ZEN_ON_SCOPE_EXIT(pod.spinLock = false); if (pod.inst) return *pod.inst; return nullptr; } void set(std::unique_ptr&& newInst) { std::shared_ptr* tmpInst = nullptr; if (newInst) tmpInst = new std::shared_ptr(std::move(newInst)); { while (pod.spinLock.exchange(true)) ; ZEN_ON_SCOPE_EXIT(pod.spinLock = false); std::swap(pod.inst, tmpInst); } delete tmpInst; } private: //avoid static destruction order fiasco: there may be accesses to "Global::get()" during process shutdown //e.g. _("") used by message in debug_minidump.cpp or by some detached thread assembling an error message! //=> use trivially-destructible POD only!!! struct Pod { std::shared_ptr* inst = nullptr; //serialize access; can't use std::mutex: has non-trival destructor std::atomic spinLock { false }; } pod; }; #if defined _MSC_VER && _MSC_VER < 1900 #error function scope static initialization is not yet thread-safe! #endif } #endif //GLOBALS_H_8013740213748021573485