From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- .../checkout/src/common/system_utils_posix.cpp | 470 +++++++++++++++++++++ 1 file changed, 470 insertions(+) create mode 100644 gfx/angle/checkout/src/common/system_utils_posix.cpp (limited to 'gfx/angle/checkout/src/common/system_utils_posix.cpp') diff --git a/gfx/angle/checkout/src/common/system_utils_posix.cpp b/gfx/angle/checkout/src/common/system_utils_posix.cpp new file mode 100644 index 0000000000..ab0faee0bc --- /dev/null +++ b/gfx/angle/checkout/src/common/system_utils_posix.cpp @@ -0,0 +1,470 @@ +// +// Copyright 2018 The ANGLE Project Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// + +// system_utils_posix.cpp: Implementation of POSIX OS-specific functions. + +#include "common/debug.h" +#include "system_utils.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common/string_utils.h" + +#ifdef ANGLE_PLATFORM_FUCHSIA +# include +# include +#else +# include +#endif + +namespace angle +{ + +namespace +{ +std::string GetModulePath(void *moduleOrSymbol) +{ + Dl_info dlInfo; + if (dladdr(moduleOrSymbol, &dlInfo) == 0) + { + return ""; + } + + return dlInfo.dli_fname; +} + +void *OpenPosixLibrary(const std::string &fullPath, int extraFlags, std::string *errorOut) +{ + void *module = dlopen(fullPath.c_str(), RTLD_NOW | extraFlags); + if (module) + { + if (errorOut) + { + *errorOut = fullPath; + } + } + else if (errorOut) + { + *errorOut = "dlopen("; + *errorOut += fullPath; + *errorOut += ") failed with error: "; + *errorOut += dlerror(); + struct stat sfile; + if (-1 == stat(fullPath.c_str(), &sfile)) + { + *errorOut += ", stat() call failed."; + } + else + { + *errorOut += ", stat() info: "; + struct passwd *pwuser = getpwuid(sfile.st_uid); + if (pwuser) + { + *errorOut += "owner: "; + *errorOut += pwuser->pw_name; + *errorOut += ", "; + } + struct group *grpnam = getgrgid(sfile.st_gid); + if (grpnam) + { + *errorOut += "group: "; + *errorOut += grpnam->gr_name; + *errorOut += ", "; + } + *errorOut += "perms: "; + *errorOut += std::to_string(sfile.st_mode); + *errorOut += ", links: "; + *errorOut += std::to_string(sfile.st_nlink); + *errorOut += ", size: "; + *errorOut += std::to_string(sfile.st_size); + } + } + return module; +} +} // namespace + +Optional GetCWD() +{ + std::array pathBuf; + char *result = getcwd(pathBuf.data(), pathBuf.size()); + if (result == nullptr) + { + return Optional::Invalid(); + } + return std::string(pathBuf.data()); +} + +bool SetCWD(const char *dirName) +{ + return (chdir(dirName) == 0); +} + +bool UnsetEnvironmentVar(const char *variableName) +{ + return (unsetenv(variableName) == 0); +} + +bool SetEnvironmentVar(const char *variableName, const char *value) +{ + return (setenv(variableName, value, 1) == 0); +} + +std::string GetEnvironmentVar(const char *variableName) +{ + const char *value = getenv(variableName); + return (value == nullptr ? std::string() : std::string(value)); +} + +const char *GetPathSeparatorForEnvironmentVar() +{ + return ":"; +} + +std::string GetModuleDirectoryAndGetError(std::string *errorOut) +{ + std::string directory; + static int placeholderSymbol = 0; + std::string moduleName = GetModulePath(&placeholderSymbol); + if (!moduleName.empty()) + { + directory = moduleName.substr(0, moduleName.find_last_of('/') + 1); + } + + // Ensure we return the full path to the module, not the relative path + if (!IsFullPath(directory)) + { + if (errorOut) + { + *errorOut += "Directory: '"; + *errorOut += directory; + *errorOut += "' is not full path"; + } + Optional cwd = GetCWD(); + if (cwd.valid()) + { + directory = ConcatenatePath(cwd.value(), directory); + if (errorOut) + { + *errorOut += ", so it has been modified to: '"; + *errorOut += directory; + *errorOut += "'. "; + } + } + else if (errorOut) + { + *errorOut += " and getcwd was invalid. "; + } + } + return directory; +} + +std::string GetModuleDirectory() +{ + return GetModuleDirectoryAndGetError(nullptr); +} + +void *OpenSystemLibraryWithExtensionAndGetError(const char *libraryName, + SearchType searchType, + std::string *errorOut) +{ + std::string directory; + if (searchType == SearchType::ModuleDir) + { +#if ANGLE_PLATFORM_IOS + // On iOS, shared libraries must be loaded from within the app bundle. + directory = GetExecutableDirectory() + "/Frameworks/"; +#elif ANGLE_PLATFORM_FUCHSIA + // On Fuchsia the dynamic loader always looks up libraries in /pkg/lib + // and disallows loading of libraries via absolute paths. + directory = ""; +#else + directory = GetModuleDirectoryAndGetError(errorOut); +#endif + } + + int extraFlags = 0; + if (searchType == SearchType::AlreadyLoaded) + { + extraFlags = RTLD_NOLOAD; + } + + std::string fullPath = directory + libraryName; + return OpenPosixLibrary(fullPath, extraFlags, errorOut); +} + +void *GetLibrarySymbol(void *libraryHandle, const char *symbolName) +{ + if (!libraryHandle) + { + return nullptr; + } + + return dlsym(libraryHandle, symbolName); +} + +std::string GetLibraryPath(void *libraryHandle) +{ + if (!libraryHandle) + { + return ""; + } + + return GetModulePath(libraryHandle); +} + +void CloseSystemLibrary(void *libraryHandle) +{ + if (libraryHandle) + { + dlclose(libraryHandle); + } +} + +bool IsDirectory(const char *filename) +{ + struct stat st; + int result = stat(filename, &st); + return result == 0 && ((st.st_mode & S_IFDIR) == S_IFDIR); +} + +bool IsDebuggerAttached() +{ + // This could have a fuller implementation. + // See https://cs.chromium.org/chromium/src/base/debug/debugger_posix.cc + return false; +} + +void BreakDebugger() +{ + // This could have a fuller implementation. + // See https://cs.chromium.org/chromium/src/base/debug/debugger_posix.cc + abort(); +} + +const char *GetExecutableExtension() +{ + return ""; +} + +char GetPathSeparator() +{ + return '/'; +} + +std::string GetRootDirectory() +{ + return "/"; +} + +Optional GetTempDirectory() +{ + const char *tmp = getenv("TMPDIR"); + if (tmp != nullptr) + { + return std::string(tmp); + } + +#if defined(ANGLE_PLATFORM_ANDROID) + // Not used right now in the ANGLE test runner. + // return PathService::Get(DIR_CACHE, path); + return Optional::Invalid(); +#else + return std::string("/tmp"); +#endif +} + +Optional CreateTemporaryFileInDirectory(const std::string &directory) +{ + std::string tempFileTemplate = directory + "/.angle.XXXXXX"; + + char tempFile[1000]; + strcpy(tempFile, tempFileTemplate.c_str()); + + int fd = mkstemp(tempFile); + close(fd); + + if (fd != -1) + { + return std::string(tempFile); + } + + return Optional::Invalid(); +} + +double GetCurrentProcessCpuTime() +{ +#ifdef ANGLE_PLATFORM_FUCHSIA + static zx_handle_t me = zx_process_self(); + zx_info_task_runtime_t task_runtime; + zx_object_get_info(me, ZX_INFO_TASK_RUNTIME, &task_runtime, sizeof(task_runtime), nullptr, + nullptr); + return static_cast(task_runtime.cpu_time) * 1e-9; +#else + // We could also have used /proc/stat, but that requires us to read the + // filesystem and convert from jiffies. /proc/stat also relies on jiffies + // (lower resolution) while getrusage can potentially use a sched_clock() + // underneath that has higher resolution. + struct rusage usage; + getrusage(RUSAGE_SELF, &usage); + double userTime = usage.ru_utime.tv_sec + usage.ru_utime.tv_usec * 1e-6; + double systemTime = usage.ru_stime.tv_sec + usage.ru_stime.tv_usec * 1e-6; + return userTime + systemTime; +#endif +} + +namespace +{ +bool SetMemoryProtection(uintptr_t start, size_t size, int protections) +{ + int ret = mprotect(reinterpret_cast(start), size, protections); + if (ret < 0) + { + perror("mprotect failed"); + } + return ret == 0; +} + +class PosixPageFaultHandler : public PageFaultHandler +{ + public: + PosixPageFaultHandler(PageFaultCallback callback) : PageFaultHandler(callback) {} + ~PosixPageFaultHandler() override {} + + bool enable() override; + bool disable() override; + void handle(int sig, siginfo_t *info, void *unused); + + private: + struct sigaction mDefaultBusAction = {}; + struct sigaction mDefaultSegvAction = {}; +}; + +PosixPageFaultHandler *gPosixPageFaultHandler = nullptr; +void SegfaultHandlerFunction(int sig, siginfo_t *info, void *unused) +{ + gPosixPageFaultHandler->handle(sig, info, unused); +} + +void PosixPageFaultHandler::handle(int sig, siginfo_t *info, void *unused) +{ + bool found = false; + if ((sig == SIGSEGV || sig == SIGBUS) && + (info->si_code == SEGV_ACCERR || info->si_code == SEGV_MAPERR)) + { + found = mCallback(reinterpret_cast(info->si_addr)) == + PageFaultHandlerRangeType::InRange; + } + + // Fall back to default signal handler + if (!found) + { + if (sig == SIGSEGV) + { + mDefaultSegvAction.sa_sigaction(sig, info, unused); + } + else if (sig == SIGBUS) + { + mDefaultBusAction.sa_sigaction(sig, info, unused); + } + else + { + UNREACHABLE(); + } + } +} + +bool PosixPageFaultHandler::disable() +{ + return sigaction(SIGSEGV, &mDefaultSegvAction, nullptr) == 0 && + sigaction(SIGBUS, &mDefaultBusAction, nullptr) == 0; +} + +bool PosixPageFaultHandler::enable() +{ + struct sigaction sigAction = {}; + sigAction.sa_flags = SA_SIGINFO; + sigAction.sa_sigaction = &SegfaultHandlerFunction; + sigemptyset(&sigAction.sa_mask); + + // Some POSIX implementations use SIGBUS for mprotect faults + return sigaction(SIGSEGV, &sigAction, &mDefaultSegvAction) == 0 && + sigaction(SIGBUS, &sigAction, &mDefaultBusAction) == 0; +} +} // namespace + +// Set write protection +bool ProtectMemory(uintptr_t start, size_t size) +{ + return SetMemoryProtection(start, size, PROT_READ); +} + +// Allow reading and writing +bool UnprotectMemory(uintptr_t start, size_t size) +{ + return SetMemoryProtection(start, size, PROT_READ | PROT_WRITE); +} + +size_t GetPageSize() +{ + long pageSize = sysconf(_SC_PAGE_SIZE); + if (pageSize < 0) + { + perror("Could not get sysconf page size"); + return 0; + } + return static_cast(pageSize); +} + +PageFaultHandler *CreatePageFaultHandler(PageFaultCallback callback) +{ + gPosixPageFaultHandler = new PosixPageFaultHandler(callback); + return gPosixPageFaultHandler; +} + +uint64_t GetProcessMemoryUsageKB() +{ + FILE *file = fopen("/proc/self/status", "r"); + + if (!file) + { + return 0; + } + + const char *kSearchString = "VmRSS:"; + constexpr size_t kMaxLineSize = 100; + std::array line = {}; + + uint64_t kb = 0; + + while (fgets(line.data(), line.size(), file) != nullptr) + { + if (strncmp(line.data(), kSearchString, strlen(kSearchString)) == 0) + { + std::vector strings; + SplitStringAlongWhitespace(line.data(), &strings); + + sscanf(strings[1].c_str(), "%" SCNu64, &kb); + break; + } + } + fclose(file); + + return kb; +} +} // namespace angle -- cgit v1.2.3