/* * ===================================================================================== * * 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 #include #include #include #include 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_; 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 Guard; // typedef robust::Guard 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 T *FindOrCreate(const std::string &name, Params &&...params) { return find_or_construct(name.c_str(), std::nothrow)(std::forward(params)...); } template T *Create(const std::string &name, Params &&...params) { return construct(name.c_str(), std::nothrow)(std::forward(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 void Dealloc(offset_ptr ptr) { return Dealloc(ptr.get()); } template T *New(Params &&...params) { Guard lock(*pmutex_); return construct(anonymous_instance, std::nothrow)(std::forward(params)...); } template void Delete(T *p) { Guard lock(*pmutex_); if (p) { destroy_ptr(p); }; } template void Delete(offset_ptr p) { Delete(p.get()); } template T *Find(const std::string &name) { return find(name.c_str()).first; } }; template using Allocator = allocator; template using Deleter = deleter; template using SharedPtr = shared_ptr, Deleter>; // ShmObject manages an object in shared memory, but ShmObject itself is not in shared memory. template 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 ShmObject(ShmType &segment, const std::string &name, Params &&...t) : shm_(segment), name_(name) { pdata_ = shm_.FindOrCreate(ObjName(name_), std::forward(t)...); if (!IsOk()) { throw("Error: Not enough memory, can not allocate \"" + name_ + "\""); } } template 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(ObjName(name_), std::forward(t)...); } else { pdata_ = shm_.Find(ObjName(name_)); } } ShmObject(const int64_t offset, ShmType &segment, const std::string &name) : shm_(segment), name_(name) { pdata_ = reinterpret_cast(Addr(shm_.get_address()) + offset); } bool IsOk() const { return pdata_; } static bool Remove(SharedMemory &shm, const std::string &name) { return shm.destroy(ObjName(name).c_str()); } static Data *Find(SharedMemory &shm, const std::string &name) { return shm.Find(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(p); } ShmType &shm_; std::string name_; Data *pdata_ = nullptr; }; } // namespace bhome_shm #endif // end of include guard: SHM_6CHO6D6C