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 }