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 }