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