github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/common/ipc/shm_bookkeeper.cpp (about)

     1  // Copyright (C) 2018 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or
     6  // modify
     7  // it under the terms of the GNU General Public License as published by
     8  // the Free Software Foundation, either version 3 of the License, or
     9  // (at your option) any later version.
    10  //
    11  // the go-nebulas library is distributed in the hope that it will be useful,
    12  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    13  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14  // GNU General Public License for more details.
    15  //
    16  // You should have received a copy of the GNU General Public License
    17  // along with the go-nebulas library.  If not, see
    18  // <http://www.gnu.org/licenses/>.
    19  //
    20  #include "common/ipc/shm_bookkeeper.h"
    21  #include "common/common.h"
    22  #include "common/ipc/shm_base.h"
    23  
    24  namespace neb {
    25  namespace ipc {
    26  void clean_bookkeeper_env(const std::string &name) {
    27    boost::interprocess::shared_memory_object::remove(name.c_str());
    28    boost::interprocess::named_mutex::remove((name + ".mutex").c_str());
    29  }
    30  
    31  namespace internal {
    32  
    33  size_t bookkeeper_mem_size = 64 * 1024;
    34  
    35  shm_bookkeeper::shm_bookkeeper(const std::string &name) : m_name(name) {
    36    try {
    37      m_segment = std::unique_ptr<boost::interprocess::managed_shared_memory>(
    38          new boost::interprocess::managed_shared_memory(
    39              boost::interprocess::open_or_create, m_name.c_str(),
    40              bookkeeper_mem_size));
    41  
    42      m_allocator = std::unique_ptr<map_allocator_t>(
    43          new map_allocator_t(m_segment->get_segment_manager()));
    44  
    45      m_mutex = std::unique_ptr<boost::interprocess::named_mutex>(
    46          new boost::interprocess::named_mutex(
    47              boost::interprocess::open_or_create, mutex_name().c_str()));
    48  
    49      m_map = m_segment->find_or_construct<map_t>(mem_name().c_str())(
    50          std::less<char_string_t>(), *m_allocator);
    51    } catch (const std::exception &e) {
    52      m_mutex.reset();
    53      m_segment.reset();
    54      throw shm_init_failure(std::string("shm_bookkeeper, ") +
    55                             std::string(typeid(e).name()) + " : " + e.what());
    56    }
    57  }
    58  void shm_bookkeeper::reset() {
    59    if (!m_mutex)
    60      return;
    61    //! We may fail to acquire m_mutex, thus, we just don't.
    62    m_mutex->try_lock();
    63  
    64    for (auto it = m_map->begin(); it != m_map->end(); ++it) {
    65      auto first = it->first;
    66      auto second = it->second;
    67      tag_counter_t tt;
    68      tt.set_data(second);
    69      if (tt.type() == tag_counter_t::boost_mutex) {
    70        boost::interprocess::named_mutex::remove(first.c_str());
    71      } else if (tt.type() == tag_counter_t::boost_semaphore) {
    72        boost::interprocess::named_semaphore::remove(first.c_str());
    73      } else if (tt.type() == tag_counter_t::boost_condition) {
    74        boost::interprocess::named_condition::remove(first.c_str());
    75      }
    76    }
    77  
    78    m_mutex->unlock();
    79  
    80    boost::interprocess::named_mutex::remove(mutex_name().c_str());
    81    boost::interprocess::shared_memory_object::remove(m_name.c_str());
    82  
    83    // LOG(INFO) << "realloc local vars";
    84    // m_segment = std::unique_ptr<boost::interprocess::managed_shared_memory>(
    85    // new boost::interprocess::managed_shared_memory(
    86    // boost::interprocess::open_or_create, m_name.c_str(),
    87    // bookkeeper_mem_size));
    88  
    89    // m_allocator = std::unique_ptr<map_allocator_t>(
    90    // new map_allocator_t(m_segment->get_segment_manager()));
    91  
    92    // m_mutex = std::unique_ptr<boost::interprocess::named_mutex>(
    93    // new boost::interprocess::named_mutex(boost::interprocess::open_or_create,
    94    // mutex_name().c_str()));
    95  
    96    // m_map = m_segment->find_or_construct<map_t>(mem_name().c_str())(
    97    // std::less<char_string_t>(), *m_allocator);
    98  }
    99  
   100  void shm_bookkeeper::acquire(const std::string &name,
   101                               const std::function<void()> &action) {
   102    acquire(name, action, tag_counter_t::other_unknown);
   103  }
   104  
   105  void shm_bookkeeper::acquire(const std::string &name,
   106                               const std::function<void()> &action,
   107                               uint8_t type) {
   108    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> _l(
   109        *m_mutex);
   110    action();
   111    char_string_t cs(name.c_str(), *m_allocator);
   112    if (m_map->find(cs) == m_map->end()) {
   113      tag_counter_t tt;
   114      tt.set_type(static_cast<tag_counter_t::type_tag>(type));
   115      tt.set_counter(1);
   116      m_map->insert(std::pair<const char_string_t, uint64_t>(cs, tt.data()));
   117    } else {
   118      tag_counter_t tt;
   119      tt.set_data(m_map->operator[](cs));
   120      tt.set_counter(tt.counter() + 1);
   121      m_map->operator[](cs) = tt.data();
   122    }
   123  }
   124  
   125  void shm_bookkeeper::release(const std::string &name,
   126                               const std::function<void()> &action) {
   127    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> _l(
   128        *m_mutex);
   129  
   130    char_string_t cs(name.c_str(), *m_allocator);
   131    if (m_map->find(cs) == m_map->end()) {
   132      return;
   133    }
   134    tag_counter_t tt;
   135    tt.set_data(m_map->operator[](cs));
   136    tt.set_counter(tt.counter() - 1);
   137    m_map->operator[](cs) = tt.data();
   138    if (tt.counter() == 0) {
   139      m_map->erase(cs);
   140      action();
   141    }
   142  }
   143  std::unique_ptr<boost::interprocess::named_mutex>
   144  shm_bookkeeper::acquire_named_mutex(const std::string &name) {
   145    std::unique_ptr<boost::interprocess::named_mutex> ret;
   146    acquire(name,
   147            [&ret, name]() {
   148              ret = std::unique_ptr<boost::interprocess::named_mutex>(
   149                  new boost::interprocess::named_mutex(
   150                      boost::interprocess::open_or_create, name.c_str()));
   151            },
   152            tag_counter_t::boost_mutex);
   153    return ret;
   154  }
   155  
   156  void shm_bookkeeper::release_named_mutex(const std::string &name) {
   157    release(name,
   158            [name]() { boost::interprocess::named_mutex::remove(name.c_str()); });
   159  }
   160  
   161  std::unique_ptr<boost::interprocess::named_semaphore>
   162  shm_bookkeeper::acquire_named_semaphore(const std::string &name) {
   163    std::unique_ptr<boost::interprocess::named_semaphore> ret;
   164    acquire(name,
   165            [&ret, name]() {
   166              ret = std::unique_ptr<boost::interprocess::named_semaphore>(
   167                  new boost::interprocess::named_semaphore(
   168                      boost::interprocess::open_or_create, name.c_str(), 0));
   169            },
   170            tag_counter_t::boost_semaphore);
   171    return ret;
   172  }
   173  
   174  void shm_bookkeeper::release_named_semaphore(const std::string &name) {
   175    release(name, [name]() {
   176      boost::interprocess::named_semaphore::remove(name.c_str());
   177    });
   178  }
   179  
   180  std::unique_ptr<boost::interprocess::named_condition>
   181  shm_bookkeeper::acquire_named_condition(const std::string &name) {
   182    std::unique_ptr<boost::interprocess::named_condition> ret;
   183    acquire(name,
   184            [&ret, name]() {
   185              ret = std::unique_ptr<boost::interprocess::named_condition>(
   186                  new boost::interprocess::named_condition(
   187                      boost::interprocess::open_or_create, name.c_str()));
   188            },
   189            tag_counter_t::boost_condition);
   190    return ret;
   191  }
   192  void shm_bookkeeper::release_named_condition(const std::string &name) {
   193    release(name, [name]() {
   194      boost::interprocess::named_condition::remove(name.c_str());
   195    });
   196  }
   197  }
   198  }
   199  } // namespace neb