github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/common/ipc/shm_service_construct_helper.h (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 #pragma once 21 #include "common/common.h" 22 #include "common/ipc/shm_base.h" 23 #include "common/ipc/shm_service_op_queue.h" 24 #include <atomic> 25 #include <condition_variable> 26 #include <mutex> 27 #include <thread> 28 29 namespace neb { 30 namespace ipc { 31 32 namespace internal { 33 34 class shm_service_construct_helper { 35 public: 36 shm_service_construct_helper( 37 boost::interprocess::managed_shared_memory *shmem, 38 shm_service_op_queue *op_queue); 39 40 template <typename T, typename... ARGS> 41 T *construct(ARGS... args){ 42 if (!m_shmem) { 43 LOG(ERROR) << "no shared memory"; 44 throw shm_service_failure("no shared memory"); 45 } 46 auto thrd_id = std::this_thread::get_id(); 47 if (thrd_id == m_local_thread_id) { 48 return m_shmem->construct<T>(boost::interprocess::anonymous_instance)( 49 args...); 50 } 51 52 uint64_t counter = m_next_alloc_op_counter.fetch_add(1); 53 std::shared_ptr<shm_service_op_allocate> p = 54 std::make_shared<shm_service_op_allocate>(counter, [this, args...]() { 55 return m_shmem->construct<T>(boost::interprocess::anonymous_instance)( 56 args...); 57 }); 58 m_op_queue->push_back(p); 59 while (true) { 60 std::unique_lock<std::mutex> _l(m_mutex); 61 for (auto it = m_finished_alloc_ops.begin(); 62 it != m_finished_alloc_ops.end(); ++it) { 63 auto lp = *it; 64 if (lp == p->m_counter) { 65 m_finished_alloc_ops.erase(it); 66 return (T *)p->m_ret; 67 } 68 } 69 m_cond_var.wait(_l); 70 } 71 }; 72 73 template <typename T> void destroy(T *ptr) { 74 std::shared_ptr<shm_service_op_destroy> p = 75 std::make_shared<shm_service_op_destroy>(m_shmem, ptr); 76 m_op_queue->push_back(p); 77 } 78 79 template <typename T> void push_back(T *ptr) { 80 std::shared_ptr<shm_service_op_push_back> p = 81 std::make_shared<shm_service_op_push_back>(); 82 p->m_pointer = ptr; 83 p->m_type_id = T::pkg_identifier; 84 m_op_queue->push_back(p); 85 } 86 87 void handle_construct_op(const std::shared_ptr<shm_service_op_base> &op); 88 void handle_destroy_op(const std::shared_ptr<shm_service_op_base> &op); 89 90 protected: 91 std::mutex m_mutex; 92 std::condition_variable m_cond_var; 93 shm_service_op_queue *m_op_queue; 94 boost::interprocess::managed_shared_memory *m_shmem; 95 std::vector<uint64_t> m_finished_alloc_ops; 96 std::atomic_uint_fast64_t m_next_alloc_op_counter; 97 std::thread::id m_local_thread_id; 98 }; 99 } // namespace internal 100 } // namespace ipc 101 } // namespace neb