mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-17 04:24:37 +03:00
[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 <chrono> 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.
This commit is contained in:
@@ -27,6 +27,25 @@
|
|||||||
#define NOMINMAX
|
#define NOMINMAX
|
||||||
#endif
|
#endif
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#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
|
#endif
|
||||||
|
|
||||||
#include "./api-config.h"
|
#include "./api-config.h"
|
||||||
|
|||||||
@@ -7,90 +7,20 @@
|
|||||||
#include "../core/osutils_p.h"
|
#include "../core/osutils_p.h"
|
||||||
#include "../core/support.h"
|
#include "../core/support.h"
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
#include <atomic>
|
|
||||||
#else
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#if defined(__APPLE__)
|
|
||||||
#include <mach/mach_time.h>
|
|
||||||
#else
|
|
||||||
#include <time.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
uint32_t OSUtils::getTickCount() noexcept {
|
|
||||||
#if defined(_WIN32)
|
|
||||||
enum HiResStatus : uint32_t {
|
|
||||||
kHiResUnknown = 0,
|
|
||||||
kHiResAvailable = 1,
|
|
||||||
kHiResNotAvailable = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::atomic<uint32_t> _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)
|
#if !defined(_WIN32)
|
||||||
Error OSUtils::readFile(const char* name, String& dst, size_t maxSize) noexcept {
|
Error OSUtils::readFile(const char* name, String& dst, size_t maxSize) noexcept {
|
||||||
char* buffer = dst.prepare(String::ModifyOp::kAssign, maxSize);
|
char* buffer = dst.prepare(String::ModifyOp::kAssign, maxSize);
|
||||||
if (ASMJIT_UNLIKELY(!buffer))
|
if (ASMJIT_UNLIKELY(!buffer))
|
||||||
return DebugUtils::errored(kErrorOutOfMemory);
|
return DebugUtils::errored(kErrorOutOfMemory);
|
||||||
|
|
||||||
int fd = ::open(name, O_RDONLY);
|
int fd = ASMJIT_FILE64_API(::open)(name, O_RDONLY);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
dst.clear();
|
dst.clear();
|
||||||
return DebugUtils::errored(kErrorFailedToOpenFile);
|
return DebugUtils::errored(kErrorFailedToOpenFile);
|
||||||
|
|||||||
@@ -13,14 +13,6 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_utilities
|
//! \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
|
//! \cond INTERNAL
|
||||||
//! Lock.
|
//! Lock.
|
||||||
//!
|
//!
|
||||||
|
|||||||
@@ -19,6 +19,10 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#if !ASMJIT_ARCH_X86
|
||||||
|
#include <sys/time.h> // required by gettimeofday()
|
||||||
|
#endif
|
||||||
|
|
||||||
// Linux has a `memfd_create` syscall that we would like to use, if available.
|
// Linux has a `memfd_create` syscall that we would like to use, if available.
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
@@ -74,17 +78,17 @@
|
|||||||
|
|
||||||
#define ASMJIT_ANONYMOUS_MEMORY_USE_FD
|
#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()`.
|
// Android NDK doesn't provide `shm_open()` and `shm_unlink()`.
|
||||||
#if !defined(__BIONIC__) && !defined(ASMJIT_NO_SHM_OPEN)
|
#if !defined(__BIONIC__) && !defined(ASMJIT_NO_SHM_OPEN)
|
||||||
#define ASMJIT_HAS_SHM_OPEN
|
#define ASMJIT_HAS_SHM_OPEN
|
||||||
#endif
|
#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
|
#if defined(__APPLE__) && TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64
|
||||||
#define ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP
|
#define ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP
|
||||||
#endif
|
#endif
|
||||||
@@ -458,6 +462,28 @@ static uint32_t getMfdExecFlag() noexcept {
|
|||||||
}
|
}
|
||||||
#endif // __linux__ && __NR_memfd_create
|
#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<uint32_t> 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 {
|
class AnonymousMemory {
|
||||||
public:
|
public:
|
||||||
enum FileType : uint32_t {
|
enum FileType : uint32_t {
|
||||||
@@ -518,26 +544,20 @@ public:
|
|||||||
else
|
else
|
||||||
return DebugUtils::errored(asmjitErrorFromErrno(errno));
|
return DebugUtils::errored(asmjitErrorFromErrno(errno));
|
||||||
#else
|
#else
|
||||||
// POSIX API. We have to generate somehow a unique name. This is nothing cryptographic, just using a bit from
|
// POSIX API. We have to generate somehow a unique name, so use `generateRandomBits()` helper. To prevent
|
||||||
// the stack address to always have a different base for different threads (as threads have their own stack)
|
// having file collisions we use `shm_open()` with flags that require creation of the file so we never open
|
||||||
// and retries for avoiding collisions. We use `shm_open()` with flags that require creation of the file so we
|
// an existing shared memory.
|
||||||
// never open an existing shared memory.
|
static const char kShmFormat[] = "/shm-id-%016llX";
|
||||||
static std::atomic<uint32_t> internalCounter;
|
|
||||||
const char* kShmFormat = "/shm-id-%016llX";
|
|
||||||
|
|
||||||
uint32_t kRetryCount = 100;
|
uint32_t kRetryCount = 100;
|
||||||
uint64_t bits = ((uintptr_t)(void*)this) & 0x55555555u;
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < kRetryCount; i++) {
|
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;
|
bool useTmp = !ASMJIT_VM_SHM_DETECT || preferTmpOverDevShm;
|
||||||
|
uint64_t bits = generateRandomBits((uintptr_t)this, i);
|
||||||
|
|
||||||
if (useTmp) {
|
if (useTmp) {
|
||||||
_tmpName.assign(getTmpDir());
|
_tmpName.assign(getTmpDir());
|
||||||
_tmpName.appendFormat(kShmFormat, (unsigned long long)bits);
|
_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)) {
|
if (ASMJIT_LIKELY(_fd >= 0)) {
|
||||||
_fileType = kFileTypeTmp;
|
_fileType = kFileTypeTmp;
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
@@ -589,7 +609,7 @@ public:
|
|||||||
|
|
||||||
Error allocate(size_t size) noexcept {
|
Error allocate(size_t size) noexcept {
|
||||||
// TODO: Improve this by using `posix_fallocate()` when available.
|
// 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 DebugUtils::errored(asmjitErrorFromErrno(errno));
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
|
|||||||
Reference in New Issue
Block a user