mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-05-04 22:49:32 +03:00
add initial primitive api for locks
This commit is contained in:
parent
d9aa19a763
commit
0b3cd51249
11 changed files with 208 additions and 48 deletions
|
@ -8,6 +8,17 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||||
#ifndef MIMALLOC_ATOMIC_H
|
#ifndef MIMALLOC_ATOMIC_H
|
||||||
#define MIMALLOC_ATOMIC_H
|
#define MIMALLOC_ATOMIC_H
|
||||||
|
|
||||||
|
// include windows.h or pthreads.h
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#endif
|
||||||
|
#include <windows.h>
|
||||||
|
#elif !defined(_WIN32) && (defined(__EMSCRIPTEN_SHARED_MEMORY__) || !defined(__wasi__))
|
||||||
|
#define MI_USE_PTHREADS
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
// Atomics
|
// Atomics
|
||||||
// We need to be portable between C, C++, and MSVC.
|
// We need to be portable between C, C++, and MSVC.
|
||||||
|
@ -133,10 +144,6 @@ static inline void mi_atomic_maxi64_relaxed(volatile int64_t* p, int64_t x) {
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
|
|
||||||
// Legacy MSVC plain C compilation wrapper that uses Interlocked operations to model C11 atomics.
|
// Legacy MSVC plain C compilation wrapper that uses Interlocked operations to model C11 atomics.
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#include <windows.h>
|
|
||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
typedef LONG64 msc_intptr_t;
|
typedef LONG64 msc_intptr_t;
|
||||||
|
@ -329,10 +336,6 @@ static inline void mi_atomic_yield(void) {
|
||||||
std::this_thread::yield();
|
std::this_thread::yield();
|
||||||
}
|
}
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#include <windows.h>
|
|
||||||
static inline void mi_atomic_yield(void) {
|
static inline void mi_atomic_yield(void) {
|
||||||
YieldProcessor();
|
YieldProcessor();
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,11 +53,6 @@ terms of the MIT license. A copy of the license can be found in the file
|
||||||
#define mi_decl_externc
|
#define mi_decl_externc
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// pthreads
|
|
||||||
#if !defined(_WIN32) && !defined(__wasi__)
|
|
||||||
#define MI_USE_PTHREADS
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// "options.c"
|
// "options.c"
|
||||||
void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message);
|
void _mi_fputs(mi_output_fun* out, void* arg, const char* prefix, const char* message);
|
||||||
|
|
|
@ -114,6 +114,24 @@ void _mi_prim_thread_done_auto_done(void);
|
||||||
// Called when the default heap for a thread changes
|
// Called when the default heap for a thread changes
|
||||||
void _mi_prim_thread_associate_default_heap(mi_heap_t* heap);
|
void _mi_prim_thread_associate_default_heap(mi_heap_t* heap);
|
||||||
|
|
||||||
|
// Locks are only used if abandoned segment visiting is permitted
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define mi_lock_t CRITICAL_SECTION
|
||||||
|
#elif defined(MI_USE_PTHREADS)
|
||||||
|
#define mi_lock_t pthread_mutex_t
|
||||||
|
#else
|
||||||
|
#define mi_lock_t _Atomic(uintptr_t)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Take a lock (blocking). Return `true` on success.
|
||||||
|
bool _mi_prim_lock(mi_lock_t* lock);
|
||||||
|
|
||||||
|
// Try to take lock and return `true` if successful.
|
||||||
|
bool _mi_prim_try_lock(mi_lock_t* lock);
|
||||||
|
|
||||||
|
// Release a lock.
|
||||||
|
void _mi_prim_unlock(mi_lock_t* lock);
|
||||||
|
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
// Thread id: `_mi_prim_thread_id()`
|
// Thread id: `_mi_prim_thread_id()`
|
||||||
|
@ -235,10 +253,6 @@ static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept {
|
||||||
|
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#include <windows.h>
|
|
||||||
static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept {
|
static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept {
|
||||||
// Windows: works on Intel and ARM in both 32- and 64-bit
|
// Windows: works on Intel and ARM in both 32- and 64-bit
|
||||||
return (uintptr_t)NtCurrentTeb();
|
return (uintptr_t)NtCurrentTeb();
|
||||||
|
@ -370,4 +384,6 @@ static inline mi_heap_t* mi_prim_get_default_heap(void) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif // MIMALLOC_PRIM_H
|
#endif // MIMALLOC_PRIM_H
|
||||||
|
|
|
@ -82,10 +82,6 @@ defined, undefined, or not accessible at all:
|
||||||
#define MI_TRACK_HEAP_DESTROY 1
|
#define MI_TRACK_HEAP_DESTROY 1
|
||||||
#define MI_TRACK_TOOL "ETW"
|
#define MI_TRACK_TOOL "ETW"
|
||||||
|
|
||||||
#ifndef WIN32_LEAN_AND_MEAN
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
|
||||||
#endif
|
|
||||||
#include <windows.h>
|
|
||||||
#include "../src/prim/windows/etw.h"
|
#include "../src/prim/windows/etw.h"
|
||||||
|
|
||||||
#define mi_track_init() EventRegistermicrosoft_windows_mimalloc();
|
#define mi_track_init() EventRegistermicrosoft_windows_mimalloc();
|
||||||
|
|
|
@ -362,7 +362,7 @@ mi_decl_nodiscard mi_decl_restrict char* mi_strndup(const char* s, size_t n) mi_
|
||||||
#ifndef PATH_MAX
|
#ifndef PATH_MAX
|
||||||
#define PATH_MAX MAX_PATH
|
#define PATH_MAX MAX_PATH
|
||||||
#endif
|
#endif
|
||||||
#include <windows.h>
|
|
||||||
mi_decl_nodiscard mi_decl_restrict char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name) mi_attr_noexcept {
|
mi_decl_nodiscard mi_decl_restrict char* mi_heap_realpath(mi_heap_t* heap, const char* fname, char* resolved_name) mi_attr_noexcept {
|
||||||
// todo: use GetFullPathNameW to allow longer file names
|
// todo: use GetFullPathNameW to allow longer file names
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
|
|
|
@ -200,7 +200,7 @@ bool _mi_prim_random_buf(void* buf, size_t buf_len) {
|
||||||
// Thread init/done
|
// Thread init/done
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN_SHARED_MEMORY__
|
#if defined(MI_USE_PTHREADS)
|
||||||
|
|
||||||
// use pthread local storage keys to detect thread ending
|
// use pthread local storage keys to detect thread ending
|
||||||
// (and used with MI_TLS_PTHREADS for the default heap)
|
// (and used with MI_TLS_PTHREADS for the default heap)
|
||||||
|
@ -242,3 +242,50 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) {
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// Locks
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
#if defined(MI_USE_PTHREADS)
|
||||||
|
|
||||||
|
bool _mi_prim_lock(mi_lock_t* lock) {
|
||||||
|
return (pthread_mutex_lock(lock) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _mi_prim_try_lock(mi_lock_t* lock) {
|
||||||
|
return (pthread_mutex_trylock(lock) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _mi_prim_unlock(mi_lock_t* lock) {
|
||||||
|
pthread_mutex_unlock(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <emscripten.h>
|
||||||
|
|
||||||
|
// fall back to poor man's locks.
|
||||||
|
bool _mi_prim_lock(mi_lock_t* lock) {
|
||||||
|
for(int i = 0; i < 1000; i++) { // for at most 1 second?
|
||||||
|
if (_mi_prim_try_lock(lock)) return true;
|
||||||
|
if (i < 25) {
|
||||||
|
mi_atomic_yield(); // first yield a bit
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
emscripten_sleep(1); // then sleep for 1ms intervals
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _mi_prim_try_lock(mi_lock_t* lock) {
|
||||||
|
uintptr_t expected = 0;
|
||||||
|
return mi_atomic_cas_strong_acq_rel(lock,&expected,(uintptr_t)1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _mi_prim_unlock(mi_lock_t* lock) {
|
||||||
|
mi_atomic_store_release(lock,(uintptr_t)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -880,3 +880,49 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// Locks
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
#if defined(MI_USE_PTHREADS)
|
||||||
|
|
||||||
|
bool _mi_prim_lock(mi_lock_t* lock) {
|
||||||
|
return (pthread_mutex_lock(lock) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _mi_prim_try_lock(mi_lock_t* lock) {
|
||||||
|
return (pthread_mutex_trylock(lock) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _mi_prim_unlock(mi_lock_t* lock) {
|
||||||
|
pthread_mutex_unlock(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// fall back to poor man's locks.
|
||||||
|
bool _mi_prim_lock(mi_lock_t* lock) {
|
||||||
|
for(int i = 0; i < 1000; i++) { // for at most 1 second?
|
||||||
|
if (_mi_prim_try_lock(lock)) return true;
|
||||||
|
if (i < 25) {
|
||||||
|
mi_atomic_yield(); // first yield a bit
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
usleep(1000); // then sleep for 1ms intervals
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _mi_prim_try_lock(mi_lock_t* lock) {
|
||||||
|
uintptr_t expected = 0;
|
||||||
|
return mi_atomic_cas_strong_acq_rel(lock,&expected,(uintptr_t)1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _mi_prim_unlock(mi_lock_t* lock) {
|
||||||
|
mi_atomic_store_release(lock,(uintptr_t)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -278,3 +278,43 @@ void _mi_prim_thread_done_auto_done(void) {
|
||||||
void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) {
|
void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) {
|
||||||
MI_UNUSED(heap);
|
MI_UNUSED(heap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// Locks
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
#if defined(MI_USE_PTHREADS)
|
||||||
|
|
||||||
|
bool _mi_prim_lock(mi_lock_t* lock) {
|
||||||
|
return (pthread_mutex_lock(lock) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _mi_prim_try_lock(mi_lock_t* lock) {
|
||||||
|
return (pthread_mutex_trylock(lock) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _mi_prim_unlock(mi_lock_t* lock) {
|
||||||
|
pthread_mutex_unlock(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// fall back to poor man's locks.
|
||||||
|
bool _mi_prim_lock(mi_lock_t* lock) {
|
||||||
|
for(int i = 0; i < 1000; i++) { // for at most 1 second?
|
||||||
|
if (_mi_prim_try_lock(lock)) return true;
|
||||||
|
mi_atomic_yield(); // this should never happen as wasi is single threaded?
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _mi_prim_try_lock(mi_lock_t* lock) {
|
||||||
|
uintptr_t expected = 0;
|
||||||
|
return mi_atomic_cas_strong_acq_rel(lock,&expected,(uintptr_t)1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _mi_prim_unlock(mi_lock_t* lock) {
|
||||||
|
mi_atomic_store_release(lock,(uintptr_t)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -468,7 +468,6 @@ mi_msecs_t _mi_prim_clock_now(void) {
|
||||||
// Process Info
|
// Process Info
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <psapi.h>
|
#include <psapi.h>
|
||||||
|
|
||||||
static mi_msecs_t filetime_msecs(const FILETIME* ftime) {
|
static mi_msecs_t filetime_msecs(const FILETIME* ftime) {
|
||||||
|
@ -564,6 +563,23 @@ bool _mi_prim_getenv(const char* name, char* result, size_t result_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
// Locks
|
||||||
|
//----------------------------------------------------------------
|
||||||
|
|
||||||
|
bool _mi_prim_lock(mi_lock_t* lock) {
|
||||||
|
EnterCriticalSection(lock);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _mi_prim_try_lock(mi_lock_t* lock) {
|
||||||
|
return TryEnterCriticalSection(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _mi_prim_unlock(mi_lock_t* lock) {
|
||||||
|
LeaveCriticalSection(lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//----------------------------------------------------------------
|
//----------------------------------------------------------------
|
||||||
// Random
|
// Random
|
||||||
|
@ -661,3 +677,4 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <Windows.h>
|
#include <windows.h>
|
||||||
static void msleep(unsigned long msecs) { Sleep(msecs); }
|
static void msleep(unsigned long msecs) { Sleep(msecs); }
|
||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
|
@ -285,7 +285,7 @@ static void (*thread_entry_fun)(intptr_t) = &stress;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
static DWORD WINAPI thread_entry(LPVOID param) {
|
static DWORD WINAPI thread_entry(LPVOID param) {
|
||||||
thread_entry_fun((intptr_t)param);
|
thread_entry_fun((intptr_t)param);
|
||||||
|
|
Loading…
Add table
Reference in a new issue