github.com/igggame/nebulas-go@v2.1.0+incompatible/nbre/common/ipc/shm_session.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_session.h"
    21  #include "common/common.h"
    22  #include "common/configuration.h"
    23  #include "common/exception_queue.h"
    24  #include "fs/util.h"
    25  #include <chrono>
    26  
    27  namespace neb {
    28  namespace ipc {
    29  static std::string bookkeeper_mem_name_str = neb::fs::get_user_name() + ".nbre";
    30  const static char *bookkeeper_mem_name = bookkeeper_mem_name_str.c_str();
    31  
    32  void clean_shm_session_env() {
    33    auto bookkeeper_mem_name_str =
    34        neb::configuration::instance().shm_name_identity() + std::string(".nbre");
    35    auto bookkeeper_mem_name = bookkeeper_mem_name_str.c_str();
    36    clean_bookkeeper_env(bookkeeper_mem_name);
    37  }
    38  namespace internal {
    39  size_t max_wait_fail_times = 8;
    40  
    41  shm_session_base::shm_session_base(const std::string &name)
    42      : quitable_thread(), m_name(name) {
    43    try {
    44      auto bookkeeper_mem_name_str =
    45          neb::configuration::instance().shm_name_identity() +
    46          std::string(".nbre");
    47      auto bookkeeper_mem_name = bookkeeper_mem_name_str.c_str();
    48      m_bookkeeper = std::unique_ptr<shm_bookkeeper>(
    49          new shm_bookkeeper(bookkeeper_mem_name));
    50        m_server_sema = m_bookkeeper->acquire_named_semaphore(server_sema_name());
    51        m_client_sema = m_bookkeeper->acquire_named_semaphore(client_sema_name());
    52    } catch (const std::exception &e) {
    53      throw shm_init_failure(std::string("shm_session_base, ") +
    54                             std::string(typeid(e).name()) + " : " + e.what());
    55    }
    56  }
    57  
    58  shm_session_base::~shm_session_base() {
    59    if (m_thread) {
    60      m_thread->join();
    61      m_thread.reset();
    62    }
    63    m_bookkeeper->release_named_semaphore(server_sema_name());
    64    m_bookkeeper->release_named_semaphore(client_sema_name());
    65  }
    66  
    67  void shm_session_base::reset() {
    68    m_bookkeeper->reset();
    69    //! We need manually remove this
    70    boost::interprocess::named_mutex::remove(server_session_mutex_name().c_str());
    71  }
    72  
    73  void shm_session_base::start_session() { start(); }
    74  
    75  shm_session_util::shm_session_util(const std::string &name)
    76      : shm_session_base(name) {}
    77  
    78  void shm_session_util::thread_func() {}
    79  
    80  shm_session_server::shm_session_server(const std::string &name)
    81      : shm_session_base(name), m_client_started(false), m_client_alive(false) {
    82  }
    83  
    84  void shm_session_server::wait_until_client_start() {
    85    if (m_client_started)
    86      return;
    87    m_client_sema->wait();
    88    m_client_started = true;
    89  }
    90  
    91  bool shm_session_server::is_client_alive() { return m_client_alive; }
    92  
    93  void shm_session_server::start_session() {
    94    start();
    95  }
    96  void shm_session_server::thread_func() {
    97    struct quit_helper {
    98      quit_helper(shm_bookkeeper *bk, const std::string &name)
    99          : m_bk(bk), m_name(name), m_to_unlock(false) {
   100        m_mutex = m_bk->acquire_named_mutex(m_name);
   101      };
   102      ~quit_helper() {
   103        if (m_to_unlock) {
   104          m_mutex->unlock();
   105        }
   106        m_bk->release_named_mutex(m_name);
   107      }
   108      shm_bookkeeper *m_bk;
   109      std::string m_name;
   110      std::unique_ptr<boost::interprocess::named_mutex> m_mutex;
   111      bool m_to_unlock;
   112    } _l(m_bookkeeper.get(), server_session_mutex_name());
   113    if (_l.m_mutex->try_lock()) {
   114      _l.m_to_unlock = true;
   115    } else {
   116      throw shm_session_already_start();
   117    }
   118  
   119    uint32_t fail_counter = 0;
   120    while (!m_exit_flag) {
   121      if (!m_client_started) {
   122        bool ret = m_client_sema->try_wait();
   123        if (ret) {
   124          m_client_started = true;
   125          m_client_alive = true;
   126        }
   127      } else {
   128        bool ret = m_client_sema->try_wait();
   129        if (ret) {
   130          fail_counter = 0;
   131          m_client_alive = true;
   132        } else {
   133          fail_counter++;
   134          if (fail_counter >= max_wait_fail_times) {
   135            m_client_alive = false;
   136            throw shm_session_timeout();
   137          }
   138        }
   139      }
   140      std::this_thread::sleep_for(std::chrono::seconds(1));
   141      m_server_sema->post();
   142    }
   143  }
   144  
   145  shm_session_client::shm_session_client(const std::string &name)
   146      : shm_session_base(name), m_server_alive(false) {}
   147  
   148  void shm_session_client::thread_func() {
   149  
   150    LOG(INFO) << "client loop";
   151    uint32_t fail_counter = 0;
   152    while (!m_exit_flag) {
   153      bool ret = m_server_sema->try_wait();
   154      if (ret) {
   155        // LOG(INFO) << "client wait succ";
   156        fail_counter = 0;
   157        m_server_alive = true;
   158      } else {
   159        // LOG(INFO) << "client wait fail";
   160        fail_counter++;
   161        if (fail_counter >= max_wait_fail_times) {
   162          m_server_alive = false;
   163          LOG(INFO) << "client timeout";
   164          throw shm_session_timeout();
   165        }
   166      }
   167      std::this_thread::sleep_for(std::chrono::seconds(1));
   168      m_client_sema->post();
   169    }
   170  }
   171  
   172  bool shm_session_client::is_server_alive() { return m_server_alive; }
   173  }
   174  }
   175  }