@@ -8,6 +8,17 @@ terms of the MIT license. A copy of the license can be found in the file
88#ifndef MIMALLOC_ATOMIC_H
99#define MIMALLOC_ATOMIC_H
1010
11+ // include windows.h or pthreads.h
12+ #if defined(_WIN32)
13+ #ifndef WIN32_LEAN_AND_MEAN
14+ #define WIN32_LEAN_AND_MEAN
15+ #endif
16+ #include < windows.h>
17+ #elif !defined(__wasi__) && (!defined(__EMSCRIPTEN__) || defined(__EMSCRIPTEN_PTHREADS__))
18+ #define MI_USE_PTHREADS
19+ #include < pthread.h>
20+ #endif
21+
1122// --------------------------------------------------------------------------------------------
1223// Atomics
1324// We need to be portable between C, C++, and MSVC.
@@ -24,9 +35,9 @@ terms of the MIT license. A copy of the license can be found in the file
2435#define mi_atomic (name ) std::atomic_##name
2536#define mi_memory_order (name ) std::memory_order_##name
2637#if (__cplusplus >= 202002L) // c++20, see issue #571
27- #define MI_ATOMIC_VAR_INIT (x ) x
38+ #define MI_ATOMIC_VAR_INIT (x ) x
2839#elif !defined(ATOMIC_VAR_INIT)
29- #define MI_ATOMIC_VAR_INIT (x ) x
40+ #define MI_ATOMIC_VAR_INIT (x ) x
3041#else
3142 #define MI_ATOMIC_VAR_INIT (x ) ATOMIC_VAR_INIT(x)
3243#endif
@@ -133,10 +144,6 @@ static inline void mi_atomic_maxi64_relaxed(volatile int64_t* p, int64_t x) {
133144#elif defined(_MSC_VER)
134145
135146// Legacy MSVC plain C compilation wrapper that uses Interlocked operations to model C11 atomics.
136- #ifndef WIN32_LEAN_AND_MEAN
137- #define WIN32_LEAN_AND_MEAN
138- #endif
139- #include < windows.h>
140147#include < intrin.h>
141148#ifdef _WIN64
142149typedef LONG64 msc_intptr_t ;
@@ -302,11 +309,16 @@ static inline intptr_t mi_atomic_subi(_Atomic(intptr_t)*p, intptr_t sub) {
302309 return (intptr_t )mi_atomic_addi (p, -sub);
303310}
304311
312+
313+ // ----------------------------------------------------------------------
314+ // Once and Guard
315+ // ----------------------------------------------------------------------
316+
305317typedef _Atomic (uintptr_t ) mi_atomic_once_t;
306318
307319// Returns true only on the first invocation
308320static inline bool mi_atomic_once ( mi_atomic_once_t * once ) {
309- if (mi_atomic_load_relaxed (once) != 0 ) return false ; // quick test
321+ if (mi_atomic_load_relaxed (once) != 0 ) return false ; // quick test
310322 uintptr_t expected = 0 ;
311323 return mi_atomic_cas_strong_acq_rel (once, &expected, (uintptr_t )1 ); // try to set to 1
312324}
@@ -322,17 +334,16 @@ typedef _Atomic(uintptr_t) mi_atomic_guard_t;
322334
323335
324336
337+ // ----------------------------------------------------------------------
325338// Yield
339+ // ----------------------------------------------------------------------
340+
326341#if defined(__cplusplus)
327342#include < thread>
328343static inline void mi_atomic_yield (void ) {
329344 std::this_thread::yield ();
330345}
331346#elif defined(_WIN32)
332- #ifndef WIN32_LEAN_AND_MEAN
333- #define WIN32_LEAN_AND_MEAN
334- #endif
335- #include < windows.h>
336347static inline void mi_atomic_yield (void ) {
337348 YieldProcessor ();
338349}
@@ -390,4 +401,107 @@ static inline void mi_atomic_yield(void) {
390401#endif
391402
392403
404+ // ----------------------------------------------------------------------
405+ // Locks are only used for abandoned segment visiting in `arena.c`
406+ // ----------------------------------------------------------------------
407+
408+ #if defined(_WIN32)
409+
410+ #define mi_lock_t CRITICAL_SECTION
411+
412+ static inline bool mi_lock_try_acquire (mi_lock_t * lock) {
413+ return TryEnterCriticalSection (lock);
414+ }
415+ static inline bool mi_lock_acquire (mi_lock_t * lock) {
416+ EnterCriticalSection (lock);
417+ return true ;
418+ }
419+ static inline void mi_lock_release (mi_lock_t * lock) {
420+ LeaveCriticalSection (lock);
421+ }
422+ static inline void mi_lock_init (mi_lock_t * lock) {
423+ InitializeCriticalSection (lock);
424+ }
425+ static inline void mi_lock_done (mi_lock_t * lock) {
426+ DeleteCriticalSection (lock);
427+ }
428+
429+
430+ #elif defined(MI_USE_PTHREADS)
431+
432+ #define mi_lock_t pthread_mutex_t
433+
434+ static inline bool mi_lock_try_acquire (mi_lock_t * lock) {
435+ return (pthread_mutex_trylock (lock) == 0 );
436+ }
437+ static inline bool mi_lock_acquire (mi_lock_t * lock) {
438+ return (pthread_mutex_lock (lock) == 0 );
439+ }
440+ static inline void mi_lock_release (mi_lock_t * lock) {
441+ pthread_mutex_unlock (lock);
442+ }
443+ static inline void mi_lock_init (mi_lock_t * lock) {
444+ pthread_mutex_init (lock, NULL );
445+ }
446+ static inline void mi_lock_done (mi_lock_t * lock) {
447+ pthread_mutex_destroy (lock);
448+ }
449+
450+ /*
451+ #elif defined(__cplusplus)
452+
453+ #include <mutex>
454+ #define mi_lock_t std::mutex
455+
456+ static inline bool mi_lock_try_acquire(mi_lock_t* lock) {
457+ return lock->lock_try_acquire();
458+ }
459+ static inline bool mi_lock_acquire(mi_lock_t* lock) {
460+ lock->lock();
461+ return true;
462+ }
463+ static inline void mi_lock_release(mi_lock_t* lock) {
464+ lock->unlock();
465+ }
466+ static inline void mi_lock_init(mi_lock_t* lock) {
467+ (void)(lock);
468+ }
469+ static inline void mi_lock_done(mi_lock_t* lock) {
470+ (void)(lock);
471+ }
472+ */
473+
474+ #else
475+
476+ // fall back to poor man's locks.
477+ // this should only be the case in a single-threaded environment (like __wasi__)
478+
479+ #define mi_lock_t _Atomic (uintptr_t )
480+
481+ static inline bool mi_lock_try_acquire(mi_lock_t * lock) {
482+ uintptr_t expected = 0 ;
483+ return mi_atomic_cas_strong_acq_rel (lock, &expected, (uintptr_t )1 );
484+ }
485+ static inline bool mi_lock_acquire (mi_lock_t * lock) {
486+ for (int i = 0 ; i < 1000 ; i++) { // for at most 1000 tries?
487+ if (mi_lock_try_acquire (lock)) return true ;
488+ mi_atomic_yield ();
489+ }
490+ return true ;
491+ }
492+ static inline void mi_lock_release (mi_lock_t * lock) {
493+ mi_atomic_store_release (lock, (uintptr_t )0 );
494+ }
495+ static inline void mi_lock_init (mi_lock_t * lock) {
496+ mi_lock_release (lock);
497+ }
498+ static inline void mi_lock_done (mi_lock_t * lock) {
499+ (void )(lock);
500+ }
501+
502+ #endif
503+
504+
505+
506+
393507#endif // __MIMALLOC_ATOMIC_H
0 commit comments