lichao
2021-05-19 ef289dc295e5597bbe39bcfdee06971726be7d7c
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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
/*
 * =====================================================================================
 *
 *       Filename:  shm.h
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2021年03月22日 16时19分21秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Li Chao (), 
 *   Organization:  
 *
 * =====================================================================================
 */
 
#ifndef SHM_6CHO6D6C
#define SHM_6CHO6D6C
 
#include "log.h"
#include <atomic>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/noncopyable.hpp>
#include <thread>
 
namespace bhome_shm
{
 
using namespace boost::interprocess;
 
typedef managed_shared_memory mshm_t;
 
class MutexWithPidCheck
{
    typedef boost::interprocess::interprocess_mutex MutexT;
    static pid_t pid()
    {
        static pid_t val = getpid();
        return val;
    }
    static bool Killed(pid_t pid)
    {
        char buf[64] = {0};
        snprintf(buf, sizeof(buf) - 1, "/proc/%d/stat", pid);
        return access(buf, F_OK) != 0;
    }
    bool PidCas(pid_t exp, pid_t val) { return pid_.compare_exchange_strong(exp, val); }
    MutexT mutex_;
    std::atomic<pid_t> pid_;
 
public:
    typedef MutexT::internal_mutex_type internal_mutex_type;
    const internal_mutex_type &internal_mutex() const { return mutex_.internal_mutex(); }
    internal_mutex_type &internal_mutex() { return mutex_.internal_mutex(); }
    MutexWithPidCheck() :
        pid_(0) {}
    bool try_lock()
    {
        bool r = false;
        if (mutex_.try_lock()) {
            auto old = pid_.load();
            r = PidCas(old, pid());
        } else {
            auto old = pid_.load();
            if (Killed(old)) {
                r = PidCas(old, pid());
                if (r) {
                    LOG_DEBUG() << "PidCheck captured pid " << old << " -> " << pid();
                }
            }
        }
        return r;
    }
 
    void lock()
    {
        while (!try_lock()) {
            std::this_thread::yield();
        }
    }
    void unlock()
    {
        auto old = pid_.load();
        if (old == pid()) {
            mutex_.unlock();
        }
    }
};
 
typedef interprocess_mutex Mutex;
typedef scoped_lock<Mutex> Guard;
// typedef robust::Guard<Mutex> Guard;
 
class SharedMemory : public mshm_t
{
    std::string name_;
    Mutex *pmutex_ = 0;
 
    static permissions AllowAll()
    {
        permissions perm;
        perm.set_unrestricted();
        return perm;
    }
    void Swap(SharedMemory &a);
 
public:
    static bool Remove(const std::string &name) { return shared_memory_object::remove(name.c_str()); }
 
    SharedMemory(const std::string &name, const uint64_t size);
    ~SharedMemory();
    std::string name() const { return name_; }
    bool Remove() { return Remove(name()); }
    template <class T, class... Params>
    T *FindOrCreate(const std::string &name, Params &&...params)
    {
        return find_or_construct<T>(name.c_str(), std::nothrow)(std::forward<decltype(params)>(params)...);
    }
    template <class T, class... Params>
    T *Create(const std::string &name, Params &&...params)
    {
        return construct<T>(name.c_str(), std::nothrow)(std::forward<decltype(params)>(params)...);
    }
    void *Alloc(const size_t size)
    {
        Guard lock(*pmutex_);
        return allocate(size, std::nothrow);
    }
    void Dealloc(void *p)
    {
        Guard lock(*pmutex_);
        if (p) { deallocate(p); }
    }
    template <class T>
    void Dealloc(offset_ptr<T> ptr) { return Dealloc(ptr.get()); }
 
    template <class T, class... Params>
    T *New(Params &&...params)
    {
        Guard lock(*pmutex_);
        return construct<T>(anonymous_instance, std::nothrow)(std::forward<decltype(params)>(params)...);
    }
    template <class T>
    void Delete(T *p)
    {
        Guard lock(*pmutex_);
        if (p) { destroy_ptr<T>(p); };
    }
    template <class T>
    void Delete(offset_ptr<T> p) { Delete(p.get()); }
    template <class T>
    T *Find(const std::string &name) { return find<T>(name.c_str()).first; }
};
 
template <class D>
using Allocator = allocator<D, SharedMemory::segment_manager>;
template <class D>
using Deleter = deleter<D, SharedMemory::segment_manager>;
template <class D>
using SharedPtr = shared_ptr<D, Allocator<void>, Deleter<D>>;
 
// ShmObject manages an object in shared memory, but ShmObject itself is not in shared memory.
template <class T>
class ShmObject : private boost::noncopyable
{
    static std::string ObjName(const std::string &name) { return "obj" + name; }
 
public:
    typedef T Data;
    typedef SharedMemory ShmType;
    ShmType &shm() const { return shm_; }
 
    template <class... Params>
    ShmObject(ShmType &segment, const std::string &name, Params &&...t) :
        shm_(segment), name_(name)
    {
        pdata_ = shm_.FindOrCreate<Data>(ObjName(name_), std::forward<decltype(t)>(t)...);
        if (!IsOk()) {
            throw("Error: Not enough memory, can not allocate \"" + name_ + "\"");
        }
    }
    template <class... Params>
    ShmObject(ShmType &segment, const bool create_or_else_find, const std::string &name, Params &&...t) :
        shm_(segment), name_(name)
    {
        if (create_or_else_find) {
            pdata_ = shm_.Create<Data>(ObjName(name_), std::forward<decltype(t)>(t)...);
        } else {
            pdata_ = shm_.Find<Data>(ObjName(name_));
        }
    }
    ShmObject(const int64_t offset, ShmType &segment, const std::string &name) :
        shm_(segment), name_(name)
    {
        pdata_ = reinterpret_cast<Data *>(Addr(shm_.get_address()) + offset);
    }
 
    bool IsOk() const { return pdata_; }
 
    static bool Remove(SharedMemory &shm, const std::string &name) { return shm.destroy<Data>(ObjName(name).c_str()); }
    static Data *Find(SharedMemory &shm, const std::string &name) { return shm.Find<Data>(ObjName(name)); }
    Data *Find(const std::string &name) { return Find(shm_, ObjName(name)); }
    virtual ~ShmObject() {}
    std::string name() const { return name_; }
    Data *data() { return pdata_; }
    const Data *data() const { return pdata_; }
    int64_t offset() const { return Addr(pdata_) - Addr(shm_.get_address()); }
    Data *operator->() { return data(); }
    const Data *operator->() const { return data(); }
    bool Remove() { return Remove(shm_, name_); }
 
private:
    static int64_t Addr(const void *p) { return reinterpret_cast<int64_t>(p); }
    ShmType &shm_;
    std::string name_;
    Data *pdata_ = nullptr;
};
 
} // namespace bhome_shm
 
#endif // end of include guard: SHM_6CHO6D6C