blob: b6c5dd287b050a88d9ed84343eee02f38c244e33 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
// *****************************************************************************
// * 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 <atomic>
#include <memory>
#include "scope_guard.h"
namespace zen
{
//solve static destruction order fiasco by providing shared ownership and serialized access to global variables
template <class T>
class Global
{
public:
Global()
{
static_assert(std::is_trivially_destructible<Pod>::value, "this memory needs to live forever");
assert(!pod.inst && !pod.spinLock); //we depend on static zero-initialization!
}
explicit Global(std::unique_ptr<T>&& newInst) { set(std::move(newInst)); }
~Global() { set(nullptr); }
std::shared_ptr<T> 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<T>&& newInst)
{
std::shared_ptr<T>* tmpInst = nullptr;
if (newInst)
tmpInst = new std::shared_ptr<T>(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<T>::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<T>* inst; // = nullptr;
std::atomic<bool> spinLock; // { false }; rely entirely on static zero-initialization! => avoid potential contention with worker thread during Global<> construction!
//serialize access; can't use std::mutex: has non-trival destructor
} pod;
};
}
#endif //GLOBALS_H_8013740213748021573485
|