diff options
author | 2018-06-08 11:40:38 -0700 | |
---|---|---|
committer | 2018-06-21 16:22:12 -0700 | |
commit | 882ed6bcccf60e55b61aa1860d9a15a7e92af959 (patch) | |
tree | 98df8864025233a5ab2de61e27789308aadd969d | |
parent | 2b40dd35c65ad644d448611750f5b577e97594a1 (diff) |
Add low_4gb MemMap and remove ashmem support for Fuchsia
Test: Tested with Fuchsia build system go/fuchsia-android
Change-Id: I61b09614d6f4d24bf9c975baa1f34c6b5735ca3d
-rw-r--r-- | libartbase/Android.bp | 2 | ||||
-rw-r--r-- | libartbase/base/fuchsia_compat.h | 36 | ||||
-rw-r--r-- | libartbase/base/globals.h | 15 | ||||
-rw-r--r-- | libartbase/base/mem_map.cc | 55 | ||||
-rw-r--r-- | libartbase/base/mem_map.h | 22 | ||||
-rw-r--r-- | libartbase/base/mem_map_fuchsia.cc | 144 | ||||
-rw-r--r-- | libartbase/base/mem_map_unix.cc | 35 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.cc | 4 | ||||
-rw-r--r-- | runtime/oat_file.cc | 3 |
9 files changed, 286 insertions, 30 deletions
diff --git a/libartbase/Android.bp b/libartbase/Android.bp index adf0ad6376..4ee48da5e8 100644 --- a/libartbase/Android.bp +++ b/libartbase/Android.bp @@ -31,6 +31,8 @@ cc_defaults { "base/malloc_arena_pool.cc", "base/memory_region.cc", "base/mem_map.cc", + // "base/mem_map_fuchsia.cc", put in target when fuchsia supported by soong + "base/mem_map_unix.cc", "base/os_linux.cc", "base/runtime_debug.cc", "base/safe_copy.cc", diff --git a/libartbase/base/fuchsia_compat.h b/libartbase/base/fuchsia_compat.h new file mode 100644 index 0000000000..018bac0528 --- /dev/null +++ b/libartbase/base/fuchsia_compat.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_LIBARTBASE_BASE_FUCHSIA_COMPAT_H_ +#define ART_LIBARTBASE_BASE_FUCHSIA_COMPAT_H_ + +// stubs for features lacking in Fuchsia + +struct rlimit { + int rlim_cur; +}; + +#define RLIMIT_FSIZE (1) +#define RLIM_INFINITY (-1) +static int getrlimit(int resource, struct rlimit *rlim) { + LOG(FATAL) << "getrlimit not available for Fuchsia"; +} + +static int ashmem_create_region(const char *name, size_t size) { + LOG(FATAL) << "ashmem_create_region not available for Fuchsia"; +} + +#endif // ART_LIBARTBASE_BASE_FUCHSIA_COMPAT_H_ diff --git a/libartbase/base/globals.h b/libartbase/base/globals.h index 39e0c509cd..cd0bf8fafc 100644 --- a/libartbase/base/globals.h +++ b/libartbase/base/globals.h @@ -74,7 +74,9 @@ static constexpr bool kIsPGOInstrumentation = false; // ART_TARGET - Defined for target builds of ART. // ART_TARGET_LINUX - Defined for target Linux builds of ART. // ART_TARGET_ANDROID - Defined for target Android builds of ART. -// Note: Either ART_TARGET_LINUX or ART_TARGET_ANDROID need to be set when ART_TARGET is set. +// ART_TARGET_FUCHSIA - Defined for Fuchsia builds of ART. +// Note: Either ART_TARGET_LINUX, ART_TARGET_ANDROID or ART_TARGET_FUCHSIA +// need to be set when ART_TARGET is set. // Note: When ART_TARGET_LINUX is defined mem_map.h will not be using Ashmem for memory mappings // (usually only available on Android kernels). #if defined(ART_TARGET) @@ -82,10 +84,16 @@ static constexpr bool kIsPGOInstrumentation = false; static constexpr bool kIsTargetBuild = true; # if defined(ART_TARGET_LINUX) static constexpr bool kIsTargetLinux = true; +static constexpr bool kIsTargetFuchsia = false; # elif defined(ART_TARGET_ANDROID) static constexpr bool kIsTargetLinux = false; +static constexpr bool kIsTargetFuchsia = false; +# elif defined(ART_TARGET_FUCHSIA) +static constexpr bool kIsTargetLinux = false; +static constexpr bool kIsTargetFuchsia = true; # else -# error "Either ART_TARGET_LINUX or ART_TARGET_ANDROID needs to be defined for target builds." +# error "Either ART_TARGET_LINUX, ART_TARGET_ANDROID or ART_TARGET_FUCHSIA " \ + "needs to be defined for target builds." # endif #else static constexpr bool kIsTargetBuild = false; @@ -93,8 +101,11 @@ static constexpr bool kIsTargetBuild = false; # error "ART_TARGET_LINUX defined for host build." # elif defined(ART_TARGET_ANDROID) # error "ART_TARGET_ANDROID defined for host build." +# elif defined(ART_TARGET_FUCHSIA) +# error "ART_TARGET_FUCHSIA defined for host build." # else static constexpr bool kIsTargetLinux = false; +static constexpr bool kIsTargetFuchsia = false; # endif #endif diff --git a/libartbase/base/mem_map.cc b/libartbase/base/mem_map.cc index c455fed829..3ce2b51e15 100644 --- a/libartbase/base/mem_map.cc +++ b/libartbase/base/mem_map.cc @@ -19,7 +19,7 @@ #include <inttypes.h> #include <stdlib.h> #include <sys/mman.h> // For the PROT_* and MAP_* constants. -#ifndef ANDROID_OS +#if !defined(ANDROID_OS) && !defined(__Fuchsia__) #include <sys/resource.h> #endif @@ -29,7 +29,12 @@ #include "android-base/stringprintf.h" #include "android-base/unique_fd.h" + +#if !defined(__Fuchsia__) #include "cutils/ashmem.h" +#else +#include "fuchsia_compat.h" +#endif #include "allocator.h" #include "bit_utils.h" @@ -161,7 +166,7 @@ bool MemMap::ContainedWithinExistingMap(uint8_t* ptr, size_t size, std::string* // non-null, we check that pointer is the actual_ptr == expected_ptr, // and if not, report in error_msg what the conflict mapping was if // found, or a generic error in other cases. -static bool CheckMapRequest(uint8_t* expected_ptr, void* actual_ptr, size_t byte_count, +bool MemMap::CheckMapRequest(uint8_t* expected_ptr, void* actual_ptr, size_t byte_count, std::string* error_msg) { // Handled first by caller for more specific error messages. CHECK(actual_ptr != MAP_FAILED); @@ -178,7 +183,7 @@ static bool CheckMapRequest(uint8_t* expected_ptr, void* actual_ptr, size_t byte } // We asked for an address but didn't get what we wanted, all paths below here should fail. - int result = munmap(actual_ptr, byte_count); + int result = TargetMUnmap(actual_ptr, byte_count); if (result == -1) { PLOG(WARNING) << StringPrintf("munmap(%p, %zd) failed", actual_ptr, byte_count); } @@ -207,18 +212,18 @@ static bool CheckMapRequest(uint8_t* expected_ptr, void* actual_ptr, size_t byte } #if USE_ART_LOW_4G_ALLOCATOR -static inline void* TryMemMapLow4GB(void* ptr, +void* MemMap::TryMemMapLow4GB(void* ptr, size_t page_aligned_byte_count, int prot, int flags, int fd, off_t offset) { - void* actual = mmap(ptr, page_aligned_byte_count, prot, flags, fd, offset); + void* actual = TargetMMap(ptr, page_aligned_byte_count, prot, flags, fd, offset); if (actual != MAP_FAILED) { // Since we didn't use MAP_FIXED the kernel may have mapped it somewhere not in the low // 4GB. If this is the case, unmap and retry. if (reinterpret_cast<uintptr_t>(actual) + page_aligned_byte_count >= 4 * GB) { - munmap(actual, page_aligned_byte_count); + TargetMUnmap(actual, page_aligned_byte_count); actual = MAP_FAILED; } } @@ -237,7 +242,7 @@ MemMap* MemMap::MapAnonymous(const char* name, #ifndef __LP64__ UNUSED(low_4gb); #endif - use_ashmem = use_ashmem && !kIsTargetLinux; + use_ashmem = use_ashmem && !kIsTargetLinux && !kIsTargetFuchsia; if (byte_count == 0) { return new MemMap(name, nullptr, 0, nullptr, 0, prot, false); } @@ -521,7 +526,7 @@ MemMap::~MemMap() { if (!reuse_) { MEMORY_TOOL_MAKE_UNDEFINED(base_begin_, base_size_); if (!already_unmapped_) { - int result = munmap(base_begin_, base_size_); + int result = TargetMUnmap(base_begin_, base_size_); if (result == -1) { PLOG(FATAL) << "munmap failed"; } @@ -565,7 +570,7 @@ MemMap::MemMap(const std::string& name, uint8_t* begin, size_t size, void* base_ MemMap* MemMap::RemapAtEnd(uint8_t* new_end, const char* tail_name, int tail_prot, std::string* error_msg, bool use_ashmem) { - use_ashmem = use_ashmem && !kIsTargetLinux; + use_ashmem = use_ashmem && !kIsTargetLinux && !kIsTargetFuchsia; DCHECK_GE(new_end, Begin()); DCHECK_LE(new_end, End()); DCHECK_LE(begin_ + size_, reinterpret_cast<uint8_t*>(base_begin_) + base_size_); @@ -607,7 +612,7 @@ MemMap* MemMap::RemapAtEnd(uint8_t* new_end, const char* tail_name, int tail_pro MEMORY_TOOL_MAKE_UNDEFINED(tail_base_begin, tail_base_size); // Unmap/map the tail region. - int result = munmap(tail_base_begin, tail_base_size); + int result = TargetMUnmap(tail_base_begin, tail_base_size); if (result == -1) { PrintFileToLog("/proc/self/maps", LogSeverity::WARNING); *error_msg = StringPrintf("munmap(%p, %zd) failed for '%s'. See process maps in the log.", @@ -618,12 +623,12 @@ MemMap* MemMap::RemapAtEnd(uint8_t* new_end, const char* tail_name, int tail_pro // calls. Otherwise, libc (or something else) might take this memory // region. Note this isn't perfect as there's no way to prevent // other threads to try to take this memory region here. - uint8_t* actual = reinterpret_cast<uint8_t*>(mmap(tail_base_begin, - tail_base_size, - tail_prot, - flags, - fd.get(), - 0)); + uint8_t* actual = reinterpret_cast<uint8_t*>(TargetMMap(tail_base_begin, + tail_base_size, + tail_prot, + flags, + fd.get(), + 0)); if (actual == MAP_FAILED) { PrintFileToLog("/proc/self/maps", LogSeverity::WARNING); *error_msg = StringPrintf("anonymous mmap(%p, %zd, 0x%x, 0x%x, %d, 0) failed. See process " @@ -798,6 +803,8 @@ void MemMap::Init() { std::lock_guard<std::mutex> mu(*mem_maps_lock_); DCHECK(gMaps == nullptr); gMaps = new Maps; + + TargetMMapInit(); } void MemMap::Shutdown() { @@ -829,8 +836,10 @@ void MemMap::SetSize(size_t new_size) { reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(BaseBegin()) + new_base_size), base_size_ - new_base_size); - CHECK_EQ(munmap(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(BaseBegin()) + new_base_size), - base_size_ - new_base_size), 0) << new_base_size << " " << base_size_; + CHECK_EQ(TargetMUnmap(reinterpret_cast<void*>( + reinterpret_cast<uintptr_t>(BaseBegin()) + new_base_size), + base_size_ - new_base_size), 0) + << new_base_size << " " << base_size_; base_size_ = new_base_size; size_ = new_size; } @@ -976,7 +985,7 @@ void* MemMap::MapInternal(void* addr, if (orig_prot != prot_non_exec) { if (mprotect(actual, length, orig_prot) != 0) { PLOG(ERROR) << "Could not protect to requested prot: " << orig_prot; - munmap(actual, length); + TargetMUnmap(actual, length); errno = ENOMEM; return MAP_FAILED; } @@ -984,14 +993,14 @@ void* MemMap::MapInternal(void* addr, return actual; } - actual = mmap(addr, length, prot, flags, fd, offset); + actual = TargetMMap(addr, length, prot, flags, fd, offset); #else #if defined(__LP64__) if (low_4gb && addr == nullptr) { flags |= MAP_32BIT; } #endif - actual = mmap(addr, length, prot, flags, fd, offset); + actual = TargetMMap(addr, length, prot, flags, fd, offset); #endif return actual; } @@ -1067,13 +1076,13 @@ void MemMap::AlignBy(size_t size) { // Unmap the unaligned parts. if (base_begin < aligned_base_begin) { MEMORY_TOOL_MAKE_UNDEFINED(base_begin, aligned_base_begin - base_begin); - CHECK_EQ(munmap(base_begin, aligned_base_begin - base_begin), 0) + CHECK_EQ(TargetMUnmap(base_begin, aligned_base_begin - base_begin), 0) << "base_begin=" << reinterpret_cast<void*>(base_begin) << " aligned_base_begin=" << reinterpret_cast<void*>(aligned_base_begin); } if (aligned_base_end < base_end) { MEMORY_TOOL_MAKE_UNDEFINED(aligned_base_end, base_end - aligned_base_end); - CHECK_EQ(munmap(aligned_base_end, base_end - aligned_base_end), 0) + CHECK_EQ(TargetMUnmap(aligned_base_end, base_end - aligned_base_end), 0) << "base_end=" << reinterpret_cast<void*>(base_end) << " aligned_base_end=" << reinterpret_cast<void*>(aligned_base_end); } diff --git a/libartbase/base/mem_map.h b/libartbase/base/mem_map.h index 3a324b2dc5..1979357714 100644 --- a/libartbase/base/mem_map.h +++ b/libartbase/base/mem_map.h @@ -29,10 +29,11 @@ namespace art { -#if defined(__LP64__) && (defined(__aarch64__) || defined(__mips__) || defined(__APPLE__)) +#if defined(__LP64__) && !defined(__Fuchsia__) && \ + (defined(__aarch64__) || defined(__mips__) || defined(__APPLE__)) #define USE_ART_LOW_4G_ALLOCATOR 1 #else -#if defined(__LP64__) && !defined(__x86_64__) +#if defined(__LP64__) && !defined(__Fuchsia__) && !defined(__x86_64__) #error "Unrecognized 64-bit architecture." #endif #define USE_ART_LOW_4G_ALLOCATOR 0 @@ -264,6 +265,12 @@ class MemMap { off_t offset) REQUIRES(!MemMap::mem_maps_lock_); + // member function to access real_munmap + static bool CheckMapRequest(uint8_t* expected_ptr, + void* actual_ptr, + size_t byte_count, + std::string* error_msg); + const std::string name_; uint8_t* begin_; // Start of data. May be changed by AlignBy. size_t size_; // Length of data. @@ -284,8 +291,19 @@ class MemMap { #if USE_ART_LOW_4G_ALLOCATOR static uintptr_t next_mem_pos_; // Next memory location to check for low_4g extent. + + static void* TryMemMapLow4GB(void* ptr, + size_t page_aligned_byte_count, + int prot, + int flags, + int fd, + off_t offset); #endif + static void TargetMMapInit(); + static void* TargetMMap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off); + static int TargetMUnmap(void* start, size_t len); + static std::mutex* mem_maps_lock_; friend class MemMapTest; // To allow access to base_begin_ and base_size_. diff --git a/libartbase/base/mem_map_fuchsia.cc b/libartbase/base/mem_map_fuchsia.cc new file mode 100644 index 0000000000..db31efb1c0 --- /dev/null +++ b/libartbase/base/mem_map_fuchsia.cc @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mem_map.h" +#include <sys/mman.h> +#include "logging.h" + +#include <zircon/process.h> +#include <zircon/syscalls.h> + +namespace art { + +static zx_handle_t fuchsia_lowmem_vmar = ZX_HANDLE_INVALID; +static zx_vaddr_t fuchsia_lowmem_base = 0; +static size_t fuchsia_lowmem_size = 0; + +static const char map_name[] = "mmap-android"; +static constexpr uintptr_t FUCHSIA_LOWER_MEM_START = 0x80000000; +static constexpr uintptr_t FUCHSIA_LOWER_MEM_SIZE = 0x60000000; + +void MemMap::TargetMMapInit() { + if (fuchsia_lowmem_vmar != ZX_HANDLE_INVALID) { + return; + } + + zx_info_vmar_t vmarinfo; + CHECK_EQ(zx_object_get_info(zx_vmar_root_self(), + ZX_INFO_VMAR, + &vmarinfo, + sizeof(vmarinfo), + NULL, + NULL), ZX_OK) << "could not find info from root vmar"; + + uintptr_t lower_mem_start = FUCHSIA_LOWER_MEM_START - vmarinfo.base; + fuchsia_lowmem_size = FUCHSIA_LOWER_MEM_SIZE; + uint32_t allocflags = ZX_VM_FLAG_CAN_MAP_READ | + ZX_VM_FLAG_CAN_MAP_WRITE | + ZX_VM_FLAG_CAN_MAP_EXECUTE | + ZX_VM_FLAG_SPECIFIC; + CHECK_EQ(zx_vmar_allocate(zx_vmar_root_self(), + lower_mem_start, + fuchsia_lowmem_size, + allocflags, + &fuchsia_lowmem_vmar, + &fuchsia_lowmem_base), ZX_OK) << "could not allocate lowmem vmar"; +} + +void* MemMap::TargetMMap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off) { + zx_status_t status; + uintptr_t mem = 0; + + bool mmap_lower = (flags & MAP_32BIT) != 0; + + // for file-based mapping use system library + if ((flags & MAP_ANONYMOUS) == 0) { + if (start != nullptr) { + flags |= MAP_FIXED; + } + CHECK(!mmap_lower) << "cannot map files into low memory for Fuchsia"; + return mmap(start, len, prot, flags, fd, fd_off); + } + + uint32_t vmarflags = 0; + if ((prot & PROT_READ) != 0) { + vmarflags |= ZX_VM_FLAG_PERM_READ; + } + if ((prot & PROT_WRITE) != 0) { + vmarflags |= ZX_VM_FLAG_PERM_WRITE; + } + if ((prot & PROT_EXEC) != 0) { + vmarflags |= ZX_VM_FLAG_PERM_EXECUTE; + } + + if (len == 0) { + errno = EINVAL; + return MAP_FAILED; + } + + zx_info_vmar_t vmarinfo; + size_t vmaroffset = 0; + if (start != nullptr) { + vmarflags |= ZX_VM_FLAG_SPECIFIC; + status = zx_object_get_info((mmap_lower ? fuchsia_lowmem_vmar : zx_vmar_root_self()), + ZX_INFO_VMAR, + &vmarinfo, + sizeof(vmarinfo), + NULL, + NULL); + if (status < 0 || reinterpret_cast<uintptr_t>(start) < vmarinfo.base) { + errno = EINVAL; + return MAP_FAILED; + } + vmaroffset = reinterpret_cast<uintptr_t>(start) - vmarinfo.base; + } + + zx_handle_t vmo; + if (zx_vmo_create(len, 0, &vmo) < 0) { + errno = ENOMEM; + return MAP_FAILED; + } + zx_vmo_get_size(vmo, &len); + zx_object_set_property(vmo, ZX_PROP_NAME, map_name, strlen(map_name)); + + if (mmap_lower) { + status = zx_vmar_map(fuchsia_lowmem_vmar, vmaroffset, vmo, fd_off, len, vmarflags, &mem); + } else { + status = zx_vmar_map(zx_vmar_root_self(), vmaroffset, vmo, fd_off, len, vmarflags, &mem); + } + zx_handle_close(vmo); + if (status != ZX_OK) { + return MAP_FAILED; + } + + return reinterpret_cast<void *>(mem); +} + +int MemMap::TargetMUnmap(void* start, size_t len) { + uintptr_t addr = reinterpret_cast<uintptr_t>(start); + zx_handle_t alloc_vmar = zx_vmar_root_self(); + if (addr >= fuchsia_lowmem_base && addr < fuchsia_lowmem_base + fuchsia_lowmem_size) { + alloc_vmar = fuchsia_lowmem_vmar; + } + zx_status_t status = zx_vmar_unmap(alloc_vmar, addr, len); + if (status < 0) { + errno = EINVAL; + return -1; + } + return 0; +} + +} // namespace art diff --git a/libartbase/base/mem_map_unix.cc b/libartbase/base/mem_map_unix.cc new file mode 100644 index 0000000000..601b049525 --- /dev/null +++ b/libartbase/base/mem_map_unix.cc @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mem_map.h" + +#include <sys/mman.h> + +namespace art { + +void MemMap::TargetMMapInit() { + // no-op for unix +} + +void* MemMap::TargetMMap(void* start, size_t len, int prot, int flags, int fd, off_t fd_off) { + return mmap(start, len, prot, flags, fd, fd_off); +} + +int MemMap::TargetMUnmap(void* start, size_t len) { + return munmap(start, len); +} + +} // namespace art diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index b010650345..b1cd5c0657 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -167,8 +167,8 @@ JitCodeCache* JitCodeCache::Create(size_t initial_capacity, // Generating debug information is for using the Linux perf tool on // host which does not work with ashmem. - // Also, target linux does not support ashmem. - bool use_ashmem = !generate_debug_info && !kIsTargetLinux; + // Also, targets linux and fuchsia do not support ashmem. + bool use_ashmem = !generate_debug_info && !kIsTargetLinux && !kIsTargetFuchsia; // With 'perf', we want a 1-1 mapping between an address and a method. bool garbage_collect_code = !generate_debug_info; diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 2b05b0e3dd..9355ae720d 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -1063,7 +1063,8 @@ bool DlOpenOatFile::Dlopen(const std::string& elf_filename, dlopen_handle_ = android_dlopen_ext(absolute_path.get(), RTLD_NOW, &extinfo); #else UNUSED(oat_file_begin); - static_assert(!kIsTargetBuild || kIsTargetLinux, "host_dlopen_handles_ will leak handles"); + static_assert(!kIsTargetBuild || kIsTargetLinux || kIsTargetFuchsia, + "host_dlopen_handles_ will leak handles"); MutexLock mu(Thread::Current(), *Locks::host_dlopen_handles_lock_); dlopen_handle_ = dlopen(absolute_path.get(), RTLD_NOW); if (dlopen_handle_ != nullptr) { |