From 504c988e2f9ff03c8113b4a71bb93287ce2a6491 Mon Sep 17 00:00:00 2001 From: kobalicek Date: Sun, 3 Dec 2023 07:48:28 +0100 Subject: [PATCH] [ABI] Removed OSUtils::getTickCount(), use 64-bit file API by default OSUtils::getTickCount() is a legacy function that used to have some magic to actually return correct values. However, since the function was not used by any open-source project on GH it's better if it's just removed so it doesn't have to be maintained. It had no tests and since there is in C++ it really has no purpose anymore. In addition, use 64-bit file API by default on some platforms as this is what most applications use anyway. This is just a little optimization to avoid using both open() and open64() functions in an application if it already uses 64-bit file API. --- src/asmjit/core/api-build_p.h | 19 +++++++++ src/asmjit/core/osutils.cpp | 74 +---------------------------------- src/asmjit/core/osutils.h | 8 ---- src/asmjit/core/virtmem.cpp | 58 ++++++++++++++++++--------- 4 files changed, 60 insertions(+), 99 deletions(-) diff --git a/src/asmjit/core/api-build_p.h b/src/asmjit/core/api-build_p.h index 6eca971..3ddc9e7 100644 --- a/src/asmjit/core/api-build_p.h +++ b/src/asmjit/core/api-build_p.h @@ -27,6 +27,25 @@ #define NOMINMAX #endif #include +#else + // Most production code is compiled with large file support, so do the same. + #if !defined(_WIN32) && !defined(_LARGEFILE64_SOURCE) + #define _LARGEFILE64_SOURCE 1 + #endif + + // These OSes use 64-bit API by default. + #if defined(__APPLE__ ) || \ + defined(__HAIKU__ ) || \ + defined(__bsdi__ ) || \ + defined(__DragonFly__) || \ + defined(__FreeBSD__ ) || \ + defined(__NetBSD__ ) || \ + defined(__OpenBSD__ ) + #define ASMJIT_FILE64_API(NAME) NAME + #else + #define ASMJIT_FILE64_API(NAME) NAME##64 + #endif + #endif #include "./api-config.h" diff --git a/src/asmjit/core/osutils.cpp b/src/asmjit/core/osutils.cpp index 92cd7d5..2d39069 100644 --- a/src/asmjit/core/osutils.cpp +++ b/src/asmjit/core/osutils.cpp @@ -7,90 +7,20 @@ #include "../core/osutils_p.h" #include "../core/support.h" -#if defined(_WIN32) - #include -#else +#if !defined(_WIN32) #include #include - #if defined(__APPLE__) - #include - #else - #include - #endif #endif ASMJIT_BEGIN_NAMESPACE -uint32_t OSUtils::getTickCount() noexcept { -#if defined(_WIN32) - enum HiResStatus : uint32_t { - kHiResUnknown = 0, - kHiResAvailable = 1, - kHiResNotAvailable = 2 - }; - - static std::atomic _hiResStatus(kHiResUnknown); - static volatile double _hiResFreq(0); - - uint32_t status = _hiResStatus.load(); - LARGE_INTEGER now, qpf; - - if (status != kHiResNotAvailable && ::QueryPerformanceCounter(&now)) { - double freq = _hiResFreq; - if (status == kHiResUnknown) { - // Detects the availability of high resolution counter. - if (::QueryPerformanceFrequency(&qpf)) { - freq = double(qpf.QuadPart) / 1000.0; - _hiResFreq = freq; - _hiResStatus.compare_exchange_strong(status, kHiResAvailable); - status = kHiResAvailable; - } - else { - // High resolution not available. - _hiResStatus.compare_exchange_strong(status, kHiResNotAvailable); - } - } - - if (status == kHiResAvailable) - return uint32_t(uint64_t(int64_t(double(now.QuadPart) / freq)) & 0xFFFFFFFFu); - } - - // Bail to `GetTickCount()` if we cannot use high resolution. - return ::GetTickCount(); -#elif defined(__APPLE__) - // See Apple's QA1398. - static mach_timebase_info_data_t _machTime; - - uint32_t denom = _machTime.denom; - if (ASMJIT_UNLIKELY(!denom)) { - if (mach_timebase_info(&_machTime) != KERN_SUCCESS || !(denom = _machTime.denom)) - return 0; - } - - // `mach_absolute_time()` returns nanoseconds, we want milliseconds. - uint64_t t = mach_absolute_time() / 1000000u; - t = (t * _machTime.numer) / _machTime.denom; - return uint32_t(t & 0xFFFFFFFFu); -#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0 - struct timespec ts; - if (ASMJIT_UNLIKELY(clock_gettime(CLOCK_MONOTONIC, &ts) != 0)) - return 0; - - uint64_t t = (uint64_t(ts.tv_sec ) * 1000u) + (uint64_t(ts.tv_nsec) / 1000000u); - return uint32_t(t & 0xFFFFFFFFu); -#else - #pragma message("[asmjit] OSUtils::getTickCount() doesn't have implementation for the target OS.") - return 0; -#endif -} - #if !defined(_WIN32) Error OSUtils::readFile(const char* name, String& dst, size_t maxSize) noexcept { char* buffer = dst.prepare(String::ModifyOp::kAssign, maxSize); if (ASMJIT_UNLIKELY(!buffer)) return DebugUtils::errored(kErrorOutOfMemory); - int fd = ::open(name, O_RDONLY); + int fd = ASMJIT_FILE64_API(::open)(name, O_RDONLY); if (fd < 0) { dst.clear(); return DebugUtils::errored(kErrorFailedToOpenFile); diff --git a/src/asmjit/core/osutils.h b/src/asmjit/core/osutils.h index 67c8ebf..c658837 100644 --- a/src/asmjit/core/osutils.h +++ b/src/asmjit/core/osutils.h @@ -13,14 +13,6 @@ ASMJIT_BEGIN_NAMESPACE //! \addtogroup asmjit_utilities //! \{ -//! Operating system utilities. -namespace OSUtils { - -//! Gets the current CPU tick count, used for benchmarking (1ms resolution). -ASMJIT_API uint32_t getTickCount() noexcept; - -} // {OSUtils} - //! \cond INTERNAL //! Lock. //! diff --git a/src/asmjit/core/virtmem.cpp b/src/asmjit/core/virtmem.cpp index e59a890..ab4f589 100644 --- a/src/asmjit/core/virtmem.cpp +++ b/src/asmjit/core/virtmem.cpp @@ -19,6 +19,10 @@ #include #include + #if !ASMJIT_ARCH_X86 + #include // required by gettimeofday() + #endif + // Linux has a `memfd_create` syscall that we would like to use, if available. #if defined(__linux__) #include @@ -74,17 +78,17 @@ #define ASMJIT_ANONYMOUS_MEMORY_USE_FD - #if defined(__APPLE__) || defined(__BIONIC__) - #define ASMJIT_VM_SHM_DETECT 0 - #else - #define ASMJIT_VM_SHM_DETECT 1 - #endif - // Android NDK doesn't provide `shm_open()` and `shm_unlink()`. #if !defined(__BIONIC__) && !defined(ASMJIT_NO_SHM_OPEN) #define ASMJIT_HAS_SHM_OPEN #endif + #if defined(__APPLE__) || defined(__BIONIC__) || !defined(ASMJIT_HAS_SHM_OPEN) + #define ASMJIT_VM_SHM_DETECT 0 + #else + #define ASMJIT_VM_SHM_DETECT 1 + #endif + #if defined(__APPLE__) && TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64 #define ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP #endif @@ -458,6 +462,28 @@ static uint32_t getMfdExecFlag() noexcept { } #endif // __linux__ && __NR_memfd_create + +// It's not fully random, just to avoid collisions when opening TMP or SHM file. +ASMJIT_MAYBE_UNUSED +static uint64_t generateRandomBits(uintptr_t stackPtr, uint32_t attempt) noexcept { + static std::atomic internalCounter; + +#if defined(__GNUC__) && ASMJIT_ARCH_X86 + // Use RDTSC instruction to avoid gettimeofday() as we just need some "random" bits. + uint64_t mix = __builtin_ia32_rdtsc(); +#else + struct timeval tm {}; + uint64_t mix = 1; // only used when gettimeofday() fails, which is unlikely. + if (gettimeofday(&tm, nullptr) == 0) { + mix = uint64_t(tm.tv_usec) ^ uint64_t(tm.tv_sec); + } +#endif + + uint64_t bits = (uint64_t(stackPtr) & 0x1010505000055590u) - mix * 773703683; + bits = (bits >> 33) ^ (bits << 7) ^ (attempt * 87178291199); + return bits + uint64_t(++internalCounter) * 10619863; +} + class AnonymousMemory { public: enum FileType : uint32_t { @@ -518,26 +544,20 @@ public: else return DebugUtils::errored(asmjitErrorFromErrno(errno)); #else - // POSIX API. We have to generate somehow a unique name. This is nothing cryptographic, just using a bit from - // the stack address to always have a different base for different threads (as threads have their own stack) - // and retries for avoiding collisions. We use `shm_open()` with flags that require creation of the file so we - // never open an existing shared memory. - static std::atomic internalCounter; - const char* kShmFormat = "/shm-id-%016llX"; - + // POSIX API. We have to generate somehow a unique name, so use `generateRandomBits()` helper. To prevent + // having file collisions we use `shm_open()` with flags that require creation of the file so we never open + // an existing shared memory. + static const char kShmFormat[] = "/shm-id-%016llX"; uint32_t kRetryCount = 100; - uint64_t bits = ((uintptr_t)(void*)this) & 0x55555555u; for (uint32_t i = 0; i < kRetryCount; i++) { - bits -= uint64_t(OSUtils::getTickCount()) * 773703683; - bits = ((bits >> 14) ^ (bits << 6)) + uint64_t(++internalCounter) * 10619863; - bool useTmp = !ASMJIT_VM_SHM_DETECT || preferTmpOverDevShm; + uint64_t bits = generateRandomBits((uintptr_t)this, i); if (useTmp) { _tmpName.assign(getTmpDir()); _tmpName.appendFormat(kShmFormat, (unsigned long long)bits); - _fd = ::open(_tmpName.data(), O_RDWR | O_CREAT | O_EXCL, 0); + _fd = ASMJIT_FILE64_API(::open)(_tmpName.data(), O_RDWR | O_CREAT | O_EXCL, 0); if (ASMJIT_LIKELY(_fd >= 0)) { _fileType = kFileTypeTmp; return kErrorOk; @@ -589,7 +609,7 @@ public: Error allocate(size_t size) noexcept { // TODO: Improve this by using `posix_fallocate()` when available. - if (ftruncate(_fd, off_t(size)) != 0) + if (ASMJIT_FILE64_API(ftruncate)(_fd, off_t(size)) != 0) return DebugUtils::errored(asmjitErrorFromErrno(errno)); return kErrorOk;