Branch data Line data Source code
1 : : /* 2 : : * Copyright (C) 2026 by Thun Lu. All rights reserved. 3 : : * Author: Thun Lu <thun.lu@zohomail.cn> 4 : : * Repo: https://github.com/thun-res/vlink 5 : : * _ __ __ _ __ 6 : : * | | / / / / (_) ____ / /__ 7 : : * | | / / / / / / / __ \ / //_/ 8 : : * | |/ / / /___ / / / / / / / ,< 9 : : * |___/ /_____/ /_/ /_/ /_/ /_/|_| 10 : : * 11 : : * Licensed under the Apache License, Version 2.0 (the "License"); 12 : : * you may not use this file except in compliance with the License. 13 : : * You may obtain a copy of the License at 14 : : * 15 : : * http://www.apache.org/licenses/LICENSE-2.0 16 : : * 17 : : * Unless required by applicable law or agreed to in writing, software 18 : : * distributed under the License is distributed on an "AS IS" BASIS, 19 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 : : * See the License for the specific language governing permissions and 21 : : * limitations under the License. 22 : : */ 23 : : 24 : : #include "./impl/client_impl.h" 25 : : 26 : : #include <mutex> 27 : : #include <utility> 28 : : 29 : : #include "./base/condition_variable.h" 30 : : #include "./base/utils.h" 31 : : 32 : : namespace vlink { 33 : : 34 : : // ClientImplHelper 35 : : struct ClientImplHelper final { 36 : : bool connected{false}; 37 : : NodeImpl::ConnectCallback connected_callback; 38 : : ConditionVariable connected_cv; 39 : : std::mutex mtx; 40 : : std::recursive_mutex callback_mtx; 41 : : }; 42 : : 43 : : // ClientImpl 44 : 150 : ClientImpl::~ClientImpl() = default; 45 : : 46 : 119 : void ClientImpl::interrupt() { 47 : 119 : NodeImpl::interrupt(); 48 : : 49 : : { 50 [ + - ]: 119 : std::lock_guard sync_lock(helper_->mtx); 51 : 119 : } 52 : : 53 : 119 : helper_->connected_cv.notify_all(); 54 : 119 : } 55 : : 56 : 13 : void ClientImpl::detect_connected(ConnectCallback&& callback) { 57 [ + - ]: 13 : std::unique_lock lock(helper_->callback_mtx); 58 : 13 : helper_->connected_callback = std::move(callback); 59 : : 60 [ + + ]: 13 : if (helper_->connected) { 61 [ + - ]: 5 : auto callback_copy = helper_->connected_callback; 62 [ + - ]: 5 : lock.unlock(); 63 [ + - ]: 5 : callback_copy(true); 64 : 5 : } 65 : 13 : } 66 : : 67 : 181 : bool ClientImpl::wait_for_connected(std::chrono::milliseconds timeout) { 68 [ + - + + ]: 181 : if VLIKELY (is_connected()) { 69 : 150 : return true; 70 : : } 71 : : 72 : 31 : Utils::yield_cpu(); 73 : : 74 [ + - ]: 31 : std::unique_lock lock(helper_->mtx); 75 : : 76 [ + - ]: 31 : reset_interrupted(); 77 : : 78 [ + + + + ]: 62 : auto predicate = [this]() -> bool { return is_connected() || is_interrupted(); }; 79 : : 80 [ + + ]: 31 : if VUNLIKELY (timeout.count() < 0) { 81 : 2 : helper_->connected_cv.wait(lock, std::move(predicate)); 82 [ + - ]: 2 : return is_connected(); 83 : : } else { 84 [ + + + - : 29 : return helper_->connected_cv.wait_for(lock, timeout, std::move(predicate)) && !is_interrupted(); + - ] 85 : : } 86 : 31 : } 87 : : 88 : 178 : void ClientImpl::update_connected() { 89 : 178 : Utils::yield_cpu(); 90 : : 91 [ + - ]: 178 : std::unique_lock lock(helper_->callback_mtx); 92 : : 93 [ + - + + ]: 178 : if (helper_->connected == is_connected()) { 94 : 73 : return; 95 : : } 96 : : 97 : 105 : helper_->connected = !helper_->connected; 98 : : 99 : : { 100 [ + - ]: 105 : std::lock_guard sync_lock(helper_->mtx); 101 : 105 : } 102 : : 103 : 105 : helper_->connected_cv.notify_all(); 104 : : 105 [ + + ]: 105 : if (helper_->connected_callback) { 106 : 11 : bool connected = helper_->connected; 107 [ + - ]: 11 : auto callback_copy = helper_->connected_callback; 108 [ + - ]: 11 : lock.unlock(); 109 [ + - ]: 11 : callback_copy(connected); 110 : 11 : } 111 [ + + ]: 178 : } 112 : : 113 [ + - ]: 150 : ClientImpl::ClientImpl() : NodeImpl(kClient), helper_(std::make_unique<ClientImplHelper>()) {} 114 : : 115 : : } // namespace vlink