summaryrefslogtreecommitdiff
path: root/zen/globals.h
blob: 5f3dd64aa7bf023dd6bf50a25d722cd9f79e05a5 (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
// *****************************************************************************
// * 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 scoped ownership and serialized access to global variables
template <class T>
class Global
{
public:
	Global() {}
	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 (spinLock.exchange(true)) ;
        ZEN_ON_SCOPE_EXIT(spinLock = false);
        if (inst)
            return *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 (spinLock.exchange(true)) ;
            ZEN_ON_SCOPE_EXIT(spinLock = false);
            std::swap(inst, tmpInst);
        }
        delete tmpInst;
    }

private:
    //avoid static destruction order fiasco: there may be accesses to "Global<T>::get()" during process shutdown
    //e.g. show message in debug_minidump.cpp or some detached thread assembling an error message!
    //=> use trivially-destructible POD only!!!
    std::shared_ptr<T>* inst = nullptr;
    //serialize access: can't use std::mutex because of non-trival destructor
    std::atomic<bool> spinLock { false };
};
}

#endif //GLOBALS_H_8013740213748021573485
bgstack15