Rewriting/simplifying DynamicLibrary in C. (#5221)
This allowed for a lot of file IO code to go away - there was needless
abstraction here as there was only a single user of a lot of these things
that was already platform-specialized.
Progress on #4369 and #3848.
Fixes #4642.
Unblocks #3845, which can now be added cleanly.
diff --git a/iree/base/BUILD b/iree/base/BUILD
index 32e4a10..e2fc7bc 100644
--- a/iree/base/BUILD
+++ b/iree/base/BUILD
@@ -64,26 +64,6 @@
#===------------------------------------------------------------------------===#
cc_library(
- name = "dynamic_library",
- srcs = [
- "dynamic_library_posix.cc",
- "dynamic_library_win32.cc",
- ],
- hdrs = ["dynamic_library.h"],
- deps = [
- ":core_headers",
- ":logging",
- ":status",
- ":tracing",
- "//build_tools:default_linkopts",
- "//iree/base/internal:file_path",
- "@com_google_absl//absl/memory",
- "@com_google_absl//absl/strings",
- "@com_google_absl//absl/types:span",
- ],
-)
-
-cc_library(
name = "flatcc",
hdrs = ["flatcc.h"],
deps = [
diff --git a/iree/base/CMakeLists.txt b/iree/base/CMakeLists.txt
index 3855042..71c2c05 100644
--- a/iree/base/CMakeLists.txt
+++ b/iree/base/CMakeLists.txt
@@ -50,26 +50,6 @@
iree_cc_library(
NAME
- dynamic_library
- HDRS
- "dynamic_library.h"
- SRCS
- "dynamic_library_posix.cc"
- "dynamic_library_win32.cc"
- DEPS
- ::core_headers
- ::logging
- ::status
- ::tracing
- absl::memory
- absl::span
- absl::strings
- iree::base::internal::file_path
- PUBLIC
-)
-
-iree_cc_library(
- NAME
flatcc
HDRS
"flatcc.h"
diff --git a/iree/base/dynamic_library.h b/iree/base/dynamic_library.h
deleted file mode 100644
index 213bb3d..0000000
--- a/iree/base/dynamic_library.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// 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
-//
-// https://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 IREE_BASE_DYNAMIC_LIBRARY_H_
-#define IREE_BASE_DYNAMIC_LIBRARY_H_
-
-#include <memory>
-#include <string>
-
-#include "absl/types/span.h"
-#include "iree/base/status.h"
-
-namespace iree {
-
-// Dynamic library / shared object cross-platform wrapper class.
-//
-// Paths searched for libraries are platform and environment-specific.
-// In general...
-// * On Linux, the LD_LIBRARY_PATH environment variable may be set to a
-// colon-separated list of directories to search before the standard set.
-// * On Windows, all directories in the PATH environment variable are checked.
-// Library file names may be relative to the search paths, or absolute.
-// Certain platforms may require the library extension (.so, .dll), or it may
-// be optional. If you know the extension, prefer to include it.
-//
-// Usage:
-// static const char* kSearchNames[] = {"libfoo.so"};
-// IREE_ASSIGN_OR_RETURN(library,
-// DynamicLibrary::Load(absl::MakeSpan(kSearchNames)));
-// void* library_symbol_bar = library->GetSymbol("bar");
-// void* library_symbol_baz = library->GetSymbol("baz");
-class DynamicLibrary {
- public:
- virtual ~DynamicLibrary() = default;
-
- // Loads the library at the null-terminated string |search_file_name|.
- static Status Load(const char* search_file_name,
- std::unique_ptr<DynamicLibrary>* out_library) {
- return Load(absl::Span<const char* const>({search_file_name}), out_library);
- }
- // Loads the library at the first name within |search_file_names| found.
- static Status Load(absl::Span<const char* const> search_file_names,
- std::unique_ptr<DynamicLibrary>* out_library);
-
- // Gets the name of the library file that is loaded.
- const std::string& file_name() const { return file_name_; }
-
- // Loads a debug database (PDB/DWARF/etc) from the given path providing debug
- // symbols for this library and attaches it to the symbol store (if active).
- virtual void AttachDebugDatabase(const char* database_file_name) {}
-
- // Gets the address of a symbol with the given name in the loaded library.
- // Returns NULL if the symbol could not be found.
- virtual void* GetSymbol(const char* symbol_name) const = 0;
- template <typename T>
- T GetSymbol(const char* symbol_name) const {
- return reinterpret_cast<T>(GetSymbol(symbol_name));
- }
-
- protected:
- // Private constructor, use |Load| factory method instead.
- DynamicLibrary(std::string file_name) : file_name_(file_name) {}
-
- std::string file_name_;
-};
-
-} // namespace iree
-
-#endif // IREE_BASE_DYNAMIC_LIBRARY_H_
diff --git a/iree/base/dynamic_library_posix.cc b/iree/base/dynamic_library_posix.cc
deleted file mode 100644
index 3027a68..0000000
--- a/iree/base/dynamic_library_posix.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// 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
-//
-// https://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 "absl/memory/memory.h"
-#include "iree/base/dynamic_library.h"
-#include "iree/base/target_platform.h"
-#include "iree/base/tracing.h"
-
-#if defined(IREE_PLATFORM_ANDROID) || defined(IREE_PLATFORM_APPLE) || \
- defined(IREE_PLATFORM_LINUX)
-
-#include <dlfcn.h>
-
-namespace iree {
-
-class DynamicLibraryPosix : public DynamicLibrary {
- public:
- ~DynamicLibraryPosix() override {
- // TODO(benvanik): disable if we want to get profiling results.
- // Sometimes closing the library can prevent proper symbolization on
- // crashes or in sampling profilers.
- ::dlclose(library_);
- }
-
- static Status Load(absl::Span<const char* const> search_file_names,
- std::unique_ptr<DynamicLibrary>* out_library) {
- IREE_TRACE_SCOPE0("DynamicLibraryPosix::Load");
- out_library->reset();
-
- for (int i = 0; i < search_file_names.size(); ++i) {
- void* library = ::dlopen(search_file_names[i], RTLD_LAZY | RTLD_LOCAL);
- if (library) {
- out_library->reset(
- new DynamicLibraryPosix(search_file_names[i], library));
- return OkStatus();
- }
- }
- return iree_make_status(IREE_STATUS_UNAVAILABLE,
- "unable to open dynamic library:'%s'", dlerror());
- }
-
- void* GetSymbol(const char* symbol_name) const override {
- return ::dlsym(library_, symbol_name);
- }
-
- private:
- DynamicLibraryPosix(std::string file_name, void* library)
- : DynamicLibrary(file_name), library_(library) {}
-
- void* library_;
-};
-
-// static
-Status DynamicLibrary::Load(absl::Span<const char* const> search_file_names,
- std::unique_ptr<DynamicLibrary>* out_library) {
- return DynamicLibraryPosix::Load(search_file_names, out_library);
-}
-
-} // namespace iree
-
-#endif // IREE_PLATFORM_*
diff --git a/iree/base/dynamic_library_win32.cc b/iree/base/dynamic_library_win32.cc
deleted file mode 100644
index 804d793..0000000
--- a/iree/base/dynamic_library_win32.cc
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright 2020 Google LLC
-//
-// 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
-//
-// https://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 "absl/memory/memory.h"
-#include "absl/strings/str_replace.h"
-#include "iree/base/dynamic_library.h"
-#include "iree/base/internal/file_path.h"
-#include "iree/base/target_platform.h"
-#include "iree/base/tracing.h"
-
-#if defined(IREE_PLATFORM_WINDOWS)
-
-// TODO(benvanik): support PDB overlays when tracy is not enabled too; we'll
-// need to rearrange how the dbghelp lock is handled for that (probably moving
-// it here and having the tracy code redirect to this).
-#if defined(TRACY_ENABLE)
-#define IREE_HAVE_DYNAMIC_LIBRARY_PDB_SUPPORT 1
-#pragma warning(disable : 4091)
-#include <dbghelp.h>
-extern "C" void IREEDbgHelpLock();
-extern "C" void IREEDbgHelpUnlock();
-#endif // TRACY_ENABLE
-
-namespace iree {
-
-// We need to match the expected paths from dbghelp exactly or else we'll get
-// spurious warnings during module resolution. AFAICT our approach here with
-// loading the PDBs directly with a module base/size of the loaded module will
-// work regardless but calls like SymRefreshModuleList will still attempt to
-// load from system symbol search paths if things don't line up.
-static void CanonicalizePath(std::string* path) {
- absl::StrReplaceAll({{"/", "\\"}}, path);
- absl::StrReplaceAll({{"\\\\", "\\"}}, path);
-}
-
-class DynamicLibraryWin : public DynamicLibrary {
- public:
- ~DynamicLibraryWin() override {
- IREE_TRACE_SCOPE();
- // TODO(benvanik): disable if we want to get profiling results.
- // Sometimes closing the library can prevent proper symbolization on
- // crashes or in sampling profilers.
- ::FreeLibrary(library_);
- }
-
- static Status Load(absl::Span<const char* const> search_file_names,
- std::unique_ptr<DynamicLibrary>* out_library) {
- IREE_TRACE_SCOPE();
- out_library->reset();
-
- for (int i = 0; i < search_file_names.size(); ++i) {
- HMODULE library = ::LoadLibraryA(search_file_names[i]);
- if (library) {
- out_library->reset(
- new DynamicLibraryWin(search_file_names[i], library));
- return OkStatus();
- }
- }
-
- return iree_make_status(
- IREE_STATUS_UNAVAILABLE,
- "unable to open dynamic library, not found on search paths");
- }
-
-#if defined(IREE_HAVE_DYNAMIC_LIBRARY_PDB_SUPPORT)
- void AttachDebugDatabase(const char* database_file_name) override {
- IREE_TRACE_SCOPE();
-
- // Derive the base module name (path stem) for the loaded module.
- // For example, the name of 'C:\Dev\foo.dll' would be 'foo'.
- // This name is used by dbghelp for listing loaded modules and we want to
- // ensure we match the name of the PDB module with the library module.
- std::string module_name = file_name_;
- size_t last_slash = module_name.find_last_of('\\');
- if (last_slash != std::string::npos) {
- module_name = module_name.substr(last_slash + 1);
- }
- size_t dot = module_name.find_last_of('.');
- if (dot != std::string::npos) {
- module_name = module_name.substr(0, dot);
- }
-
- IREEDbgHelpLock();
-
- // Useful for debugging; will print search paths and results:
- // SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_DEBUG);
-
- // Enumerates all loaded modules in the process to extract the module
- // base/size parameters we need to overlay the PDB. There's other ways to
- // get this (such as registering a LdrDllNotification callback and snooping
- // the values during LoadLibrary or using CreateToolhelp32Snapshot), however
- // EnumerateLoadedModules is in dbghelp which we are using anyway.
- ModuleEnumCallbackState state;
- state.module_file_path = file_name_.c_str();
- EnumerateLoadedModules64(GetCurrentProcess(), EnumLoadedModulesCallback,
- &state);
-
- // Load the PDB file and overlay it onto the already-loaded module at the
- // address range it got loaded into.
- if (state.module_base != 0) {
- SymLoadModuleEx(GetCurrentProcess(), NULL, database_file_name,
- module_name.c_str(), state.module_base, state.module_size,
- NULL, 0);
- }
-
- IREEDbgHelpUnlock();
- }
-#endif // IREE_HAVE_DYNAMIC_LIBRARY_PDB_SUPPORT
-
- void* GetSymbol(const char* symbol_name) const override {
- return reinterpret_cast<void*>(::GetProcAddress(library_, symbol_name));
- }
-
- private:
- DynamicLibraryWin(std::string file_name, HMODULE library)
- : DynamicLibrary(std::move(file_name)), library_(library) {
- CanonicalizePath(&file_name_);
- }
-
-#if defined(IREE_HAVE_DYNAMIC_LIBRARY_PDB_SUPPORT)
- struct ModuleEnumCallbackState {
- const char* module_file_path = NULL;
- DWORD64 module_base = 0;
- ULONG module_size = 0;
- };
- static BOOL EnumLoadedModulesCallback(PCSTR ModuleName, DWORD64 ModuleBase,
- ULONG ModuleSize, PVOID UserContext) {
- auto* state = reinterpret_cast<ModuleEnumCallbackState*>(UserContext);
- if (strcmp(ModuleName, state->module_file_path) != 0) {
- return TRUE; // not a match; continue
- }
- state->module_base = ModuleBase;
- state->module_size = ModuleSize;
- return FALSE; // match found; stop enumeration
- }
-#endif // IREE_HAVE_DYNAMIC_LIBRARY_PDB_SUPPORT
-
- HMODULE library_ = NULL;
-};
-
-// static
-Status DynamicLibrary::Load(absl::Span<const char* const> search_file_names,
- std::unique_ptr<DynamicLibrary>* out_library) {
- return DynamicLibraryWin::Load(search_file_names, out_library);
-}
-
-} // namespace iree
-
-#endif // IREE_PLATFORM_*
diff --git a/iree/base/internal/BUILD b/iree/base/internal/BUILD
index efc4dd4..0906894 100644
--- a/iree/base/internal/BUILD
+++ b/iree/base/internal/BUILD
@@ -90,36 +90,29 @@
)
cc_library(
- name = "file_handle_win32",
- srcs = ["file_handle_win32.cc"],
- hdrs = ["file_handle_win32.h"],
+ name = "dynamic_library",
+ srcs = [
+ "dynamic_library_posix.c",
+ "dynamic_library_win32.c",
+ ],
+ hdrs = ["dynamic_library.h"],
deps = [
+ ":file_path",
+ ":internal",
"//iree/base:core_headers",
- "//iree/base:status",
- "@com_google_absl//absl/memory",
- "@com_google_absl//absl/strings",
+ "//iree/base:threading",
+ "//iree/base:tracing",
],
)
cc_library(
name = "file_io",
+ srcs = ["file_io.cc"],
hdrs = ["file_io.h"],
deps = [
+ "//iree/base:api",
"//iree/base:core_headers",
- "//iree/base:status",
- "//iree/base/internal:file_io_internal",
- "@com_google_absl//absl/memory",
- "@com_google_absl//absl/strings",
- "@com_google_absl//absl/types:span",
- ],
-)
-
-cc_library(
- name = "file_io_hdrs",
- hdrs = ["file_io.h"],
- deps = [
- "//iree/base:status",
- "@com_google_absl//absl/strings",
+ "//iree/base:tracing",
],
)
@@ -128,28 +121,8 @@
srcs = ["file_io_test.cc"],
deps = [
":file_io",
- "//iree/base:logging",
- "//iree/base:status",
"//iree/testing:gtest",
"//iree/testing:gtest_main",
- "@com_google_absl//absl/strings",
- ],
-)
-
-cc_library(
- name = "file_io_internal",
- srcs = [
- "file_io_posix.cc",
- "file_io_win32.cc",
- ],
- deps = [
- ":file_handle_win32",
- ":file_io_hdrs",
- "//iree/base:core_headers",
- "//iree/base:status",
- "//iree/base:tracing",
- "@com_google_absl//absl/memory",
- "@com_google_absl//absl/strings",
],
)
diff --git a/iree/base/internal/CMakeLists.txt b/iree/base/internal/CMakeLists.txt
index 6cf3640..2ab0ae8 100644
--- a/iree/base/internal/CMakeLists.txt
+++ b/iree/base/internal/CMakeLists.txt
@@ -76,16 +76,18 @@
iree_cc_library(
NAME
- file_handle_win32
+ dynamic_library
HDRS
- "file_handle_win32.h"
+ "dynamic_library.h"
SRCS
- "file_handle_win32.cc"
+ "dynamic_library_posix.c"
+ "dynamic_library_win32.c"
DEPS
- absl::memory
- absl::strings
+ ::file_path
+ ::internal
iree::base::core_headers
- iree::base::status
+ iree::base::threading
+ iree::base::tracing
PUBLIC
)
@@ -94,24 +96,12 @@
file_io
HDRS
"file_io.h"
+ SRCS
+ "file_io.cc"
DEPS
- absl::memory
- absl::span
- absl::strings
+ iree::base::api
iree::base::core_headers
- iree::base::internal::file_io_internal
- iree::base::status
- PUBLIC
-)
-
-iree_cc_library(
- NAME
- file_io_hdrs
- HDRS
- "file_io.h"
- DEPS
- absl::strings
- iree::base::status
+ iree::base::tracing
PUBLIC
)
@@ -122,32 +112,12 @@
"file_io_test.cc"
DEPS
::file_io
- absl::strings
- iree::base::logging
- iree::base::status
iree::testing::gtest
iree::testing::gtest_main
)
iree_cc_library(
NAME
- file_io_internal
- SRCS
- "file_io_posix.cc"
- "file_io_win32.cc"
- DEPS
- ::file_handle_win32
- ::file_io_hdrs
- absl::memory
- absl::strings
- iree::base::core_headers
- iree::base::status
- iree::base::tracing
- PUBLIC
-)
-
-iree_cc_library(
- NAME
file_path
HDRS
"file_path.h"
diff --git a/iree/base/internal/dynamic_library.h b/iree/base/internal/dynamic_library.h
new file mode 100644
index 0000000..eff168a
--- /dev/null
+++ b/iree/base/internal/dynamic_library.h
@@ -0,0 +1,86 @@
+// Copyright 2021 Google LLC
+//
+// 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
+//
+// https://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 IREE_BASE_INTERNAL_DYNAMIC_LIBRARY_H_
+#define IREE_BASE_INTERNAL_DYNAMIC_LIBRARY_H_
+
+#include "iree/base/api.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Defines the behavior of the dynamic library loader.
+enum iree_dynamic_library_flags_e {
+ IREE_DYNAMIC_LIBRARY_FLAG_NONE = 0u,
+};
+typedef uint32_t iree_dynamic_library_flags_t;
+
+// Dynamic library (aka shared object) cross-platform wrapper.
+typedef struct iree_dynamic_library_s iree_dynamic_library_t;
+
+// Loads a system library using both the system library load paths and the given
+// file name. The path may may be absolute or relative.
+//
+// For process-wide search control the LD_LIBRARY_PATH (Linux) or PATH (Windows)
+// is used in addition to the default search path rules of the platform.
+iree_status_t iree_dynamic_library_load_from_file(
+ const char* file_path, iree_dynamic_library_flags_t flags,
+ iree_allocator_t allocator, iree_dynamic_library_t** out_library);
+
+// Loads a system library using both the system library load paths and the given
+// search path/alternative file names. The paths may may be absolute or
+// relative.
+//
+// For process-wide search control the LD_LIBRARY_PATH (Linux) or PATH (Windows)
+// is used in addition to the default search path rules of the platform.
+iree_status_t iree_dynamic_library_load_from_files(
+ iree_host_size_t search_path_count, const char* const* search_paths,
+ iree_dynamic_library_flags_t flags, iree_allocator_t allocator,
+ iree_dynamic_library_t** out_library);
+
+// Opens a dynamic library from a range of bytes in memory.
+// |identifier| will be used as the module name in debugging/profiling tools.
+// |buffer| must remain live for the lifetime of the library.
+iree_status_t iree_dynamic_library_load_from_memory(
+ iree_string_view_t identifier, iree_const_byte_span_t buffer,
+ iree_dynamic_library_flags_t flags, iree_allocator_t allocator,
+ iree_dynamic_library_t** out_library);
+
+// Retains the given |library| for the caller.
+void iree_dynamic_library_retain(iree_dynamic_library_t* library);
+
+// Releases the given |library| from the caller.
+void iree_dynamic_library_release(iree_dynamic_library_t* library);
+
+// Performs a symbol lookup in the dynamic library exports.
+iree_status_t iree_dynamic_library_lookup_symbol(
+ iree_dynamic_library_t* library, const char* symbol_name, void** out_fn);
+
+// Loads a debug database (PDB/DWARF/etc) from the given path providing debug
+// symbols for this library and attaches it to the symbol store (if active).
+iree_status_t iree_dynamic_library_attach_symbols_from_file(
+ iree_dynamic_library_t* library, const char* file_path);
+
+// Loads a debug database (PDB/DWARF/etc) from a range of bytes in memory and
+// attaches it to the symbol store (if active). |buffer| must remain live for
+// the lifetime of the library.
+iree_status_t iree_dynamic_library_attach_symbols_from_memory(
+ iree_dynamic_library_t* library, iree_const_byte_span_t buffer);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // IREE_BASE_INTERNAL_DYNAMIC_LIBRARY_H_
diff --git a/iree/base/internal/dynamic_library_posix.c b/iree/base/internal/dynamic_library_posix.c
new file mode 100644
index 0000000..91e81c4
--- /dev/null
+++ b/iree/base/internal/dynamic_library_posix.c
@@ -0,0 +1,286 @@
+// Copyright 2021 Google LLC
+//
+// 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
+//
+// https://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 <stdio.h>
+
+#include "iree/base/internal/atomics.h"
+#include "iree/base/internal/dynamic_library.h"
+#include "iree/base/internal/file_path.h"
+#include "iree/base/target_platform.h"
+#include "iree/base/tracing.h"
+
+#if defined(IREE_PLATFORM_ANDROID) || defined(IREE_PLATFORM_APPLE) || \
+ defined(IREE_PLATFORM_LINUX)
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+struct iree_dynamic_library_s {
+ iree_atomic_ref_count_t ref_count;
+ iree_allocator_t allocator;
+
+ // dlopen shared object handle.
+ void* handle;
+};
+
+// Allocate a new string from |allocator| returned in |out_file_path| containing
+// a path to a unique file on the filesystem.
+static iree_status_t iree_dynamic_library_make_temp_file_path(
+ const char* prefix, const char* extension, iree_allocator_t allocator,
+ char** out_file_path) {
+ // Query the 'TMPDIR' environment variable to allow users to override the
+ // path.
+ const char* tmpdir = getenv("TMPDIR");
+ if (!tmpdir) {
+#ifdef __ANDROID__
+ // Support running Android command-line programs both as regular shell user
+ // and as root. For the latter, TMPDIR is not defined by default.
+ tmpdir = "/data/local/tmp";
+#else
+ tmpdir = "/tmp";
+#endif // __ANDROID__
+ }
+
+ // Stamp in a unique file name (replacing XXXXXX in the string).
+ char temp_path[512];
+ if (snprintf(temp_path, sizeof(temp_path), "%s/iree_dylib_XXXXXX", tmpdir) >=
+ sizeof(temp_path)) {
+ // NOTE: we could dynamically allocate things, but didn't seem worth it.
+ return iree_make_status(
+ IREE_STATUS_INVALID_ARGUMENT,
+ "TMPDIR name too long (>%zu chars); keep it reasonable",
+ sizeof(temp_path));
+ }
+ int fd = mkstemp(temp_path);
+ if (fd < 0) {
+ return iree_make_status(iree_status_code_from_errno(errno),
+ "unable to mkstemp file");
+ }
+
+ // Allocate storage for the full file path and format it in.
+ int file_path_length =
+ snprintf(NULL, 0, "%s_%s.%s", temp_path, prefix, extension);
+ if (file_path_length < 0) {
+ return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
+ "unable to form temp path string");
+ }
+ IREE_RETURN_IF_ERROR(iree_allocator_malloc(
+ allocator, file_path_length + /*NUL=*/1, (void**)out_file_path));
+ snprintf(*out_file_path, file_path_length + /*NUL=*/1, "%s_%s.%s", temp_path,
+ prefix, extension);
+
+ // Canonicalize away any double path separators.
+ iree_file_path_canonicalize(*out_file_path, file_path_length);
+
+ return iree_ok_status();
+}
+
+// Creates a temp file and writes the |source_data| into it.
+// The file path is returned in |out_file_path|.
+static iree_status_t iree_dynamic_library_write_temp_file(
+ iree_const_byte_span_t source_data, const char* prefix,
+ const char* extension, iree_allocator_t allocator, char** out_file_path) {
+ IREE_TRACE_ZONE_BEGIN(z0);
+
+ // Reserve a temp file path we can write to.
+ IREE_RETURN_AND_END_ZONE_IF_ERROR(
+ z0, iree_dynamic_library_make_temp_file_path(prefix, extension, allocator,
+ out_file_path));
+
+ iree_status_t status = iree_ok_status();
+
+ // Open the file for writing.
+ FILE* file_handle = fopen(*out_file_path, "wb");
+ if (file_handle == NULL) {
+ status = iree_make_status(iree_status_code_from_errno(errno),
+ "unable to open file '%s'", *out_file_path);
+ }
+
+ // Write all file bytes.
+ if (iree_status_is_ok(status)) {
+ if (fwrite((char*)source_data.data, source_data.data_length, 1,
+ file_handle) != 1) {
+ status =
+ iree_make_status(iree_status_code_from_errno(errno),
+ "unable to write file span of %zu bytes to '%s'",
+ source_data.data_length, *out_file_path);
+ }
+ }
+
+ if (file_handle != NULL) {
+ fclose(file_handle);
+ file_handle = NULL;
+ }
+ if (!iree_status_is_ok(status)) {
+ iree_allocator_free(allocator, *out_file_path);
+ }
+ IREE_TRACE_ZONE_END(z0);
+ return status;
+}
+
+// Allocates an iree_dynamic_library_t with the given allocator.
+static iree_status_t iree_dynamic_library_create(
+ void* handle, iree_allocator_t allocator,
+ iree_dynamic_library_t** out_library) {
+ *out_library = NULL;
+
+ iree_dynamic_library_t* library = NULL;
+ IREE_RETURN_IF_ERROR(
+ iree_allocator_malloc(allocator, sizeof(*library), (void**)&library));
+ memset(library, 0, sizeof(*library));
+ iree_atomic_ref_count_init(&library->ref_count);
+ library->allocator = allocator;
+ library->handle = handle;
+
+ *out_library = library;
+ return iree_ok_status();
+}
+
+iree_status_t iree_dynamic_library_load_from_file(
+ const char* file_path, iree_dynamic_library_flags_t flags,
+ iree_allocator_t allocator, iree_dynamic_library_t** out_library) {
+ return iree_dynamic_library_load_from_files(1, &file_path, flags, allocator,
+ out_library);
+}
+
+iree_status_t iree_dynamic_library_load_from_files(
+ iree_host_size_t search_path_count, const char* const* search_paths,
+ iree_dynamic_library_flags_t flags, iree_allocator_t allocator,
+ iree_dynamic_library_t** out_library) {
+ IREE_TRACE_ZONE_BEGIN(z0);
+ IREE_ASSERT_ARGUMENT(out_library);
+ *out_library = NULL;
+
+ // Try to load the module from the set of search paths provided.
+ void* handle = NULL;
+ iree_host_size_t i = 0;
+ for (i = 0; i < search_path_count; ++i) {
+ handle = dlopen(search_paths[i], RTLD_LAZY | RTLD_LOCAL);
+ if (handle) break;
+ }
+ if (!handle) {
+ IREE_TRACE_ZONE_END(z0);
+ return iree_make_status(IREE_STATUS_NOT_FOUND,
+ "dynamic library not found on any search path");
+ }
+
+ iree_dynamic_library_t* library = NULL;
+ iree_status_t status =
+ iree_dynamic_library_create(handle, allocator, &library);
+
+ if (iree_status_is_ok(status)) {
+ *out_library = library;
+ } else {
+ dlclose(handle);
+ }
+ IREE_TRACE_ZONE_END(z0);
+ return status;
+}
+
+// TODO(#3845): use dlopen on an fd with either dlopen(/proc/self/fd/NN),
+// fdlopen, or android_dlopen_ext to avoid needing to write the file to disk.
+// Can fallback to memfd_create + dlopen where available, and fallback from
+// that to disk (maybe just windows/mac).
+iree_status_t iree_dynamic_library_load_from_memory(
+ iree_string_view_t identifier, iree_const_byte_span_t buffer,
+ iree_dynamic_library_flags_t flags, iree_allocator_t allocator,
+ iree_dynamic_library_t** out_library) {
+ IREE_TRACE_ZONE_BEGIN(z0);
+ IREE_ASSERT_ARGUMENT(out_library);
+ *out_library = NULL;
+
+ // Extract the library to a temp file.
+ char* temp_path = NULL;
+ IREE_RETURN_AND_END_ZONE_IF_ERROR(
+ z0, iree_dynamic_library_write_temp_file(buffer, "mem_", "so", allocator,
+ &temp_path));
+
+ // Load using the normal load from file routine.
+ iree_status_t status = iree_dynamic_library_load_from_file(
+ temp_path, flags, allocator, out_library);
+
+ // Unlink the temp file - it's still open by the loader but won't be
+ // accessible to anyone else and will be deleted once the library is
+ // unloaded.
+ remove(temp_path);
+ iree_allocator_free(allocator, temp_path);
+
+ IREE_TRACE_ZONE_END(z0);
+ return status;
+}
+
+static void iree_dynamic_library_delete(iree_dynamic_library_t* library) {
+ iree_allocator_t allocator = library->allocator;
+ IREE_TRACE_ZONE_BEGIN(z0);
+
+#if IREE_TRACING_FEATURES & IREE_TRACING_FEATURE_INSTRUMENTATION
+ // Leak the library when tracing, since the profiler may still be reading it.
+ // TODO(benvanik): move to an atexit handler instead, verify with ASAN/MSAN
+ // TODO(scotttodd): Make this compatible with testing:
+ // two test cases, one for each function in the same executable
+ // first test case passes, second fails to open the file (already open)
+#else
+ // Close the library first as it may be loaded from one of the temp files we
+ // are about to delete.
+ if (library->handle != NULL) {
+ dlclose(library->handle);
+ }
+#endif // IREE_TRACING_FEATURES & IREE_TRACING_FEATURE_INSTRUMENTATION
+
+ iree_allocator_free(allocator, library);
+
+ IREE_TRACE_ZONE_END(z0);
+}
+
+void iree_dynamic_library_retain(iree_dynamic_library_t* library) {
+ if (library) {
+ iree_atomic_ref_count_inc(&library->ref_count);
+ }
+}
+
+void iree_dynamic_library_release(iree_dynamic_library_t* library) {
+ if (library && iree_atomic_ref_count_dec(&library->ref_count) == 1) {
+ iree_dynamic_library_delete(library);
+ }
+}
+
+iree_status_t iree_dynamic_library_lookup_symbol(
+ iree_dynamic_library_t* library, const char* symbol_name, void** out_fn) {
+ IREE_ASSERT_ARGUMENT(library);
+ IREE_ASSERT_ARGUMENT(symbol_name);
+ IREE_ASSERT_ARGUMENT(out_fn);
+ *out_fn = NULL;
+ void* fn = dlsym(library->handle, symbol_name);
+ if (!fn) {
+ return iree_make_status(IREE_STATUS_NOT_FOUND,
+ "symbol '%s' not found in library", symbol_name);
+ }
+ *out_fn = fn;
+ return iree_ok_status();
+}
+
+iree_status_t iree_dynamic_library_attach_symbols_from_file(
+ iree_dynamic_library_t* library, const char* file_path) {
+ return iree_ok_status();
+}
+
+iree_status_t iree_dynamic_library_attach_symbols_from_memory(
+ iree_dynamic_library_t* library, iree_const_byte_span_t buffer) {
+ return iree_ok_status();
+}
+
+#endif // IREE_PLATFORM_*
diff --git a/iree/base/internal/dynamic_library_win32.c b/iree/base/internal/dynamic_library_win32.c
new file mode 100644
index 0000000..0f21772
--- /dev/null
+++ b/iree/base/internal/dynamic_library_win32.c
@@ -0,0 +1,425 @@
+// Copyright 2021 Google LLC
+//
+// 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
+//
+// https://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 <stdio.h>
+
+#include "iree/base/internal/atomics.h"
+#include "iree/base/internal/dynamic_library.h"
+#include "iree/base/internal/file_path.h"
+#include "iree/base/target_platform.h"
+#include "iree/base/threading.h"
+#include "iree/base/tracing.h"
+
+#if defined(IREE_PLATFORM_WINDOWS)
+
+// TODO(benvanik): support PDB overlays when tracy is not enabled; we'll
+// need to rearrange how the dbghelp lock is handled for that (probably moving
+// it here and having the tracy code redirect to this).
+#if defined(TRACY_ENABLE)
+#define IREE_HAVE_DYNAMIC_LIBRARY_PDB_SUPPORT 1
+#pragma warning(disable : 4091)
+#include <dbghelp.h>
+extern "C" void IREEDbgHelpLock();
+extern "C" void IREEDbgHelpUnlock();
+#endif // TRACY_ENABLE
+
+struct iree_dynamic_library_s {
+ iree_atomic_ref_count_t ref_count;
+ iree_allocator_t allocator;
+
+ // Base module name used as an identifier. When loaded from a file this must
+ // be the basename for dbghelp to be able to find symbols.
+ // Owned and allocated as part of the struct upon creation.
+ // Has NUL terminator for compatibility with Windows APIs.
+ char* identifier;
+
+ // File path of the loaded module, if loaded from one.
+ // Owned and allocated as part of the struct upon creation.
+ // Has NUL terminator for compatibility with Windows APIs.
+ char* module_path;
+
+ // Windows module handle.
+ HMODULE module;
+
+ // 0 or more file paths that were created as part of the loading of the
+ // library or attaching of symbols from memory.
+ //
+ // Each path string is allocated using the |allocator| and freed during
+ // library deletion.
+ iree_host_size_t temp_file_count;
+ char* temp_file_paths[2];
+};
+
+static iree_once_flag iree_dynamic_library_temp_path_flag_ =
+ IREE_ONCE_FLAG_INIT;
+static char iree_dynamic_library_temp_path_base_[MAX_PATH + 1];
+static void iree_dynamic_library_init_temp_paths(void) {
+ // Query the temp path from the OS. This can be overridden with the following
+ // environment variables: [TMP, TEMP, USERPROFILE].
+ //
+ // See:
+ // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha
+ char temp_path[MAX_PATH];
+ DWORD temp_path_length = GetTempPathA(IREE_ARRAYSIZE(temp_path), temp_path);
+
+ // Append the process ID to the path; this is like what _mktemp does but
+ // without all the hoops.
+ snprintf(iree_dynamic_library_temp_path_base_,
+ sizeof(iree_dynamic_library_temp_path_base_), "%s\\iree_dylib_%08X",
+ temp_path, GetCurrentProcessId());
+
+ // Canonicalize away any double path separators.
+ iree_file_path_canonicalize(iree_dynamic_library_temp_path_base_,
+ strlen(iree_dynamic_library_temp_path_base_));
+}
+
+// Allocate a new string from |allocator| returned in |out_file_path| containing
+// a path to a unique file on the filesystem.
+static iree_status_t iree_dynamic_library_make_temp_file_path(
+ const char* prefix, const char* extension, iree_allocator_t allocator,
+ char** out_file_path) {
+ // Ensure the root temp paths are queried/initialized.
+ iree_call_once(&iree_dynamic_library_temp_path_flag_,
+ iree_dynamic_library_init_temp_paths);
+
+ // Generate a per-file unique identifier only unique **within** the current
+ // process. We combine this with the _mktemp path that should be unique to the
+ // process itself.
+ static iree_atomic_int32_t next_unique_id = IREE_ATOMIC_VAR_INIT(0);
+ uint32_t unique_id = (uint32_t)iree_atomic_fetch_add_int32(
+ &next_unique_id, 1, iree_memory_order_seq_cst);
+
+ // Allocate storage for the full file path and format it in.
+ int file_path_length =
+ snprintf(NULL, 0, "%s_%s_%08X.%s", iree_dynamic_library_temp_path_base_,
+ prefix, unique_id, extension);
+ if (file_path_length < 0) {
+ return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
+ "unable to form temp path string");
+ }
+ IREE_RETURN_IF_ERROR(iree_allocator_malloc(
+ allocator, file_path_length + /*NUL=*/1, (void**)out_file_path));
+ snprintf(*out_file_path, file_path_length + /*NUL=*/1, "%s_%s_%08X.%s",
+ iree_dynamic_library_temp_path_base_, prefix, unique_id, extension);
+
+ return iree_ok_status();
+}
+
+// Creates a temp file and writes the |source_data| into it.
+// The file path is returned in |out_file_path|.
+static iree_status_t iree_dynamic_library_write_temp_file(
+ iree_const_byte_span_t source_data, const char* prefix,
+ const char* extension, iree_allocator_t allocator, char** out_file_path) {
+ IREE_TRACE_ZONE_BEGIN(z0);
+
+ // Reserve a temp file path we can write to.
+ IREE_RETURN_AND_END_ZONE_IF_ERROR(
+ z0, iree_dynamic_library_make_temp_file_path(prefix, extension, allocator,
+ out_file_path));
+
+ iree_status_t status = iree_ok_status();
+
+ // Open the file for writing.
+ HANDLE file_handle = CreateFileA(
+ /*lpFileName=*/*out_file_path, /*dwDesiredAccess=*/GENERIC_WRITE,
+ /*dwShareMode=*/FILE_SHARE_DELETE, /*lpSecurityAttributes=*/NULL,
+ /*dwCreationDisposition=*/CREATE_ALWAYS,
+ /*dwFlagsAndAttributes=*/FILE_ATTRIBUTE_TEMPORARY |
+ FILE_FLAG_DELETE_ON_CLOSE,
+ /*hTemplateFile=*/NULL);
+ if (file_handle == INVALID_HANDLE_VALUE) {
+ status = iree_make_status(iree_status_code_from_win32_error(GetLastError()),
+ "unable to open file '%s'", *out_file_path);
+ }
+
+ // Write all file bytes.
+ if (iree_status_is_ok(status)) {
+ if (WriteFile(file_handle, source_data.data, (DWORD)source_data.data_length,
+ NULL, NULL) == FALSE) {
+ status =
+ iree_make_status(iree_status_code_from_win32_error(GetLastError()),
+ "unable to write file span of %zu bytes to '%s'",
+ source_data.data_length, *out_file_path);
+ }
+ }
+
+ if (file_handle != NULL) {
+ CloseHandle(file_handle);
+ file_handle = NULL;
+ }
+ if (!iree_status_is_ok(status)) {
+ iree_allocator_free(allocator, *out_file_path);
+ }
+ IREE_TRACE_ZONE_END(z0);
+ return status;
+}
+
+// Allocates an iree_dynamic_library_t with the given allocator.
+static iree_status_t iree_dynamic_library_create(
+ iree_string_view_t identifier, iree_string_view_t module_path,
+ HMODULE module, iree_allocator_t allocator,
+ iree_dynamic_library_t** out_library) {
+ *out_library = NULL;
+
+ iree_dynamic_library_t* library = NULL;
+ iree_host_size_t total_size =
+ sizeof(*library) + (identifier.size + 1) + (module_path.size + 1);
+ IREE_RETURN_IF_ERROR(
+ iree_allocator_malloc(allocator, total_size, (void**)&library));
+ memset(library, 0, total_size);
+ iree_atomic_ref_count_init(&library->ref_count);
+ library->allocator = allocator;
+ library->module = module;
+
+ library->identifier = (char*)library + sizeof(*library);
+ memcpy(library->identifier, identifier.data, identifier.size);
+ library->identifier[identifier.size] = 0; // NUL
+
+ library->module_path = library->identifier + (identifier.size + 1);
+ memcpy(library->module_path, module_path.data, module_path.size);
+ library->module_path[module_path.size] = 0; // NUL
+
+ *out_library = library;
+ return iree_ok_status();
+}
+
+iree_status_t iree_dynamic_library_load_from_file(
+ const char* file_path, iree_dynamic_library_flags_t flags,
+ iree_allocator_t allocator, iree_dynamic_library_t** out_library) {
+ return iree_dynamic_library_load_from_files(1, &file_path, flags, allocator,
+ out_library);
+}
+
+iree_status_t iree_dynamic_library_load_from_files(
+ iree_host_size_t search_path_count, const char* const* search_paths,
+ iree_dynamic_library_flags_t flags, iree_allocator_t allocator,
+ iree_dynamic_library_t** out_library) {
+ IREE_TRACE_ZONE_BEGIN(z0);
+ IREE_ASSERT_ARGUMENT(out_library);
+ *out_library = NULL;
+
+ // Try to load the module from the set of search paths provided.
+ HMODULE module = NULL;
+ iree_host_size_t i = 0;
+ for (i = 0; i < search_path_count; ++i) {
+ module = LoadLibraryA(search_paths[i]);
+ if (module) break;
+ }
+ if (!module) {
+ IREE_TRACE_ZONE_END(z0);
+ return iree_make_status(IREE_STATUS_NOT_FOUND,
+ "dynamic library not found on any search path");
+ }
+
+ iree_string_view_t file_path = iree_make_cstring_view(search_paths[i]);
+ iree_string_view_t identifier = iree_file_path_basename(file_path);
+
+ iree_dynamic_library_t* library = NULL;
+ iree_status_t status = iree_dynamic_library_create(
+ identifier, file_path, module, allocator, &library);
+
+ if (iree_status_is_ok(status)) {
+ *out_library = library;
+ } else {
+ FreeLibrary(module);
+ }
+ IREE_TRACE_ZONE_END(z0);
+ return status;
+}
+
+iree_status_t iree_dynamic_library_load_from_memory(
+ iree_string_view_t identifier, iree_const_byte_span_t buffer,
+ iree_dynamic_library_flags_t flags, iree_allocator_t allocator,
+ iree_dynamic_library_t** out_library) {
+ IREE_TRACE_ZONE_BEGIN(z0);
+ IREE_ASSERT_ARGUMENT(out_library);
+ *out_library = NULL;
+
+ // Extract the library to a temp file.
+ char* temp_path = NULL;
+ iree_status_t status = iree_dynamic_library_write_temp_file(
+ buffer, "mem_", "dll", allocator, &temp_path);
+
+ if (iree_status_is_ok(status)) {
+ // Load using the normal load from file routine.
+ status = iree_dynamic_library_load_from_file(temp_path, flags, allocator,
+ out_library);
+ }
+ if (iree_status_is_ok(status)) {
+ // Associate the temp path to the library; the temp_path string and the
+ // backing file will be deleted when the library is closed.
+ iree_dynamic_library_t* library = *out_library;
+ library->temp_file_paths[library->temp_file_count++] = temp_path;
+ } else {
+ iree_allocator_free(allocator, temp_path);
+ }
+
+ IREE_TRACE_ZONE_END(z0);
+ return status;
+}
+
+static void iree_dynamic_library_delete(iree_dynamic_library_t* library) {
+ iree_allocator_t allocator = library->allocator;
+ IREE_TRACE_ZONE_BEGIN(z0);
+
+#if IREE_TRACING_FEATURES & IREE_TRACING_FEATURE_INSTRUMENTATION
+ // Leak the library when tracing, since the profiler may still be reading it.
+ // TODO(benvanik): move to an atexit handler instead, verify with ASAN/MSAN
+ // TODO(scotttodd): Make this compatible with testing:
+ // two test cases, one for each function in the same executable
+ // first test case passes, second fails to open the file (already open)
+#else
+ // Close the library first as it may be loaded from one of the temp files we
+ // are about to delete.
+ if (library->module != NULL) {
+ FreeLibrary(library->module);
+ }
+#endif // IREE_TRACING_FEATURES & IREE_TRACING_FEATURE_INSTRUMENTATION
+
+ // Cleanup all temp files.
+ for (iree_host_size_t i = 0; i < library->temp_file_count; ++i) {
+ char* file_path = library->temp_file_paths[i];
+ DeleteFileA(file_path);
+ iree_allocator_free(allocator, file_path);
+ }
+
+ iree_allocator_free(allocator, library);
+
+ IREE_TRACE_ZONE_END(z0);
+}
+
+void iree_dynamic_library_retain(iree_dynamic_library_t* library) {
+ if (library) {
+ iree_atomic_ref_count_inc(&library->ref_count);
+ }
+}
+
+void iree_dynamic_library_release(iree_dynamic_library_t* library) {
+ if (library && iree_atomic_ref_count_dec(&library->ref_count) == 1) {
+ iree_dynamic_library_delete(library);
+ }
+}
+
+iree_status_t iree_dynamic_library_lookup_symbol(
+ iree_dynamic_library_t* library, const char* symbol_name, void** out_fn) {
+ IREE_ASSERT_ARGUMENT(library);
+ IREE_ASSERT_ARGUMENT(symbol_name);
+ IREE_ASSERT_ARGUMENT(out_fn);
+ *out_fn = NULL;
+ void* fn = GetProcAddress(library->module, symbol_name);
+ if (!fn) {
+ return iree_make_status(IREE_STATUS_NOT_FOUND,
+ "symbol '%s' not found in library", symbol_name);
+ }
+ *out_fn = fn;
+ return iree_ok_status();
+}
+
+#if defined(IREE_HAVE_DYNAMIC_LIBRARY_PDB_SUPPORT)
+
+typedef struct {
+ const char* module_path;
+ DWORD64 module_base;
+ ULONG module_size;
+} ModuleEnumCallbackState;
+
+static BOOL EnumLoadedModulesCallback(PCSTR ModuleName, DWORD64 ModuleBase,
+ ULONG ModuleSize, PVOID UserContext) {
+ ModuleEnumCallbackState* state = (ModuleEnumCallbackState*)UserContext;
+ if (strcmp(ModuleName, state->module_path) != 0) {
+ return TRUE; // not a match; continue
+ }
+ state->module_base = ModuleBase;
+ state->module_size = ModuleSize;
+ return FALSE; // match found; stop enumeration
+}
+
+iree_status_t iree_dynamic_library_attach_symbols_from_file(
+ iree_dynamic_library_t* library, const char* file_path) {
+ IREE_ASSERT_ARGUMENT(library);
+ IREE_TRACE_ZONE_BEGIN(z0);
+
+ IREEDbgHelpLock();
+
+ // Useful for debugging this logic; will print search paths and results:
+ // SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_DEBUG);
+
+ // Enumerates all loaded modules in the process to extract the module
+ // base/size parameters we need to overlay the PDB. There's other ways to
+ // get this (such as registering a LdrDllNotification callback and snooping
+ // the values during LoadLibrary or using CreateToolhelp32Snapshot), however
+ // EnumerateLoadedModules is in dbghelp which we are using anyway.
+ ModuleEnumCallbackState state;
+ memset(&state, 0, sizeof(state));
+ state.module_path = library->module_path;
+ EnumerateLoadedModules64(GetCurrentProcess(), EnumLoadedModulesCallback,
+ &state);
+
+ // Load the PDB file and overlay it onto the already-loaded module at the
+ // address range it got loaded into.
+ if (state.module_base != 0) {
+ SymLoadModuleEx(GetCurrentProcess(), NULL, file_path,
+ library->identifier.data, state.module_base,
+ state.module_size, NULL, 0);
+ }
+
+ IREEDbgHelpUnlock();
+
+ IREE_TRACE_ZONE_END(z0);
+ return iree_ok_status();
+}
+
+iree_status_t iree_dynamic_library_attach_symbols_from_memory(
+ iree_dynamic_library_t* library, iree_const_byte_span_t buffer) {
+ IREE_ASSERT_ARGUMENT(library);
+ IREE_TRACE_ZONE_BEGIN(z0);
+
+ if (library->temp_file_count + 1 >=
+ IREE_ARRAYSIZE(library->temp_file_paths)) {
+ return iree_make_status(IREE_STATUS_RESOURCE_EXHAUSTED,
+ "too many temp files attached");
+ }
+
+ // Extract the library to a temp file.
+ char* temp_path = NULL;
+ iree_status_t status = iree_dynamic_library_write_temp_file(
+ buffer, "mem_", "pdb", library->allocator, &temp_path);
+ if (iree_status_is_ok(status)) {
+ // Associate the temp path to the library; the temp_path string and the
+ // backing file will be deleted when the library is closed.
+ library->temp_file_paths[library->temp_file_count++] = temp_path;
+
+ // Attempt to attach the extracted temp file to the module.
+ status = iree_dynamic_library_attach_symbols_from_file(library, temp_path);
+ }
+
+ IREE_TRACE_ZONE_END(z0);
+ return status;
+}
+
+#else
+
+iree_status_t iree_dynamic_library_attach_symbols_from_file(
+ iree_dynamic_library_t* library, const char* file_path) {
+ return iree_ok_status();
+}
+
+iree_status_t iree_dynamic_library_attach_symbols_from_memory(
+ iree_dynamic_library_t* library, iree_const_byte_span_t buffer) {
+ return iree_ok_status();
+}
+
+#endif // IREE_HAVE_DYNAMIC_LIBRARY_PDB_SUPPORT
+
+#endif // IREE_PLATFORM_WINDOWS
diff --git a/iree/base/internal/file_handle_win32.cc b/iree/base/internal/file_handle_win32.cc
deleted file mode 100644
index 06f0b77..0000000
--- a/iree/base/internal/file_handle_win32.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2019 Google LLC
-//
-// 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
-//
-// https://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 "iree/base/internal/file_handle_win32.h"
-
-#include "absl/memory/memory.h"
-#include "absl/strings/str_replace.h"
-#include "iree/base/target_platform.h"
-
-#if defined(IREE_PLATFORM_WINDOWS)
-
-namespace iree {
-
-static void CanonicalizePath(std::string* path) {
- absl::StrReplaceAll({{"/", "\\"}}, path);
-}
-
-// static
-Status FileHandle::OpenRead(std::string path, DWORD file_flags,
- std::unique_ptr<FileHandle>* out_handle) {
- out_handle->reset();
- CanonicalizePath(&path);
- HANDLE handle = ::CreateFileA(
- /*lpFileName=*/path.c_str(), /*dwDesiredAccess=*/GENERIC_READ,
- /*dwShareMode=*/FILE_SHARE_READ, /*lpSecurityAttributes=*/nullptr,
- /*dwCreationDisposition=*/OPEN_EXISTING,
- /*dwFlagsAndAttributes=*/FILE_ATTRIBUTE_NORMAL | file_flags,
- /*hTemplateFile=*/nullptr);
- if (handle == INVALID_HANDLE_VALUE) {
- return iree_make_status(iree_status_code_from_win32_error(GetLastError()),
- "unable to open file '%s'", path.c_str());
- }
-
- BY_HANDLE_FILE_INFORMATION file_info;
- if (::GetFileInformationByHandle(handle, &file_info) == FALSE) {
- return iree_make_status(iree_status_code_from_win32_error(GetLastError()),
- "unable to query file info for %s", path.c_str());
- }
-
- uint64_t file_size = (static_cast<uint64_t>(file_info.nFileSizeHigh) << 32) |
- file_info.nFileSizeLow;
- *out_handle = absl::make_unique<FileHandle>(handle, file_size);
- return OkStatus();
-}
-
-// static
-Status FileHandle::OpenWrite(std::string path, DWORD file_flags,
- std::unique_ptr<FileHandle>* out_handle) {
- out_handle->reset();
- CanonicalizePath(&path);
- HANDLE handle = ::CreateFileA(
- /*lpFileName=*/path.c_str(), /*dwDesiredAccess=*/GENERIC_WRITE,
- /*dwShareMode=*/FILE_SHARE_DELETE, /*lpSecurityAttributes=*/nullptr,
- /*dwCreationDisposition=*/CREATE_ALWAYS,
- /*dwFlagsAndAttributes=*/FILE_ATTRIBUTE_NORMAL | file_flags,
- /*hTemplateFile=*/nullptr);
- if (handle == INVALID_HANDLE_VALUE) {
- return iree_make_status(iree_status_code_from_win32_error(GetLastError()),
- "unable to open file '%s'", path.c_str());
- }
- *out_handle = absl::make_unique<FileHandle>(handle, 0);
- return OkStatus();
-}
-
-FileHandle::~FileHandle() { ::CloseHandle(handle_); }
-
-} // namespace iree
-
-#endif // IREE_PLATFORM_WINDOWS
diff --git a/iree/base/internal/file_handle_win32.h b/iree/base/internal/file_handle_win32.h
deleted file mode 100644
index 3532b59..0000000
--- a/iree/base/internal/file_handle_win32.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright 2019 Google LLC
-//
-// 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
-//
-// https://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 IREE_BASE_INTERNAL_FILE_HANDLE_WIN32_H_
-#define IREE_BASE_INTERNAL_FILE_HANDLE_WIN32_H_
-
-#include <memory>
-#include <string>
-
-#include "absl/memory/memory.h"
-#include "absl/strings/string_view.h"
-#include "iree/base/status.h"
-#include "iree/base/target_platform.h"
-
-#if defined(IREE_PLATFORM_WINDOWS)
-
-namespace iree {
-
-class FileHandle {
- public:
- static Status OpenRead(std::string path, DWORD file_flags,
- std::unique_ptr<FileHandle>* out_handle);
- static Status OpenWrite(std::string path, DWORD file_flags,
- std::unique_ptr<FileHandle>* out_handle);
-
- FileHandle(HANDLE handle, size_t size) : handle_(handle), size_(size) {}
- ~FileHandle();
-
- absl::string_view path() const { return path_; }
- HANDLE handle() const { return handle_; }
- size_t size() const { return size_; }
-
- private:
- FileHandle(const FileHandle&) = delete;
- FileHandle& operator=(const FileHandle&) = delete;
-
- std::string path_;
- HANDLE handle_;
- size_t size_;
-};
-
-} // namespace iree
-
-#endif // IREE_PLATFORM_WINDOWS
-
-#endif // IREE_BASE_INTERNAL_FILE_HANDLE_WIN32_H_
diff --git a/iree/base/internal/file_io.cc b/iree/base/internal/file_io.cc
new file mode 100644
index 0000000..4190e0d
--- /dev/null
+++ b/iree/base/internal/file_io.cc
@@ -0,0 +1,105 @@
+// Copyright 2019 Google LLC
+//
+// 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
+//
+// https://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 "iree/base/internal/file_io.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "iree/base/target_platform.h"
+#include "iree/base/tracing.h"
+
+namespace iree {
+namespace file_io {
+
+iree_status_t FileExists(const char* path) {
+ IREE_TRACE_ZONE_BEGIN(z0);
+ struct stat stat_buf;
+ iree_status_t status =
+ stat(path, &stat_buf) == 0
+ ? iree_ok_status()
+ : iree_make_status(IREE_STATUS_NOT_FOUND, "'%s'", path);
+ IREE_TRACE_ZONE_END(z0);
+ return status;
+}
+
+iree_status_t GetFileContents(const char* path, std::string* out_contents) {
+ IREE_TRACE_ZONE_BEGIN(z0);
+ *out_contents = std::string();
+ FILE* file = fopen(path, "r");
+ if (file == NULL) {
+ IREE_TRACE_ZONE_END(z0);
+ return iree_make_status(iree_status_code_from_errno(errno),
+ "failed to open file '%s'", path);
+ }
+ iree_status_t status = iree_ok_status();
+ if (fseek(file, 0, SEEK_END) == -1) {
+ status = iree_make_status(iree_status_code_from_errno(errno), "seek (end)");
+ }
+ size_t file_size = 0;
+ if (iree_status_is_ok(status)) {
+ file_size = ftell(file);
+ if (file_size == -1L) {
+ status =
+ iree_make_status(iree_status_code_from_errno(errno), "size query");
+ }
+ }
+ if (iree_status_is_ok(status)) {
+ if (fseek(file, 0, SEEK_SET) == -1) {
+ status =
+ iree_make_status(iree_status_code_from_errno(errno), "seek (beg)");
+ }
+ }
+ std::string contents;
+ if (iree_status_is_ok(status)) {
+ contents.resize(file_size);
+ if (fread((char*)contents.data(), file_size, 1, file) != 1) {
+ status =
+ iree_make_status(iree_status_code_from_errno(errno),
+ "unable to read entire file contents of '%s'", path);
+ }
+ }
+ if (iree_status_is_ok(status)) {
+ *out_contents = std::move(contents);
+ }
+ fclose(file);
+ IREE_TRACE_ZONE_END(z0);
+ return status;
+}
+
+iree_status_t SetFileContents(const char* path,
+ iree_const_byte_span_t content) {
+ IREE_TRACE_ZONE_BEGIN(z0);
+ FILE* file = fopen(path, "wb");
+ if (file == NULL) {
+ IREE_TRACE_ZONE_END(z0);
+ return iree_make_status(iree_status_code_from_errno(errno),
+ "failed to open file '%s'", path);
+ }
+ int ret = fwrite((char*)content.data, content.data_length, 1, file);
+ iree_status_t status = iree_ok_status();
+ if (ret != 1) {
+ status =
+ iree_make_status(IREE_STATUS_DATA_LOSS,
+ "unable to write entire file contents of '%s'", path);
+ }
+ fclose(file);
+ IREE_TRACE_ZONE_END(z0);
+ return status;
+}
+
+} // namespace file_io
+} // namespace iree
diff --git a/iree/base/internal/file_io.h b/iree/base/internal/file_io.h
index 00d53df..144204c 100644
--- a/iree/base/internal/file_io.h
+++ b/iree/base/internal/file_io.h
@@ -17,8 +17,7 @@
#include <string>
-#include "absl/strings/string_view.h"
-#include "iree/base/status.h"
+#include "iree/base/api.h"
namespace iree {
namespace file_io {
@@ -27,33 +26,13 @@
//
// Returns an OK status if the file definitely exists.
// Errors can include PermissionDeniedError, NotFoundError, etc.
-Status FileExists(const std::string& path);
+iree_status_t FileExists(const char* path);
// Synchronously reads a file's contents into a string.
-Status GetFileContents(const std::string& path, std::string* out_contents);
+iree_status_t GetFileContents(const char* path, std::string* out_contents);
// Synchronously writes a string into a file, overwriting its contents.
-Status SetFileContents(const std::string& path, absl::string_view content);
-
-// Deletes the file at the provided path.
-Status DeleteFile(const std::string& path);
-
-// Moves a file from 'source_path' to 'destination_path'.
-//
-// This may simply rename the file, but may fall back to a full copy and delete
-// of the original if renaming is not possible (for example when moving between
-// physical storage locations).
-Status MoveFile(const std::string& source_path,
- const std::string& destination_path);
-
-// Gets a platform and environment-dependent path for temporary files.
-std::string GetTempPath();
-
-// TODO(#3845): remove this when dylibs no longer need temp files.
-// Gets a temporary file name and returns its absolute path.
-// The particular path chosen is platform and environment-dependent.
-// Unique characters will be automatically inserted after |base_name|.
-Status GetTempFile(absl::string_view base_name, std::string* out_path);
+iree_status_t SetFileContents(const char* path, iree_const_byte_span_t content);
} // namespace file_io
} // namespace iree
diff --git a/iree/base/internal/file_io_posix.cc b/iree/base/internal/file_io_posix.cc
deleted file mode 100644
index 81a04ce..0000000
--- a/iree/base/internal/file_io_posix.cc
+++ /dev/null
@@ -1,161 +0,0 @@
-// Copyright 2019 Google LLC
-//
-// 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
-//
-// https://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 "iree/base/target_platform.h"
-
-#if defined(IREE_PLATFORM_ANDROID) || defined(IREE_PLATFORM_APPLE) || \
- defined(IREE_PLATFORM_LINUX)
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cstdio>
-#include <cstdlib>
-
-#include "absl/strings/str_cat.h"
-#include "iree/base/internal/file_io.h"
-#include "iree/base/status.h"
-#include "iree/base/tracing.h"
-
-namespace iree {
-namespace file_io {
-
-Status FileExists(const std::string& path) {
- IREE_TRACE_SCOPE0("file_io::FileExists");
- struct stat stat_buf;
- return stat(path.c_str(), &stat_buf) == 0
- ? iree_ok_status()
- : iree_make_status(IREE_STATUS_NOT_FOUND, "'%s'", path.c_str());
-}
-
-Status GetFileContents(const std::string& path, std::string* out_contents) {
- IREE_TRACE_SCOPE0("file_io::GetFileContents");
- *out_contents = std::string();
- std::unique_ptr<FILE, void (*)(FILE*)> file = {std::fopen(path.c_str(), "r"),
- +[](FILE* file) {
- if (file) fclose(file);
- }};
- if (file == nullptr) {
- return iree_make_status(iree_status_code_from_errno(errno),
- "failed to open file '%s'", path.c_str());
- }
- if (std::fseek(file.get(), 0, SEEK_END) == -1) {
- return iree_make_status(iree_status_code_from_errno(errno), "seek (end)");
- }
- size_t file_size = std::ftell(file.get());
- if (file_size == -1L) {
- return iree_make_status(iree_status_code_from_errno(errno), "size query");
- }
- if (std::fseek(file.get(), 0, SEEK_SET) == -1) {
- return iree_make_status(iree_status_code_from_errno(errno), "seek (beg)");
- }
- std::string contents;
- contents.resize(file_size);
- if (std::fread(const_cast<char*>(contents.data()), file_size, 1,
- file.get()) != 1) {
- return iree_make_status(IREE_STATUS_UNAVAILABLE,
- "unable to read entire file contents of '%.*s'",
- (int)path.size(), path.data());
- }
- *out_contents = std::move(contents);
- return OkStatus();
-}
-
-Status SetFileContents(const std::string& path, absl::string_view content) {
- IREE_TRACE_SCOPE0("file_io::SetFileContents");
- std::unique_ptr<FILE, void (*)(FILE*)> file = {std::fopen(path.c_str(), "wb"),
- +[](FILE* file) {
- if (file) fclose(file);
- }};
- if (file == nullptr) {
- return iree_make_status(iree_status_code_from_errno(errno),
- "failed to open file '%s'", path.c_str());
- }
- if (std::fwrite(const_cast<char*>(content.data()), content.size(), 1,
- file.get()) != 1) {
- return iree_make_status(IREE_STATUS_UNAVAILABLE,
- "unable to write entire file contents of '%.*s'",
- (int)path.size(), path.data());
- }
- return OkStatus();
-}
-
-Status DeleteFile(const std::string& path) {
- IREE_TRACE_SCOPE0("file_io::DeleteFile");
- if (::remove(path.c_str()) == -1) {
- return iree_make_status(iree_status_code_from_errno(errno),
- "failed to delete file '%s'", path.c_str());
- }
- return OkStatus();
-}
-
-Status MoveFile(const std::string& source_path,
- const std::string& destination_path) {
- IREE_TRACE_SCOPE0("file_io::MoveFile");
- if (::rename(source_path.c_str(), destination_path.c_str()) == -1) {
- return iree_make_status(iree_status_code_from_errno(errno),
- "failed to rename file '%s' to '%s'",
- source_path.c_str(), destination_path.c_str());
- }
- return OkStatus();
-}
-
-std::string GetTempPath() {
- IREE_TRACE_SCOPE0("file_io::GetTempPath");
-
- // TEST_TMPDIR will point to a writeable temp path when running bazel tests.
- char* test_tmpdir = getenv("TEST_TMPDIR");
- if (test_tmpdir) {
- return test_tmpdir;
- }
-
- char* tmpdir = getenv("TMPDIR");
- if (tmpdir) {
- return tmpdir;
- }
-
-#ifdef __ANDROID__
- // Support running Android command-line programs both as regular shell user
- // and as root. For the latter, TMPDIR is not defined by default.
- return "/data/local/tmp";
-#else
- return "/tmp";
-#endif
-}
-
-// TODO(#3845): remove this when dylibs no longer need temp files.
-Status GetTempFile(absl::string_view base_name, std::string* out_path) {
- IREE_TRACE_SCOPE0("file_io::GetTempFile");
- *out_path = std::string();
-
- std::string temp_path = GetTempPath();
- std::string template_path =
- temp_path + "/" + std::string(base_name) + "XXXXXX";
-
- if (::mkstemp(&template_path[0]) != -1) {
- // Should have been modified by mkstemp.
- *out_path = std::move(template_path);
- return OkStatus();
- } else {
- return iree_make_status(iree_status_code_from_errno(errno),
- "failed to create temp file with template '%s'",
- template_path.c_str());
- }
-}
-
-} // namespace file_io
-} // namespace iree
-
-#endif // IREE_PLATFORM_*
diff --git a/iree/base/internal/file_io_test.cc b/iree/base/internal/file_io_test.cc
index 37dc1a1..e628fa9 100644
--- a/iree/base/internal/file_io_test.cc
+++ b/iree/base/internal/file_io_test.cc
@@ -14,10 +14,6 @@
#include "iree/base/internal/file_io.h"
-#include "absl/strings/str_cat.h"
-#include "absl/strings/string_view.h"
-#include "iree/base/logging.h"
-#include "iree/base/status.h"
#include "iree/testing/gtest.h"
#include "iree/testing/status_matchers.h"
@@ -27,82 +23,36 @@
using ::iree::testing::status::StatusIs;
-std::string GetUniquePath(absl::string_view unique_name) {
+std::string GetUniquePath(const char* unique_name) {
char* test_tmpdir = getenv("TEST_TMPDIR");
- IREE_CHECK(test_tmpdir) << "TEST_TMPDIR not defined";
- return test_tmpdir + std::string("/") + std::string(unique_name) +
- "_test.txt";
+ if (!test_tmpdir) {
+ test_tmpdir = getenv("TMPDIR");
+ }
+ if (!test_tmpdir) {
+ test_tmpdir = getenv("TEMP");
+ }
+ IREE_CHECK(test_tmpdir) << "TEST_TMPDIR/TMPDIR/TEMP not defined";
+ return test_tmpdir + std::string("/iree_test_") + unique_name;
}
-std::string GetUniqueContents(absl::string_view unique_name) {
- return absl::StrCat("Test with name ", unique_name, "\n");
+std::string GetUniqueContents(const char* unique_name) {
+ return std::string("Test with name ") + unique_name + "\n";
}
TEST(FileIo, GetSetContents) {
- std::string unique_name = "GetSetContents";
- auto path = GetUniquePath(unique_name);
- ASSERT_THAT(FileExists(path), StatusIs(StatusCode::kNotFound));
- auto to_write = GetUniqueContents(unique_name);
+ constexpr const char* kUniqueName = "GetSetContents";
+ auto path = GetUniquePath(kUniqueName);
+ ASSERT_THAT(FileExists(path.c_str()), StatusIs(StatusCode::kNotFound));
+ auto to_write = GetUniqueContents(kUniqueName);
- IREE_ASSERT_OK(SetFileContents(path, to_write));
+ IREE_ASSERT_OK(SetFileContents(
+ path.c_str(),
+ iree_make_const_byte_span(to_write.data(), to_write.size())));
std::string read;
- IREE_ASSERT_OK(GetFileContents(path, &read));
+ IREE_ASSERT_OK(GetFileContents(path.c_str(), &read));
EXPECT_EQ(to_write, read);
}
-TEST(FileIo, SetDeleteExists) {
- std::string unique_name = "SetDeleteExists";
- auto path = GetUniquePath(unique_name);
- ASSERT_THAT(FileExists(path), StatusIs(StatusCode::kNotFound));
- auto to_write = GetUniqueContents(unique_name);
-
- IREE_ASSERT_OK(SetFileContents(path, to_write));
- IREE_ASSERT_OK(FileExists(path));
- IREE_ASSERT_OK(DeleteFile(path));
- EXPECT_THAT(FileExists(path), StatusIs(StatusCode::kNotFound));
-}
-
-TEST(FileIo, MoveFile) {
- auto from_path = GetUniquePath("MoveFileFrom");
- auto to_path = GetUniquePath("MoveFileTo");
- ASSERT_THAT(FileExists(from_path), StatusIs(StatusCode::kNotFound));
- ASSERT_THAT(FileExists(to_path), StatusIs(StatusCode::kNotFound));
- auto to_write = GetUniqueContents("MoveFile");
-
- IREE_ASSERT_OK(SetFileContents(from_path, to_write));
- IREE_ASSERT_OK(FileExists(from_path));
- IREE_EXPECT_OK(MoveFile(from_path, to_path));
- EXPECT_THAT(FileExists(from_path), StatusIs(StatusCode::kNotFound));
- IREE_EXPECT_OK(FileExists(to_path));
- std::string read;
- IREE_ASSERT_OK(GetFileContents(to_path, &read));
- EXPECT_EQ(to_write, read);
-}
-
-TEST(FileIo, GetTempPath) {
- auto temp_path = GetTempPath();
- EXPECT_NE("", temp_path);
-}
-
-TEST(FileIo, GetTempFile) {
- std::string path1;
- IREE_ASSERT_OK(GetTempFile("foo", &path1));
- EXPECT_TRUE(path1.find("foo") != std::string::npos);
-
- // Should be able to set file contents at the given path.
- // Note that the file may or may not exist, depending on the platform, and
- // a file must be created at the path before calling GetTempFile again, or
- // else the same path may be returned.
- auto to_write = GetUniqueContents("GetTempFile");
- IREE_ASSERT_OK(SetFileContents(path1, to_write));
-
- // Create another temp file with the same base name, check for a unique path.
- std::string path2;
- IREE_ASSERT_OK(GetTempFile("foo", &path2));
- EXPECT_TRUE(path2.find("foo") != std::string::npos);
- EXPECT_NE(path1, path2);
-}
-
} // namespace
} // namespace file_io
} // namespace iree
diff --git a/iree/base/internal/file_io_win32.cc b/iree/base/internal/file_io_win32.cc
deleted file mode 100644
index 2a7cc7b..0000000
--- a/iree/base/internal/file_io_win32.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-// Copyright 2019 Google LLC
-//
-// 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
-//
-// https://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 "iree/base/target_platform.h"
-
-#if defined(IREE_PLATFORM_WINDOWS)
-
-#include <io.h>
-
-#include <atomic>
-
-#include "absl/memory/memory.h"
-#include "absl/strings/str_cat.h"
-#include "iree/base/internal/file_handle_win32.h"
-#include "iree/base/internal/file_io.h"
-#include "iree/base/target_platform.h"
-#include "iree/base/tracing.h"
-
-namespace iree {
-namespace file_io {
-
-Status FileExists(const std::string& path) {
- IREE_TRACE_SCOPE0("file_io::FileExists");
- DWORD attrs = ::GetFileAttributesA(path.c_str());
- if (attrs == INVALID_FILE_ATTRIBUTES) {
- return iree_make_status(iree_status_code_from_win32_error(GetLastError()),
- "unable to find/access file: %s", path.c_str());
- }
- return OkStatus();
-}
-
-Status GetFileContents(const std::string& path, std::string* out_contents) {
- IREE_TRACE_SCOPE0("file_io::GetFileContents");
- *out_contents = std::string();
- std::unique_ptr<FileHandle> file;
- IREE_RETURN_IF_ERROR(
- FileHandle::OpenRead(std::move(path), FILE_FLAG_SEQUENTIAL_SCAN, &file));
- std::string contents;
- contents.resize(file->size());
- DWORD bytes_read = 0;
- if (::ReadFile(file->handle(), const_cast<char*>(contents.data()),
- static_cast<DWORD>(contents.size()), &bytes_read,
- nullptr) == FALSE) {
- return iree_make_status(iree_status_code_from_win32_error(GetLastError()),
- "unable to read file span of %zu bytes from '%s'",
- contents.size(), path.c_str());
- } else if (bytes_read != file->size()) {
- return iree_make_status(
- IREE_STATUS_RESOURCE_EXHAUSTED,
- "unable to read all %zu bytes from '%.*s' (got %zu)", file->size(),
- (int)path.size(), path.data(), bytes_read);
- }
- *out_contents = contents;
- return OkStatus();
-}
-
-Status SetFileContents(const std::string& path, absl::string_view content) {
- IREE_TRACE_SCOPE0("file_io::SetFileContents");
- std::unique_ptr<FileHandle> file;
- IREE_RETURN_IF_ERROR(FileHandle::OpenWrite(std::move(path), 0, &file));
- if (::WriteFile(file->handle(), content.data(),
- static_cast<DWORD>(content.size()), NULL, NULL) == FALSE) {
- return iree_make_status(iree_status_code_from_win32_error(GetLastError()),
- "unable to write file span of %zu bytes to '%s'",
- content.size(), path.c_str());
- }
- return OkStatus();
-}
-
-Status DeleteFile(const std::string& path) {
- IREE_TRACE_SCOPE0("file_io::DeleteFile");
- if (::DeleteFileA(path.c_str()) == FALSE) {
- return iree_make_status(iree_status_code_from_win32_error(GetLastError()),
- "unable to delete/access file: %s", path.c_str());
- }
- return OkStatus();
-}
-
-Status MoveFile(const std::string& source_path,
- const std::string& destination_path) {
- IREE_TRACE_SCOPE0("file_io::MoveFile");
- if (::MoveFileA(source_path.c_str(), destination_path.c_str()) == FALSE) {
- return iree_make_status(iree_status_code_from_win32_error(GetLastError()),
- "unable to move file '%s' to '%s'",
- source_path.c_str(), destination_path.c_str());
- }
- return OkStatus();
-}
-
-std::string GetTempPath() {
- IREE_TRACE_SCOPE0("file_io::GetTempPath");
-
- // TEST_TMPDIR will point to a writeable temp path when running bazel tests.
- char* test_tmpdir = getenv("TEST_TMPDIR");
- if (test_tmpdir) {
- return test_tmpdir;
- }
-
- std::string temp_path(64, '\0');
- for (bool retry_query = true; retry_query;) {
- DWORD required_length =
- ::GetTempPathA(static_cast<DWORD>(temp_path.size()), &temp_path[0]);
- retry_query = required_length > temp_path.size();
- temp_path.resize(required_length);
- }
- return temp_path;
-}
-
-// TODO(#3845): remove this when dylibs no longer need temp files.
-Status GetTempFile(absl::string_view base_name, std::string* out_path) {
- IREE_TRACE_SCOPE0("file_io::GetTempFile");
- *out_path = std::string();
-
- std::string temp_path = GetTempPath();
- std::string template_path =
- temp_path + std::string("\\") + std::string(base_name) + "XXXXXX";
-
- if (::_mktemp(&template_path[0]) != nullptr) {
- // Should have been modified by _mktemp.
- static std::atomic<int> next_id{0};
- template_path += std::to_string(next_id++);
- *out_path = std::move(template_path);
- return OkStatus();
- } else {
- return iree_make_status(iree_status_code_from_win32_error(GetLastError()),
- "unable to create temp file with template '%s'",
- template_path.c_str());
- }
-}
-
-} // namespace file_io
-} // namespace iree
-
-#endif // IREE_PLATFORM_WINDOWS
diff --git a/iree/base/testing/BUILD b/iree/base/testing/BUILD
index 9a897f1..299a3d1 100644
--- a/iree/base/testing/BUILD
+++ b/iree/base/testing/BUILD
@@ -43,8 +43,7 @@
deps = [
":dynamic_library_test_library",
"//iree/base:core_headers",
- "//iree/base:dynamic_library",
- "//iree/base:status",
+ "//iree/base/internal:dynamic_library",
"//iree/base/internal:file_io",
"//iree/testing:gtest",
"//iree/testing:gtest_main",
diff --git a/iree/base/testing/CMakeLists.txt b/iree/base/testing/CMakeLists.txt
index 8b0c957..6c3a4a2 100644
--- a/iree/base/testing/CMakeLists.txt
+++ b/iree/base/testing/CMakeLists.txt
@@ -50,9 +50,8 @@
DEPS
::dynamic_library_test_library
iree::base::core_headers
- iree::base::dynamic_library
+ iree::base::internal::dynamic_library
iree::base::internal::file_io
- iree::base::status
iree::testing::gtest
iree::testing::gtest_main
)
diff --git a/iree/base/testing/dynamic_library_test.cc b/iree/base/testing/dynamic_library_test.cc
index 0f831ba..559950b 100644
--- a/iree/base/testing/dynamic_library_test.cc
+++ b/iree/base/testing/dynamic_library_test.cc
@@ -12,12 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "iree/base/dynamic_library.h"
+#include "iree/base/internal/dynamic_library.h"
#include <string>
#include "iree/base/internal/file_io.h"
-#include "iree/base/status.h"
#include "iree/base/target_platform.h"
#include "iree/base/testing/dynamic_library_test_library_embed.h"
#include "iree/testing/gtest.h"
@@ -32,6 +31,20 @@
class DynamicLibraryTest : public ::testing::Test {
public:
+ static std::string GetTempFilename(const char* suffix) {
+ static int unique_id = 0;
+ char* test_tmpdir = getenv("TEST_TMPDIR");
+ if (!test_tmpdir) {
+ test_tmpdir = getenv("TMPDIR");
+ }
+ if (!test_tmpdir) {
+ test_tmpdir = getenv("TEMP");
+ }
+ IREE_CHECK(test_tmpdir) << "TEST_TMPDIR/TMPDIR/TEMP not defined";
+ return test_tmpdir + std::string("/iree_test_") +
+ std::to_string(unique_id++) + suffix;
+ }
+
static void SetUpTestCase() {
// Making files available to tests, particularly across operating systems
// and build tools (Bazel/CMake) is complicated. Rather than include a test
@@ -39,19 +52,18 @@
// the file so it's embedded in a C++ module, then write that embedded file
// to a platform/test-environment specific temp file for loading.
- std::string base_name = "dynamic_library_test_library";
- IREE_ASSERT_OK(file_io::GetTempFile(base_name, &library_temp_path_));
// System APIs for loading dynamic libraries typically require an extension.
#if defined(IREE_PLATFORM_WINDOWS)
- library_temp_path_ += ".dll";
+ static constexpr const char* ext = ".dll";
#else
- library_temp_path_ += ".so";
+ static constexpr const char* ext = ".so";
#endif
+ library_temp_path_ = GetTempFilename(ext);
const auto* file_toc = dynamic_library_test_library_create();
- absl::string_view file_data(reinterpret_cast<const char*>(file_toc->data),
- file_toc->size);
- IREE_ASSERT_OK(file_io::SetFileContents(library_temp_path_, file_data));
+ IREE_ASSERT_OK(file_io::SetFileContents(
+ library_temp_path_.c_str(),
+ iree_make_const_byte_span(file_toc->data, file_toc->size)));
IREE_LOG(INFO) << "Embedded test library written to temp path: "
<< library_temp_path_;
@@ -63,38 +75,62 @@
std::string DynamicLibraryTest::library_temp_path_;
TEST_F(DynamicLibraryTest, LoadLibrarySuccess) {
- std::unique_ptr<DynamicLibrary> library;
- IREE_ASSERT_OK(DynamicLibrary::Load(library_temp_path_.c_str(), &library));
+ iree_dynamic_library_t* library = NULL;
+ IREE_ASSERT_OK(iree_dynamic_library_load_from_file(
+ library_temp_path_.c_str(), IREE_DYNAMIC_LIBRARY_FLAG_NONE,
+ iree_allocator_system(), &library));
+ iree_dynamic_library_release(library);
}
TEST_F(DynamicLibraryTest, LoadLibraryFailure) {
- std::unique_ptr<DynamicLibrary> library;
- EXPECT_THAT(DynamicLibrary::Load(kUnknownName, &library),
- StatusIs(iree::StatusCode::kUnavailable));
+ iree_dynamic_library_t* library = NULL;
+ EXPECT_THAT(iree_dynamic_library_load_from_file(
+ kUnknownName, IREE_DYNAMIC_LIBRARY_FLAG_NONE,
+ iree_allocator_system(), &library),
+ StatusIs(iree::StatusCode::kNotFound));
}
TEST_F(DynamicLibraryTest, LoadLibraryTwice) {
- std::unique_ptr<DynamicLibrary> library1;
- IREE_ASSERT_OK(DynamicLibrary::Load(library_temp_path_.c_str(), &library1));
- std::unique_ptr<DynamicLibrary> library2;
- IREE_ASSERT_OK(DynamicLibrary::Load(library_temp_path_.c_str(), &library2));
+ iree_dynamic_library_t* library1 = NULL;
+ iree_dynamic_library_t* library2 = NULL;
+ IREE_ASSERT_OK(iree_dynamic_library_load_from_file(
+ library_temp_path_.c_str(), IREE_DYNAMIC_LIBRARY_FLAG_NONE,
+ iree_allocator_system(), &library1));
+ IREE_ASSERT_OK(iree_dynamic_library_load_from_file(
+ library_temp_path_.c_str(), IREE_DYNAMIC_LIBRARY_FLAG_NONE,
+ iree_allocator_system(), &library2));
+ iree_dynamic_library_release(library1);
+ iree_dynamic_library_release(library2);
}
TEST_F(DynamicLibraryTest, GetSymbolSuccess) {
- std::unique_ptr<DynamicLibrary> library;
- IREE_ASSERT_OK(DynamicLibrary::Load(library_temp_path_.c_str(), &library));
+ iree_dynamic_library_t* library = NULL;
+ IREE_ASSERT_OK(iree_dynamic_library_load_from_file(
+ library_temp_path_.c_str(), IREE_DYNAMIC_LIBRARY_FLAG_NONE,
+ iree_allocator_system(), &library));
- auto times_two_fn = library->GetSymbol<int (*)(int)>("times_two");
- ASSERT_NE(nullptr, times_two_fn);
- EXPECT_EQ(246, times_two_fn(123));
+ int (*fn_ptr)(int);
+ IREE_ASSERT_OK(iree_dynamic_library_lookup_symbol(library, "times_two",
+ (void**)&fn_ptr));
+ ASSERT_NE(nullptr, fn_ptr);
+ EXPECT_EQ(246, fn_ptr(123));
+
+ iree_dynamic_library_release(library);
}
TEST_F(DynamicLibraryTest, GetSymbolFailure) {
- std::unique_ptr<DynamicLibrary> library;
- IREE_ASSERT_OK(DynamicLibrary::Load(library_temp_path_.c_str(), &library));
+ iree_dynamic_library_t* library = NULL;
+ IREE_ASSERT_OK(iree_dynamic_library_load_from_file(
+ library_temp_path_.c_str(), IREE_DYNAMIC_LIBRARY_FLAG_NONE,
+ iree_allocator_system(), &library));
- auto unknown_fn = library->GetSymbol<int (*)(int)>("unknown");
- EXPECT_EQ(nullptr, unknown_fn);
+ int (*fn_ptr)(int);
+ EXPECT_THAT(
+ iree_dynamic_library_lookup_symbol(library, "unknown", (void**)&fn_ptr),
+ StatusIs(iree::StatusCode::kNotFound));
+ EXPECT_EQ(nullptr, fn_ptr);
+
+ iree_dynamic_library_release(library);
}
} // namespace
diff --git a/iree/base/testing/dynamic_library_test_library.cc b/iree/base/testing/dynamic_library_test_library.cc
index 4d99552..20cde18 100644
--- a/iree/base/testing/dynamic_library_test_library.cc
+++ b/iree/base/testing/dynamic_library_test_library.cc
@@ -13,9 +13,7 @@
// limitations under the License.
#ifdef __cplusplus
-#define IREE_API_EXPORT extern "C"
-#else
-#define IREE_API_EXPORT
+extern "C" {
#endif // __cplusplus
#if defined(_WIN32)
@@ -24,4 +22,8 @@
#define IREE_SYM_EXPORT __attribute__((visibility("default")))
#endif // _WIN32
-IREE_API_EXPORT int IREE_SYM_EXPORT times_two(int value) { return value * 2; }
+int IREE_SYM_EXPORT times_two(int value) { return value * 2; }
+
+#ifdef __cplusplus
+} // extern "C"
+#endif // __cplusplus
diff --git a/iree/hal/cuda/BUILD b/iree/hal/cuda/BUILD
index b1c1d88..00f80ef 100644
--- a/iree/hal/cuda/BUILD
+++ b/iree/hal/cuda/BUILD
@@ -80,18 +80,18 @@
name = "dynamic_symbols",
srcs = [
"cuda_headers.h",
- "dynamic_symbols.cc",
- "dynamic_symbols_tables.h",
+ "dynamic_symbols.c",
],
hdrs = [
"dynamic_symbols.h",
],
+ textual_hdrs = [
+ "dynamic_symbol_tables.h",
+ ],
deps = [
"//iree/base:core_headers",
- "//iree/base:dynamic_library",
- "//iree/base:status",
"//iree/base:tracing",
- "@com_google_absl//absl/types:span",
+ "//iree/base/internal:dynamic_library",
"@cuda_headers",
],
)
diff --git a/iree/hal/cuda/CMakeLists.txt b/iree/hal/cuda/CMakeLists.txt
index 205e343..967bde4 100644
--- a/iree/hal/cuda/CMakeLists.txt
+++ b/iree/hal/cuda/CMakeLists.txt
@@ -65,16 +65,15 @@
dynamic_symbols
HDRS
"dynamic_symbols.h"
+ TEXTUAL_HDRS
+ "dynamic_symbol_tables.h"
SRCS
"cuda_headers.h"
- "dynamic_symbols.cc"
- "dynamic_symbols_tables.h"
+ "dynamic_symbols.c"
DEPS
- absl::span
cuda_headers
iree::base::core_headers
- iree::base::dynamic_library
- iree::base::status
+ iree::base::internal::dynamic_library
iree::base::tracing
PUBLIC
)
diff --git a/iree/hal/cuda/cuda_driver.c b/iree/hal/cuda/cuda_driver.c
index 1f83363..1a1b20f 100644
--- a/iree/hal/cuda/cuda_driver.c
+++ b/iree/hal/cuda/cuda_driver.c
@@ -61,7 +61,8 @@
identifier, &driver->identifier,
(char*)driver + total_size - identifier.size);
driver->default_device_index = options->default_device_index;
- iree_status_t status = load_symbols(&driver->syms);
+ iree_status_t status =
+ iree_hal_cuda_dynamic_symbols_initialize(host_allocator, &driver->syms);
if (iree_status_is_ok(status)) {
*out_driver = (iree_hal_driver_t*)driver;
} else {
@@ -75,7 +76,7 @@
iree_allocator_t host_allocator = driver->host_allocator;
IREE_TRACE_ZONE_BEGIN(z0);
- unload_symbols(&driver->syms);
+ iree_hal_cuda_dynamic_symbols_deinitialize(&driver->syms);
iree_allocator_free(host_allocator, driver);
IREE_TRACE_ZONE_END(z0);
diff --git a/iree/hal/cuda/dynamic_symbols_tables.h b/iree/hal/cuda/dynamic_symbol_tables.h
similarity index 100%
rename from iree/hal/cuda/dynamic_symbols_tables.h
rename to iree/hal/cuda/dynamic_symbol_tables.h
diff --git a/iree/hal/cuda/dynamic_symbols.c b/iree/hal/cuda/dynamic_symbols.c
new file mode 100644
index 0000000..2449006
--- /dev/null
+++ b/iree/hal/cuda/dynamic_symbols.c
@@ -0,0 +1,73 @@
+// Copyright 2021 Google LLC
+//
+// 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
+//
+// https://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 "iree/hal/cuda/dynamic_symbols.h"
+
+#include <stddef.h>
+
+#include "iree/base/internal/dynamic_library.h"
+#include "iree/base/target_platform.h"
+#include "iree/base/tracing.h"
+
+static const char* kCUDALoaderSearchNames[] = {
+#if defined(IREE_PLATFORM_WINDOWS)
+ "nvcuda.dll",
+#else
+ "libcuda.so",
+#endif
+};
+
+static iree_status_t iree_hal_cuda_dynamic_symbols_resolve_all(
+ iree_hal_cuda_dynamic_symbols_t* syms) {
+#define CU_PFN_DECL(cudaSymbolName, ...) \
+ { \
+ static const char* kName = #cudaSymbolName; \
+ IREE_RETURN_IF_ERROR(iree_dynamic_library_lookup_symbol( \
+ syms->loader_library, kName, (void**)&syms->cudaSymbolName)); \
+ }
+#include "iree/hal/cuda/dynamic_symbol_tables.h"
+#undef CU_PFN_DECL
+ return iree_ok_status();
+}
+
+iree_status_t iree_hal_cuda_dynamic_symbols_initialize(
+ iree_allocator_t allocator, iree_hal_cuda_dynamic_symbols_t* out_syms) {
+ IREE_TRACE_ZONE_BEGIN(z0);
+ memset(out_syms, 0, sizeof(*out_syms));
+ iree_status_t status = iree_dynamic_library_load_from_files(
+ IREE_ARRAYSIZE(kCUDALoaderSearchNames), kCUDALoaderSearchNames,
+ IREE_DYNAMIC_LIBRARY_FLAG_NONE, allocator, &out_syms->loader_library);
+ if (iree_status_is_not_found(status)) {
+ iree_status_ignore(status);
+ return iree_make_status(
+ IREE_STATUS_UNAVAILABLE,
+ "CUDA runtime library not available; ensure installed and on path");
+ }
+ if (iree_status_is_ok(status)) {
+ status = iree_hal_cuda_dynamic_symbols_resolve_all(out_syms);
+ }
+ if (!iree_status_is_ok(status)) {
+ iree_hal_cuda_dynamic_symbols_deinitialize(out_syms);
+ }
+ IREE_TRACE_ZONE_END(z0);
+ return status;
+}
+
+void iree_hal_cuda_dynamic_symbols_deinitialize(
+ iree_hal_cuda_dynamic_symbols_t* syms) {
+ IREE_TRACE_ZONE_BEGIN(z0);
+ iree_dynamic_library_release(syms->loader_library);
+ memset(syms, 0, sizeof(*syms));
+ IREE_TRACE_ZONE_END(z0);
+}
diff --git a/iree/hal/cuda/dynamic_symbols.cc b/iree/hal/cuda/dynamic_symbols.cc
deleted file mode 100644
index df13a4d..0000000
--- a/iree/hal/cuda/dynamic_symbols.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2021 Google LLC
-//
-// 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
-//
-// https://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 "iree/hal/cuda/dynamic_symbols.h"
-
-#include <cstddef>
-
-#include "absl/types/span.h"
-#include "iree/base/dynamic_library.h"
-#include "iree/base/status.h"
-#include "iree/base/target_platform.h"
-#include "iree/base/tracing.h"
-
-static const char* kCUDALoaderSearchNames[] = {
-#if defined(IREE_PLATFORM_WINDOWS)
- "nvcuda.dll",
-#else
- "libcuda.so",
-#endif
-};
-
-extern "C" {
-
-iree_status_t load_symbols(iree_hal_cuda_dynamic_symbols_t* syms) {
- std::unique_ptr<iree::DynamicLibrary> loader_library;
- IREE_RETURN_IF_ERROR(iree::DynamicLibrary::Load(
- absl::MakeSpan(kCUDALoaderSearchNames), &loader_library));
-
-#define CU_PFN_DECL(cudaSymbolName, ...) \
- { \
- using FuncPtrT = decltype(syms->cudaSymbolName); \
- static const char* kName = #cudaSymbolName; \
- syms->cudaSymbolName = loader_library->GetSymbol<FuncPtrT>(kName); \
- if (!syms->cudaSymbolName) { \
- return iree_make_status(IREE_STATUS_UNAVAILABLE, "symbol not found"); \
- } \
- }
-
-#include "dynamic_symbols_tables.h"
-#undef CU_PFN_DECL
- syms->opaque_loader_library_ = (void*)loader_library.release();
- return iree_ok_status();
-}
-
-void unload_symbols(iree_hal_cuda_dynamic_symbols_t* syms) {
- delete (iree::DynamicLibrary*)syms->opaque_loader_library_;
-}
-
-} // extern "C"
\ No newline at end of file
diff --git a/iree/hal/cuda/dynamic_symbols.h b/iree/hal/cuda/dynamic_symbols.h
index 436b32d..97d9ba1 100644
--- a/iree/hal/cuda/dynamic_symbols.h
+++ b/iree/hal/cuda/dynamic_symbols.h
@@ -16,25 +16,37 @@
#define IREE_HAL_CUDA_DYNAMIC_SYMBOLS_H_
#include "iree/base/api.h"
+#include "iree/base/internal/dynamic_library.h"
#include "iree/hal/cuda/cuda_headers.h"
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
-/// DyanmicSymbols allow loading dynamically a subset of CUDA driver API. It
-/// loads all the function declared in `dynamic_symbol_tables.def` and fail if
-/// any of the symbol is not available. The functions signatures are matching
-/// the declarations in `cuda.h`.
+
+// DynamicSymbols allow loading dynamically a subset of CUDA driver API. It
+// loads all the function declared in `dynamic_symbol_tables.def` and fail if
+// any of the symbol is not available. The functions signatures are matching
+// the declarations in `cuda.h`.
typedef struct {
+ iree_dynamic_library_t* loader_library;
+
#define CU_PFN_DECL(cudaSymbolName, ...) \
CUresult (*cudaSymbolName)(__VA_ARGS__);
-#include "dynamic_symbols_tables.h"
+#include "iree/hal/cuda/dynamic_symbol_tables.h"
#undef CU_PFN_DECL
- void* opaque_loader_library_;
} iree_hal_cuda_dynamic_symbols_t;
-iree_status_t load_symbols(iree_hal_cuda_dynamic_symbols_t* syms);
-void unload_symbols(iree_hal_cuda_dynamic_symbols_t* syms);
+// Initializes |out_syms| in-place with dynamically loaded CUDA symbols.
+// iree_hal_cuda_dynamic_symbols_deinitialize must be used to release the
+// library resources.
+iree_status_t iree_hal_cuda_dynamic_symbols_initialize(
+ iree_allocator_t allocator, iree_hal_cuda_dynamic_symbols_t* out_syms);
+
+// Deinitializes |syms| by unloading the backing library. All function pointers
+// will be invalidated. They _may_ still work if there are other reasons the
+// library remains loaded so be careful.
+void iree_hal_cuda_dynamic_symbols_deinitialize(
+ iree_hal_cuda_dynamic_symbols_t* syms);
#ifdef __cplusplus
} // extern "C"
diff --git a/iree/hal/cuda/dynamic_symbols_test.cc b/iree/hal/cuda/dynamic_symbols_test.cc
index 5b8681f..566c060 100644
--- a/iree/hal/cuda/dynamic_symbols_test.cc
+++ b/iree/hal/cuda/dynamic_symbols_test.cc
@@ -30,7 +30,8 @@
TEST(DynamicSymbolsTest, CreateFromSystemLoader) {
iree_hal_cuda_dynamic_symbols_t symbols;
- iree_status_t status = load_symbols(&symbols);
+ iree_status_t status = iree_hal_cuda_dynamic_symbols_initialize(
+ iree_allocator_system(), &symbols);
if (!iree_status_is_ok(status)) {
IREE_LOG(WARNING) << "Symbols cannot be loaded, skipping test.";
GTEST_SKIP();
@@ -43,7 +44,8 @@
CUdevice device;
CUDE_CHECK_ERRORS(symbols.cuDeviceGet(&device, /*ordinal=*/0));
}
- unload_symbols(&symbols);
+
+ iree_hal_cuda_dynamic_symbols_deinitialize(&symbols);
}
} // namespace
diff --git a/iree/hal/local/loaders/BUILD b/iree/hal/local/loaders/BUILD
index 8c711c3..618881d 100644
--- a/iree/hal/local/loaders/BUILD
+++ b/iree/hal/local/loaders/BUILD
@@ -25,7 +25,7 @@
cc_library(
name = "legacy_library_loader",
- srcs = ["legacy_library_loader.cc"],
+ srcs = ["legacy_library_loader.c"],
hdrs = ["legacy_library_loader.h"],
defines = [
"IREE_HAL_HAVE_LEGACY_LIBRARY_LOADER=1",
@@ -33,11 +33,9 @@
deps = [
"//iree/base:api",
"//iree/base:core_headers",
- "//iree/base:dynamic_library",
"//iree/base:flatcc",
"//iree/base:tracing",
- "//iree/base/internal:file_io",
- "//iree/base/internal:file_path",
+ "//iree/base/internal:dynamic_library",
"//iree/hal:api",
"//iree/hal/local",
"//iree/schemas:dylib_executable_def_c_fbs",
diff --git a/iree/hal/local/loaders/CMakeLists.txt b/iree/hal/local/loaders/CMakeLists.txt
index 761b566..d4168d4 100644
--- a/iree/hal/local/loaders/CMakeLists.txt
+++ b/iree/hal/local/loaders/CMakeLists.txt
@@ -16,14 +16,12 @@
HDRS
"legacy_library_loader.h"
SRCS
- "legacy_library_loader.cc"
+ "legacy_library_loader.c"
DEPS
iree::base::api
iree::base::core_headers
- iree::base::dynamic_library
iree::base::flatcc
- iree::base::internal::file_io
- iree::base::internal::file_path
+ iree::base::internal::dynamic_library
iree::base::tracing
iree::hal::api
iree::hal::local
diff --git a/iree/hal/local/loaders/legacy_library_loader.cc b/iree/hal/local/loaders/legacy_library_loader.c
similarity index 76%
rename from iree/hal/local/loaders/legacy_library_loader.cc
rename to iree/hal/local/loaders/legacy_library_loader.c
index bebb69b..136877b 100644
--- a/iree/hal/local/loaders/legacy_library_loader.cc
+++ b/iree/hal/local/loaders/legacy_library_loader.c
@@ -14,9 +14,7 @@
#include "iree/hal/local/loaders/legacy_library_loader.h"
-#include "iree/base/dynamic_library.h"
-#include "iree/base/internal/file_io.h"
-#include "iree/base/internal/file_path.h"
+#include "iree/base/internal/dynamic_library.h"
#include "iree/base/target_platform.h"
#include "iree/base/tracing.h"
#include "iree/hal/local/local_executable.h"
@@ -74,13 +72,8 @@
// Flatbuffer definition referencing the executable memory.
iree_DyLibExecutableDef_table_t def;
- // Temporary files created as part of extraction.
- // Strings are allocated from the host allocator.
- iree_host_size_t temp_file_count;
- iree_string_view_t temp_files[8];
-
// Loaded platform dynamic library.
- iree::DynamicLibrary* handle;
+ iree_dynamic_library_t* handle;
// Queried metadata from the library.
union {
@@ -94,45 +87,14 @@
static iree_status_t iree_hal_legacy_executable_extract_and_load(
iree_hal_legacy_executable_t* executable, iree_allocator_t host_allocator) {
- // Write the embedded library out to a temp file, since all of the dynamic
- // library APIs work with files. We could instead use in-memory files on
- // platforms where that is convenient.
- //
- // TODO(#3845): use dlopen on an fd with either dlopen(/proc/self/fd/NN),
- // fdlopen, or android_dlopen_ext to avoid needing to write the file to disk.
- // Can fallback to memfd_create + dlopen where available, and fallback from
- // that to disk (maybe just windows/mac).
- std::string library_temp_path;
- IREE_RETURN_IF_ERROR(
- iree::file_io::GetTempFile("dylib_executable", &library_temp_path));
-
-// Add platform-specific file extensions so opinionated dynamic library
-// loaders are more likely to find the file:
-#if defined(IREE_PLATFORM_WINDOWS)
- library_temp_path += ".dll";
-#else
- library_temp_path += ".so";
-#endif // IREE_PLATFORM_WINDOWS
-
- iree_string_view_t library_temp_file = iree_string_view_empty();
- IREE_RETURN_IF_ERROR(
- iree_allocator_clone(host_allocator,
- iree_make_const_byte_span(library_temp_path.data(),
- library_temp_path.size()),
- (void**)&library_temp_file.data));
- library_temp_file.size = library_temp_path.size();
- executable->temp_files[executable->temp_file_count++] = library_temp_file;
-
flatbuffers_uint8_vec_t embedded_library_vec =
iree_DyLibExecutableDef_library_embedded_get(executable->def);
- IREE_RETURN_IF_ERROR(iree::file_io::SetFileContents(
- library_temp_path,
- absl::string_view(reinterpret_cast<const char*>(embedded_library_vec),
- flatbuffers_uint8_vec_len(embedded_library_vec))));
-
- std::unique_ptr<iree::DynamicLibrary> handle;
- IREE_RETURN_IF_ERROR(
- iree::DynamicLibrary::Load(library_temp_path.c_str(), &handle));
+ IREE_RETURN_IF_ERROR(iree_dynamic_library_load_from_memory(
+ iree_make_cstring_view("aot"),
+ iree_make_const_byte_span(
+ embedded_library_vec,
+ flatbuffers_uint8_vec_len(embedded_library_vec)),
+ IREE_DYNAMIC_LIBRARY_FLAG_NONE, host_allocator, &executable->handle));
flatbuffers_string_t debug_database_filename =
iree_DyLibExecutableDef_debug_database_filename_get(executable->def);
@@ -140,44 +102,22 @@
iree_DyLibExecutableDef_debug_database_embedded_get(executable->def);
if (flatbuffers_string_len(debug_database_filename) &&
flatbuffers_uint8_vec_len(debug_database_embedded_vec)) {
- IREE_TRACE_SCOPE0("DyLibExecutable::AttachDebugDatabase");
- iree_string_view_t library_temp_path_sv = iree_make_string_view(
- library_temp_path.data(), library_temp_path.size());
- iree_string_view_t debug_database_filename_sv =
- iree_make_string_view(debug_database_filename,
- flatbuffers_string_len(debug_database_filename));
- char* debug_database_path = NULL;
- IREE_RETURN_IF_ERROR(iree_file_path_join(
- iree_file_path_dirname(library_temp_path_sv),
- debug_database_filename_sv, host_allocator, &debug_database_path));
- iree_string_view_t debug_database_path_sv =
- iree_make_cstring_view(debug_database_path);
- executable->temp_files[executable->temp_file_count++] =
- debug_database_path_sv;
- IREE_IGNORE_ERROR(iree::file_io::SetFileContents(
- debug_database_path,
- absl::string_view(
- reinterpret_cast<const char*>(debug_database_embedded_vec),
+ IREE_RETURN_IF_ERROR(iree_dynamic_library_attach_symbols_from_memory(
+ executable->handle,
+ iree_make_const_byte_span(
+ debug_database_embedded_vec,
flatbuffers_uint8_vec_len(debug_database_embedded_vec))));
- handle->AttachDebugDatabase(debug_database_path);
}
-
- executable->handle = handle.release();
-
return iree_ok_status();
}
static iree_status_t iree_hal_legacy_executable_query_library(
iree_hal_legacy_executable_t* executable) {
// Get the exported symbol used to get the library metadata.
- iree_hal_executable_library_query_fn_t query_fn =
- (iree_hal_executable_library_query_fn_t)executable->handle->GetSymbol(
- IREE_HAL_EXECUTABLE_LIBRARY_EXPORT_NAME);
- if (!query_fn) {
- return iree_make_status(
- IREE_STATUS_NOT_FOUND,
- "executable metadata query function not found in library");
- }
+ iree_hal_executable_library_query_fn_t query_fn = NULL;
+ IREE_RETURN_IF_ERROR(iree_dynamic_library_lookup_symbol(
+ executable->handle, IREE_HAL_EXECUTABLE_LIBRARY_EXPORT_NAME,
+ (void**)&query_fn));
// Query for a compatible version of the library.
executable->library.header =
@@ -286,22 +226,7 @@
iree_allocator_t host_allocator = executable->base.host_allocator;
IREE_TRACE_ZONE_BEGIN(z0);
-#if IREE_TRACING_FEATURES & IREE_TRACING_FEATURE_INSTRUMENTATION
- // Leak the library when tracing, since the profiler may still be reading it.
- // TODO(benvanik): move to an atexit handler instead, verify with ASAN/MSAN
- // TODO(scotttodd): Make this compatible with testing:
- // two test cases, one for each function in the same executable
- // first test case passes, second fails to open the file (already open)
-#else
- delete executable->handle;
-#endif // IREE_TRACING_FEATURES & IREE_TRACING_FEATURE_INSTRUMENTATION
-
- for (iree_host_size_t i = 0; i < executable->temp_file_count; ++i) {
- iree_string_view_t file_path = executable->temp_files[i];
- iree::file_io::DeleteFile(std::string(file_path.data, file_path.size))
- .IgnoreError();
- iree_allocator_free(host_allocator, (void*)file_path.data);
- }
+ iree_dynamic_library_release(executable->handle);
iree_hal_local_executable_deinitialize(
(iree_hal_local_executable_t*)base_executable);
diff --git a/iree/hal/vulkan/BUILD b/iree/hal/vulkan/BUILD
index 4c495c8..d729186 100644
--- a/iree/hal/vulkan/BUILD
+++ b/iree/hal/vulkan/BUILD
@@ -121,19 +121,17 @@
"vulkan_headers.h",
],
hdrs = [
- "dynamic_symbol_tables.h",
"dynamic_symbols.h",
],
+ textual_hdrs = [
+ "dynamic_symbol_tables.h",
+ ],
deps = [
"//iree/base:core_headers",
- "//iree/base:dynamic_library",
"//iree/base:status",
"//iree/base:tracing",
+ "//iree/base/internal:dynamic_library",
"//iree/hal/vulkan/util:ref_ptr",
- "@com_google_absl//absl/base:core_headers",
- "@com_google_absl//absl/memory",
- "@com_google_absl//absl/strings",
- "@com_google_absl//absl/types:span",
"@iree_vulkan_headers//:vulkan_headers",
],
)
diff --git a/iree/hal/vulkan/CMakeLists.txt b/iree/hal/vulkan/CMakeLists.txt
index 49783de..ae1bd70 100644
--- a/iree/hal/vulkan/CMakeLists.txt
+++ b/iree/hal/vulkan/CMakeLists.txt
@@ -99,19 +99,16 @@
NAME
dynamic_symbols
HDRS
- "dynamic_symbol_tables.h"
"dynamic_symbols.h"
+ TEXTUAL_HDRS
+ "dynamic_symbol_tables.h"
SRCS
"dynamic_symbols.cc"
"vulkan_headers.h"
DEPS
Vulkan::Headers
- absl::core_headers
- absl::memory
- absl::span
- absl::strings
iree::base::core_headers
- iree::base::dynamic_library
+ iree::base::internal::dynamic_library
iree::base::status
iree::base::tracing
iree::hal::vulkan::util::ref_ptr
diff --git a/iree/hal/vulkan/dynamic_symbols.cc b/iree/hal/vulkan/dynamic_symbols.cc
index 81067c0..91bf60b 100644
--- a/iree/hal/vulkan/dynamic_symbols.cc
+++ b/iree/hal/vulkan/dynamic_symbols.cc
@@ -16,9 +16,6 @@
#include <cstddef>
-#include "absl/memory/memory.h"
-#include "absl/strings/str_cat.h"
-#include "absl/types/span.h"
#include "iree/base/attributes.h"
#include "iree/base/status.h"
#include "iree/base/target_platform.h"
@@ -164,16 +161,32 @@
StatusOr<ref_ptr<DynamicSymbols>> DynamicSymbols::CreateFromSystemLoader() {
IREE_TRACE_SCOPE0("DynamicSymbols::CreateFromSystemLoader");
- std::unique_ptr<iree::DynamicLibrary> loader_library;
- IREE_RETURN_IF_ERROR(DynamicLibrary::Load(
- absl::MakeSpan(kVulkanLoaderSearchNames), &loader_library));
- auto syms = make_ref<DynamicSymbols>();
- syms->loader_library_ = std::move(loader_library);
+ iree_dynamic_library_t* loader_library = NULL;
+ iree_status_t status = iree_dynamic_library_load_from_files(
+ IREE_ARRAYSIZE(kVulkanLoaderSearchNames), kVulkanLoaderSearchNames,
+ IREE_DYNAMIC_LIBRARY_FLAG_NONE, iree_allocator_system(), &loader_library);
+ if (iree_status_is_not_found(status)) {
+ iree_status_ignore(status);
+ return iree_make_status(
+ IREE_STATUS_UNAVAILABLE,
+ "Vulkan runtime library not available; ensure installed and on path");
+ } else if (!iree_status_is_ok(status)) {
+ return status;
+ }
- auto* loader_library_ptr = syms->loader_library_.get();
- IREE_RETURN_IF_ERROR(ResolveFunctions(
- syms.get(), [loader_library_ptr](const char* function_name) {
- return loader_library_ptr->GetSymbol<PFN_vkVoidFunction>(function_name);
+ auto syms = make_ref<DynamicSymbols>();
+ syms->loader_library_ = loader_library;
+
+ IREE_RETURN_IF_ERROR(
+ ResolveFunctions(syms.get(), [loader_library](const char* function_name) {
+ PFN_vkVoidFunction fn = NULL;
+ iree_status_t status = iree_dynamic_library_lookup_symbol(
+ loader_library, function_name, (void**)&fn);
+ if (!iree_status_is_ok(status)) {
+ IREE_IGNORE_ERROR(status);
+ return (PFN_vkVoidFunction)NULL;
+ }
+ return fn;
}));
syms->FixupExtensionFunctions();
return syms;
@@ -229,7 +242,11 @@
DynamicSymbols::DynamicSymbols() = default;
-DynamicSymbols::~DynamicSymbols() = default;
+DynamicSymbols::~DynamicSymbols() {
+ if (loader_library_) {
+ iree_dynamic_library_release(loader_library_);
+ }
+}
void DynamicSymbols::FixupExtensionFunctions() {
this->vkGetSemaphoreCounterValue = this->vkGetSemaphoreCounterValue
diff --git a/iree/hal/vulkan/dynamic_symbols.h b/iree/hal/vulkan/dynamic_symbols.h
index 67cff28..d80e339 100644
--- a/iree/hal/vulkan/dynamic_symbols.h
+++ b/iree/hal/vulkan/dynamic_symbols.h
@@ -23,7 +23,7 @@
#include <functional>
#include <memory>
-#include "iree/base/dynamic_library.h"
+#include "iree/base/internal/dynamic_library.h"
#include "iree/base/status.h"
#include "iree/hal/vulkan/dynamic_symbol_tables.h"
#include "iree/hal/vulkan/util/ref_ptr.h"
@@ -124,7 +124,7 @@
void FixupExtensionFunctions();
// Optional Vulkan Loader dynamic library.
- std::unique_ptr<DynamicLibrary> loader_library_;
+ iree_dynamic_library_t* loader_library_ = nullptr;
};
} // namespace vulkan
diff --git a/iree/testing/vulkan/iree-run-module-vulkan-gui-main.cc b/iree/testing/vulkan/iree-run-module-vulkan-gui-main.cc
index 0ea4501..29491ba 100644
--- a/iree/testing/vulkan/iree-run-module-vulkan-gui-main.cc
+++ b/iree/testing/vulkan/iree-run-module-vulkan-gui-main.cc
@@ -94,7 +94,8 @@
*out_contents = std::string{std::istreambuf_iterator<char>(std::cin),
std::istreambuf_iterator<char>()};
} else {
- IREE_RETURN_IF_ERROR(file_io::GetFileContents(module_file, out_contents));
+ IREE_RETURN_IF_ERROR(
+ file_io::GetFileContents(module_file.c_str(), out_contents));
}
return OkStatus();
}
diff --git a/iree/tools/BUILD b/iree/tools/BUILD
index 3931f8a..ca16070 100644
--- a/iree/tools/BUILD
+++ b/iree/tools/BUILD
@@ -73,6 +73,7 @@
name = "iree-dump-module",
srcs = ["iree-dump-module-main.cc"],
deps = [
+ "//iree/base:status",
"//iree/base/internal:file_io",
"//iree/schemas:bytecode_module_def_c_fbs",
],
diff --git a/iree/tools/CMakeLists.txt b/iree/tools/CMakeLists.txt
index 550059f..2c9c330 100644
--- a/iree/tools/CMakeLists.txt
+++ b/iree/tools/CMakeLists.txt
@@ -115,6 +115,7 @@
DEPS
flatcc::runtime
iree::base::internal::file_io
+ iree::base::status
iree::schemas::bytecode_module_def_c_fbs
)
diff --git a/iree/tools/iree-benchmark-module-main.cc b/iree/tools/iree-benchmark-module-main.cc
index 058dc2b..a225339 100644
--- a/iree/tools/iree-benchmark-module-main.cc
+++ b/iree/tools/iree-benchmark-module-main.cc
@@ -121,7 +121,8 @@
*out_contents = std::string{std::istreambuf_iterator<char>(std::cin),
std::istreambuf_iterator<char>()};
} else {
- IREE_RETURN_IF_ERROR(file_io::GetFileContents(module_file, out_contents));
+ IREE_RETURN_IF_ERROR(
+ file_io::GetFileContents(module_file.c_str(), out_contents));
}
return OkStatus();
}
diff --git a/iree/tools/iree-check-module-main.cc b/iree/tools/iree-check-module-main.cc
index 928b066..1a310b6 100644
--- a/iree/tools/iree-check-module-main.cc
+++ b/iree/tools/iree-check-module-main.cc
@@ -97,7 +97,7 @@
std::istreambuf_iterator<char>()};
} else {
IREE_RETURN_IF_ERROR(
- file_io::GetFileContents(module_file_path, &module_data));
+ file_io::GetFileContents(module_file_path.c_str(), &module_data));
}
iree_vm_module_t* input_module = nullptr;
diff --git a/iree/tools/iree-dump-module-main.cc b/iree/tools/iree-dump-module-main.cc
index d83e429..273246a 100644
--- a/iree/tools/iree-dump-module-main.cc
+++ b/iree/tools/iree-dump-module-main.cc
@@ -17,6 +17,7 @@
#include <utility>
#include "iree/base/internal/file_io.h"
+#include "iree/base/status.h"
#include "iree/schemas/bytecode_module_def_json_printer.h"
// Today we just print to JSON. We could do something more useful (size
@@ -31,11 +32,7 @@
return 1;
}
std::string module_contents;
- auto status = iree::file_io::GetFileContents(argv[1], &module_contents);
- if (!status.ok()) {
- std::cerr << status;
- return 1;
- }
+ IREE_CHECK_OK(iree::file_io::GetFileContents(argv[1], &module_contents));
// Print direct to stdout.
flatcc_json_printer_t printer;
diff --git a/iree/tools/iree-run-module-main.cc b/iree/tools/iree-run-module-main.cc
index f770b22..d4015a3 100644
--- a/iree/tools/iree-run-module-main.cc
+++ b/iree/tools/iree-run-module-main.cc
@@ -62,7 +62,8 @@
*out_contents = std::string{std::istreambuf_iterator<char>(std::cin),
std::istreambuf_iterator<char>()};
} else {
- IREE_RETURN_IF_ERROR(file_io::GetFileContents(module_file, out_contents));
+ IREE_RETURN_IF_ERROR(
+ file_io::GetFileContents(module_file.c_str(), out_contents));
}
return OkStatus();
}
diff --git a/iree/tools/utils/vm_util.cc b/iree/tools/utils/vm_util.cc
index fa502ad..296d7fc 100644
--- a/iree/tools/utils/vm_util.cc
+++ b/iree/tools/utils/vm_util.cc
@@ -182,7 +182,7 @@
iree_hal_allocator_t* allocator, const std::string& filename,
iree_vm_list_t** out_list) {
std::string contents;
- IREE_RETURN_IF_ERROR(file_io::GetFileContents(filename, &contents));
+ IREE_RETURN_IF_ERROR(file_io::GetFileContents(filename.c_str(), &contents));
absl::InlinedVector<absl::string_view, 4> input_views(
absl::StrSplit(contents, '\n', absl::SkipEmpty()));
return ParseToVariantList(descs, allocator, input_views, out_list);