mirror of
https://github.com/microsoft/mimalloc.git
synced 2025-05-04 14:39:31 +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
|
||||
#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
|
||||
// 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)
|
||||
|
||||
// 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>
|
||||
#ifdef _WIN64
|
||||
typedef LONG64 msc_intptr_t;
|
||||
|
@ -329,10 +336,6 @@ static inline void mi_atomic_yield(void) {
|
|||
std::this_thread::yield();
|
||||
}
|
||||
#elif defined(_WIN32)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
static inline void mi_atomic_yield(void) {
|
||||
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
|
||||
#endif
|
||||
|
||||
// pthreads
|
||||
#if !defined(_WIN32) && !defined(__wasi__)
|
||||
#define MI_USE_PTHREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
// "options.c"
|
||||
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
|
||||
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()`
|
||||
|
@ -235,10 +253,6 @@ static inline mi_threadid_t _mi_prim_thread_id(void) mi_attr_noexcept {
|
|||
|
||||
#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 {
|
||||
// Windows: works on Intel and ARM in both 32- and 64-bit
|
||||
return (uintptr_t)NtCurrentTeb();
|
||||
|
@ -370,4 +384,6 @@ static inline mi_heap_t* mi_prim_get_default_heap(void) {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // MIMALLOC_PRIM_H
|
||||
|
|
|
@ -82,10 +82,6 @@ defined, undefined, or not accessible at all:
|
|||
#define MI_TRACK_HEAP_DESTROY 1
|
||||
#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"
|
||||
|
||||
#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
|
||||
#define PATH_MAX MAX_PATH
|
||||
#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 {
|
||||
// todo: use GetFullPathNameW to allow longer file names
|
||||
char buf[PATH_MAX];
|
||||
|
|
|
@ -200,7 +200,7 @@ bool _mi_prim_random_buf(void* buf, size_t buf_len) {
|
|||
// Thread init/done
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#ifdef __EMSCRIPTEN_SHARED_MEMORY__
|
||||
#if defined(MI_USE_PTHREADS)
|
||||
|
||||
// use pthread local storage keys to detect thread ending
|
||||
// (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
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// 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
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
// 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) {
|
||||
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
|
||||
//----------------------------------------------------------------
|
||||
|
||||
#include <windows.h>
|
||||
#include <psapi.h>
|
||||
|
||||
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
|
||||
|
@ -661,3 +677,4 @@ void _mi_prim_thread_associate_default_heap(mi_heap_t* heap) {
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <windows.h>
|
||||
static void msleep(unsigned long msecs) { Sleep(msecs); }
|
||||
#else
|
||||
#include <unistd.h>
|
||||
|
|
|
@ -285,7 +285,7 @@ static void (*thread_entry_fun)(intptr_t) = &stress;
|
|||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <Windows.h>
|
||||
#include <windows.h>
|
||||
|
||||
static DWORD WINAPI thread_entry(LPVOID param) {
|
||||
thread_entry_fun((intptr_t)param);
|
||||
|
|
Loading…
Add table
Reference in a new issue