[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:
kobalicek
2023-12-03 07:48:28 +01:00
parent e731f57975
commit 504c988e2f
4 changed files with 60 additions and 99 deletions

View File

@@ -27,6 +27,25 @@
#define NOMINMAX
#endif
#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
#include "./api-config.h"

View File

@@ -7,90 +7,20 @@
#include "../core/osutils_p.h"
#include "../core/support.h"
#if defined(_WIN32)
#include <atomic>
#else
#if !defined(_WIN32)
#include <fcntl.h>
#include <unistd.h>
#if defined(__APPLE__)
#include <mach/mach_time.h>
#else
#include <time.h>
#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<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)
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);

View File

@@ -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.
//!

View File

@@ -19,6 +19,10 @@
#include <sys/types.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.
#if defined(__linux__)
#include <sys/syscall.h>
@@ -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<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 {
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<uint32_t> 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;