1 /* 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef PANDA_RUNTIME_INCLUDE_LOADABLE_AGENT_H 17 #define PANDA_RUNTIME_INCLUDE_LOADABLE_AGENT_H 18 19 #include "libpandabase/os/library_loader.h" 20 #include "libpandabase/os/mutex.h" 21 #include "runtime/include/mem/panda_smart_pointers.h" 22 #include "runtime/include/mem/panda_string.h" 23 24 namespace panda { 25 class LoadableAgent { 26 public: 27 LoadableAgent() = default; 28 virtual ~LoadableAgent() = default; 29 30 virtual bool Load() = 0; 31 virtual bool Unload() = 0; 32 33 private: 34 NO_COPY_SEMANTIC(LoadableAgent); 35 NO_MOVE_SEMANTIC(LoadableAgent); 36 }; 37 38 using LoadableAgentHandle = std::shared_ptr<LoadableAgent>; 39 40 class LibraryAgent : public LoadableAgent { 41 public: 42 LibraryAgent(os::memory::Mutex &mutex, PandaString libraryPath, PandaString loadCallbackName, 43 PandaString unloadCallbackName); 44 45 bool Load() override; 46 bool Unload() override; 47 48 private: 49 virtual bool CallLoadCallback(void *resolvedFunction) = 0; 50 virtual bool CallUnloadCallback(void *resolvedFunction) = 0; 51 52 os::memory::LockHolder<os::memory::Mutex> lock_; 53 54 PandaString library_path_; 55 PandaString load_callback_name_; 56 PandaString unload_callback_name_; 57 58 os::library_loader::LibraryHandle handle_ {nullptr}; 59 void *unload_callback_ {}; 60 }; 61 62 template <typename AgentType, bool Reusable> 63 class LibraryAgentLoader { 64 public: 65 template <typename... Args> LoadInstance(Args &&...args)66 static LoadableAgentHandle LoadInstance(Args &&... args) 67 { 68 // This mutex is needed to be sure that getting / creation of an instance is made atomically 69 // (e.g. there won't be two threads that found no instance and tried to create a new one). 70 static os::memory::Mutex creation_mutex; 71 os::memory::LockHolder<os::memory::Mutex> creation_mutex_lock(creation_mutex); 72 73 static std::weak_ptr<LoadableAgent> instance; 74 75 auto inst = instance.lock(); 76 if (inst) { 77 if constexpr (Reusable) { // NOLINT(readability-braces-around-statements) 78 return inst; 79 } else { // NOLINT(readability-misleading-indentation) 80 LOG(ERROR, RUNTIME) << "Non-reusable library is already used"; 81 return {}; 82 } 83 } 84 85 // This mutex is needed to be sure that there is only one library at a given point of time 86 // (e.g. a new instance initialization won't be performed earlier than deinitialization of the old one). 87 static os::memory::Mutex uniqueness_mutex; 88 89 auto lib = MakePandaUnique<AgentType>(uniqueness_mutex, std::forward<Args>(args)...); 90 if (!lib->Load()) { 91 LOG(ERROR, RUNTIME) << "Could not load library"; 92 return {}; 93 } 94 95 inst = std::shared_ptr<AgentType>(lib.release(), [](AgentType *ptr) { 96 ptr->Unload(); 97 mem::InternalAllocator<>::GetInternalAllocatorFromRuntime()->Delete(ptr); 98 }); 99 100 instance = inst; 101 102 return inst; 103 } 104 }; 105 } // namespace panda 106 107 #endif // PANDA_RUNTIME_INCLUDE_LOADABLE_AGENT_H 108