github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/common/ipc/shm_queue.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_queue.h"
    21  
    22  namespace neb {
    23  namespace ipc {
    24  namespace internal {
    25  
    26  shm_queue::shm_queue(const std::string &name, shm_session_base *session,
    27                       boost::interprocess::managed_shared_memory *shmem,
    28                       size_t capacity)
    29      : m_name(name), m_shmem(shmem), m_capacity(capacity), m_session(session) {
    30    try {
    31      if (!m_shmem) {
    32        throw shm_queue_failure("shmem can't be nullptr");
    33      }
    34      if (!m_capacity) {
    35        throw shm_queue_failure("capacity can't be 0");
    36      }
    37      m_allocator = new shmem_allocator_t(m_shmem->get_segment_manager());
    38  
    39      m_mutex = m_session->bookkeeper()->acquire_named_mutex(mutex_name());
    40      m_empty_cond =
    41          m_session->bookkeeper()->acquire_named_condition(empty_cond_name());
    42      m_full_cond =
    43          m_session->bookkeeper()->acquire_named_condition(full_cond_name());
    44  
    45      m_buffer =
    46          m_shmem->find_or_construct<shm_vector_t>(m_name.c_str())(*m_allocator);
    47      if (!m_mutex) {
    48        throw shm_queue_failure("alloc mutex fail");
    49      }
    50      if (!m_empty_cond) {
    51        throw shm_queue_failure("alloc empty cond fail");
    52      }
    53      if (!m_full_cond) {
    54        throw shm_queue_failure("alloc full cond fail");
    55      }
    56      if (!m_buffer) {
    57        throw shm_queue_failure("alloc vector fail");
    58      }
    59    } catch (const std::exception &e) {
    60      throw shm_init_failure(std::string("shm_queue, ") +
    61                             std::string(typeid(e).name()) + " : " + e.what());
    62    }
    63  };
    64  
    65  void shm_queue::reset() {
    66    m_session->bookkeeper()->reset();
    67    // boost::interprocess::named_mutex::remove(mutex_name().c_str());
    68    // boost::interprocess::named_condition::remove(empty_cond_name().c_str());
    69    // boost::interprocess::named_condition::remove(full_cond_name().c_str());
    70    // m_session->reset();
    71  }
    72  void shm_queue::push_back(shm_type_id_t type_id, void *ptr) {
    73    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> _l(
    74        *m_mutex);
    75    if (m_buffer->size() == m_capacity) {
    76      m_full_cond->wait(_l);
    77    }
    78    if (m_buffer->size() >= m_capacity)
    79      return;
    80    boost::interprocess::managed_shared_memory::handle_t h =
    81        m_shmem->get_handle_from_address(ptr);
    82    vector_elem_t e;
    83    e.m_handle = h;
    84    e.m_type = type_id;
    85    e.m_op_type = new_object;
    86    try {
    87      m_buffer->push_back(e);
    88    } catch (const std::exception &e) {
    89      LOG(ERROR) << "got exception " << e.what();
    90    }
    91    if (m_buffer->size() == 1) {
    92      m_empty_cond->notify_all();
    93    }
    94  }
    95  
    96  std::tuple<void *, shm_type_id_t, shm_queue::element_op_tag>
    97  shm_queue::pop_front() {
    98    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> _l(
    99        *m_mutex);
   100    if (m_buffer->empty()) {
   101      m_empty_cond->wait(_l);
   102    }
   103    if (m_buffer->empty()) {
   104      return std::make_tuple<void *, shm_type_id_t, element_op_tag>(nullptr, 0,
   105                                                                    new_object);
   106    }
   107    vector_elem_t e;
   108    e = m_buffer->front();
   109    m_buffer->erase(m_buffer->begin());
   110    if (m_buffer->size() == m_capacity - 1) {
   111      m_full_cond->notify_all();
   112    }
   113    return std::make_tuple(m_shmem->get_address_from_handle(e.m_handle), e.m_type,
   114                           e.m_op_type);
   115  }
   116  
   117  std::tuple<void *, shm_type_id_t, shm_queue::element_op_tag>
   118  shm_queue::try_pop_front() {
   119    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> _l(
   120        *m_mutex);
   121    if (m_buffer->empty()) {
   122      return std::make_tuple<void *, shm_type_id_t, element_op_tag>(nullptr, 0,
   123                                                                    new_object);
   124    }
   125    vector_elem_t e;
   126    e = m_buffer->front();
   127    m_buffer->erase(m_buffer->begin());
   128    if (m_buffer->size() == m_capacity - 1) {
   129      m_full_cond->notify_all();
   130    }
   131    return std::make_tuple(m_shmem->get_address_from_handle(e.m_handle), e.m_type,
   132                           e.m_op_type);
   133  }
   134  
   135  size_t shm_queue::size() const {
   136    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> _l(
   137        *m_mutex);
   138    return m_buffer->size();
   139  }
   140  
   141  void shm_queue::wake_up_if_empty() {
   142    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> _l(
   143        *m_mutex);
   144  
   145    if (m_buffer->empty()) {
   146      m_empty_cond->notify_all();
   147    }
   148  }
   149  size_t shm_queue::empty() const {
   150    boost::interprocess::scoped_lock<boost::interprocess::named_mutex> _l(
   151        *m_mutex);
   152    return m_buffer->empty();
   153  }
   154  
   155  shm_queue::~shm_queue() {
   156    LOG(INFO) << "m_shmem: " << (void *)m_shmem;
   157    if (m_shmem && m_buffer) {
   158      m_shmem->destroy_ptr(m_buffer);
   159    }
   160    if (m_allocator) {
   161      delete m_allocator;
   162    }
   163    m_session->bookkeeper()->release_named_mutex(mutex_name());
   164    m_session->bookkeeper()->release_named_condition(empty_cond_name());
   165    m_session->bookkeeper()->release_named_condition(full_cond_name());
   166  }
   167  }
   168  }
   169  }