1
0
forked from mirrors/0ad

Use std::atomic instead of platform-dependant code

This covers atomic add operations and atomic compare-and-switch
operations.
This commit is contained in:
Itms
2024-09-16 23:02:32 +02:00
committed by Nicolas Auvray
parent 9db8e792b6
commit e7434e1770
18 changed files with 103 additions and 114 deletions
+1 -2
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2018 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -24,7 +24,6 @@
#include "lib/allocators/page_aligned.h"
#include "lib/alignment.h"
#include "lib/sysdep/cpu.h" // cpu_CAS
//-----------------------------------------------------------------------------
+1 -1
View File
@@ -44,7 +44,7 @@
* execute the code passed as a parameter only the first time this is
* reached.
* may be called at any time (in particular before main), but is not
* thread-safe. if that's important, use pthread_once() instead.
* thread-safe. if that's important, use std::call_once instead.
**/
#define ONCE(ONCE_code__)\
STMT(\
+12 -14
View File
@@ -173,13 +173,11 @@ Status debug_WriteCrashlog(const wchar_t* text)
BUSY,
FAILED
};
// note: the initial state is IDLE. we rely on zero-init because
// initializing local static objects from constants may happen when
// this is first called, which isn't thread-safe. (see C++ 6.7.4)
cassert(IDLE == 0);
static volatile intptr_t state;
if(!cpu_CAS(&state, IDLE, BUSY))
static std::atomic<State> state{ IDLE };
State initial{ IDLE };
if(!state.compare_exchange_strong(initial, BUSY))
return ERR::REENTERED; // NOWARN
OsPath pathname = ah_get_log_dir()/"crashlog.txt";
@@ -342,7 +340,7 @@ void debug_DisplayMessage(const wchar_t* caption, const wchar_t* msg)
// errors (e.g. caused by atexit handlers) to come up, possibly causing an
// infinite loop. hiding errors isn't good, but we assume that whoever clicked
// exit really doesn't want to see any more messages.
static std::atomic<bool> isExiting;
static std::atomic<bool> isExiting{ false };
// this logic is applicable to any type of error. special cases such as
// suppressing certain expected WARN_ERRs are done there.
@@ -465,17 +463,17 @@ enum SkipStatus
{
INVALID, VALID, BUSY
};
static intptr_t skipStatus = INVALID;
static std::atomic<SkipStatus> skipStatus{ INVALID };
static Status errorToSkip;
static size_t numSkipped;
void debug_SkipErrors(Status err)
{
if(cpu_CAS(&skipStatus, INVALID, BUSY))
SkipStatus expected{ INVALID };
if(skipStatus.compare_exchange_strong(expected, BUSY))
{
errorToSkip = err;
numSkipped = 0;
COMPILER_FENCE;
skipStatus = VALID; // linearization point
}
else
@@ -484,10 +482,10 @@ void debug_SkipErrors(Status err)
size_t debug_StopSkippingErrors()
{
if(cpu_CAS(&skipStatus, VALID, BUSY))
SkipStatus expected{ VALID };
if(skipStatus.compare_exchange_strong(expected, BUSY))
{
const size_t ret = numSkipped;
COMPILER_FENCE;
skipStatus = INVALID; // linearization point
return ret;
}
@@ -500,11 +498,11 @@ size_t debug_StopSkippingErrors()
static bool ShouldSkipError(Status err)
{
if(cpu_CAS(&skipStatus, VALID, BUSY))
SkipStatus expected{ VALID };
if(skipStatus.compare_exchange_strong(expected, BUSY))
{
numSkipped++;
const bool ret = (err == errorToSkip);
COMPILER_FENCE;
skipStatus = VALID;
return ret;
}
+11 -11
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2010 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -27,25 +27,25 @@
#include "precompiled.h"
#include "lib/module_init.h"
#include "lib/sysdep/cpu.h" // cpu_CAS
#include "lib/sysdep/cpu.h"
// not yet initialized, or already shutdown
static const ModuleInitState UNINITIALIZED = 0; // value documented in header
static const Status UNINITIALIZED = 0; // value documented in header
// running user callback - concurrent ModuleInit callers must spin
static const ModuleInitState BUSY = ERR::AGAIN; // never returned
static const Status BUSY = ERR::AGAIN; // never returned
// init succeeded; allow shutdown
static const ModuleInitState INITIALIZED = INFO::SKIPPED;
static const Status INITIALIZED = INFO::SKIPPED;
Status ModuleInit(volatile ModuleInitState* initState, Status (*init)())
{
for(;;)
{
if(cpu_CAS(initState, UNINITIALIZED, BUSY))
Status expected{ UNINITIALIZED };
if(initState->compare_exchange_strong(expected, BUSY))
{
Status ret = init();
*initState = (ret == INFO::OK)? INITIALIZED : ret;
COMPILER_FENCE;
initState->store(ret == INFO::OK ? INITIALIZED : ret);
return ret;
}
@@ -66,11 +66,11 @@ Status ModuleShutdown(volatile ModuleInitState* initState, void (*shutdown)())
{
for(;;)
{
if(cpu_CAS(initState, INITIALIZED, BUSY))
Status expected{ INITIALIZED };
if(initState->compare_exchange_strong(expected, BUSY))
{
shutdown();
*initState = UNINITIALIZED;
COMPILER_FENCE;
initState->store(UNINITIALIZED);
return INFO::OK;
}
+4 -2
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2022 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -27,12 +27,14 @@
#ifndef INCLUDED_MODULE_INIT
#define INCLUDED_MODULE_INIT
#include <atomic>
/**
* initialization state of a module (class, source file, etc.)
* must be initialized to zero (e.g. by defining as a static variable).
* DO NOT change the value!
**/
typedef intptr_t ModuleInitState; // intptr_t is required by cpu_CAS
typedef std::atomic<Status> ModuleInitState;
/**
* calls a user-defined init function if initState is zero.
+2 -2
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -100,7 +100,7 @@ static Status InitApicIds()
return status;
}
static ModuleInitState apicInitState;
static ModuleInitState apicInitState{ 0 };
bool AreApicIdsReliable()
+6 -6
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2021 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -97,7 +97,7 @@ static Status InitCpuid()
bool cpuid(CpuidRegs* regs)
{
static ModuleInitState initState;
static ModuleInitState initState{ 0 };
ModuleInit(&initState, InitCpuid);
const u32 function = regs->eax;
@@ -118,7 +118,7 @@ bool cpuid(CpuidRegs* regs)
// keep in sync with enum Cap!
static u32 caps[4];
static ModuleInitState capsInitState;
static ModuleInitState capsInitState{ 0 };
static Status InitCaps()
{
@@ -199,7 +199,7 @@ static Status InitVendor()
Vendors Vendor()
{
static ModuleInitState initState;
static ModuleInitState initState{ 0 };
ModuleInit(&initState, InitVendor);
return vendor;
}
@@ -210,7 +210,7 @@ Vendors Vendor()
static size_t m_Model;
static size_t m_Family;
static ModuleInitState signatureInitState;
static ModuleInitState signatureInitState{ 0 };
static Status InitSignature()
{
@@ -360,7 +360,7 @@ static Status InitIdentifierString()
static const char* IdentifierString()
{
static ModuleInitState initState;
static ModuleInitState initState{ 0 };
ModuleInit(&initState, InitIdentifierString);
return identifierString;
}
+7 -5
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -24,11 +24,12 @@
#include "lib/sysdep/os/win/acpi.h"
#include "lib/byte_order.h"
#include "lib/sysdep/cpu.h"
#include "lib/module_init.h"
#include "lib/sysdep/os/win/wfirmware.h"
#include <atomic>
#pragma pack(1)
typedef const volatile u8* PCV_u8;
@@ -103,7 +104,7 @@ static bool ValidateTable(const AcpiTable* table, const char* signature = 0)
return true;
}
static void AllocateAndCopyTables(const AcpiTable**& tables, size_t& numTables)
static void AllocateAndCopyTables(std::atomic<const AcpiTable**>& tables, size_t& numTables)
{
const wfirmware::Provider provider = FOURCC_BE('A','C','P','I');
const wfirmware::TableIds tableIDs = wfirmware::GetTableIDs(provider);
@@ -135,7 +136,7 @@ static void AllocateAndCopyTables(const AcpiTable**& tables, size_t& numTables)
//-----------------------------------------------------------------------------
// note: avoid global std::map etc. because we may be called before _cinit
static const AcpiTable** tables; // tables == 0 <=> not initialized
static std::atomic<const AcpiTable**> tables{ nullptr }; // tables == nullptr <=> not initialized
static const AcpiTable* invalidTables; // tables == &invalidTables => init failed
static size_t numTables;
@@ -153,7 +154,8 @@ void acpi_Shutdown()
const AcpiTable* acpi_GetTable(const char* signature)
{
if(cpu_CAS(&tables, (const AcpiTable**)0, &invalidTables))
const AcpiTable** initial{ nullptr };
if(tables.compare_exchange_strong(initial, &invalidTables))
AllocateAndCopyTables(tables, numTables);
// (typically only a few tables, linear search is OK)
+7 -7
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2023 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -33,13 +33,13 @@
#include "lib/byte_order.h" // movzx_le64
#include "lib/module_init.h"
#include "lib/sysdep/cpu.h"
#include "lib/debug_stl.h"
#include "lib/app_hooks.h"
#include "lib/external_libraries/dbghelp.h"
#include "lib/sysdep/os/win/wdbg.h"
#include "lib/sysdep/os/win/wutil.h"
#include <atomic>
//----------------------------------------------------------------------------
// dbghelp
@@ -95,7 +95,7 @@ static Status InitDbghelp()
// symserv wants to access the internet.
static void sym_init()
{
static ModuleInitState initState;
static ModuleInitState initState{ 0 };
ModuleInit(&initState, InitDbghelp);
}
@@ -1717,8 +1717,9 @@ static Status dump_frame_cb(const STACKFRAME64* sf, uintptr_t UNUSED(userContext
Status debug_DumpStack(wchar_t* buf, size_t maxChars, void* pcontext, const wchar_t* lastFuncToSkip)
{
static intptr_t busy;
if(!cpu_CAS(&busy, 0, 1))
static std::atomic<bool> busy{ false };
if(busy.exchange(true))
return ERR::REENTERED; // NOWARN
out_init(buf, maxChars);
@@ -1727,8 +1728,7 @@ Status debug_DumpStack(wchar_t* buf, size_t maxChars, void* pcontext, const wcha
wdbg_assert(pcontext != 0);
Status ret = wdbg_sym_WalkStack(dump_frame_cb, 0, *(CONTEXT*)pcontext, lastFuncToSkip);
COMPILER_FENCE;
busy = 0;
busy = false;
return ret;
}
+4 -4
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -271,7 +271,7 @@ static void PopulateNodesFromProximityDomains(const ProximityDomains& proximityD
//-----------------------------------------------------------------------------
static ModuleInitState initState;
static ModuleInitState initState{ 0 };
static Status InitTopology()
{
@@ -434,7 +434,7 @@ static Status InitRelativeDistance()
double numa_Factor()
{
static ModuleInitState _initState;
static ModuleInitState _initState{ 0 };
UNUSED2(ModuleInit(&_initState, InitRelativeDistance));
return relativeDistance;
}
@@ -464,7 +464,7 @@ static Status InitMemoryInterleaved()
bool numa_IsMemoryInterleaved()
{
static ModuleInitState _initState;
static ModuleInitState _initState{ 0 };
UNUSED2(ModuleInit(&_initState, InitMemoryInterleaved));
return isMemoryInterleaved;
}
+10 -9
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2023 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -35,12 +35,12 @@
#include "lib/bits.h" // round_up
#include "lib/alignment.h" // IsAligned
#include "lib/module_init.h"
#include "lib/sysdep/cpu.h" // cpu_AtomicAdd
#include "lib/sysdep/filesystem.h" // O_DIRECT
#include "lib/sysdep/os/win/wutil.h" // wutil_SetPrivilege
#include "lib/sysdep/os/win/wiocp.h"
#include "lib/sysdep/os/win/wposix/crt_posix.h" // _get_osfhandle
#include <atomic>
#include <ctime>
// (dynamic linking preserves compatibility with previous Windows versions)
@@ -171,7 +171,7 @@ struct OvlAllocator // POD
void Shutdown()
{
if(extant != 0)
debug_printf("waio: OvlAllocator::Shutdown with extant=%d\n", extant);
debug_printf("waio: OvlAllocator::Shutdown with extant=%d\n", extant.load());
InterlockedFlushSList(&freelist);
@@ -208,14 +208,14 @@ struct OvlAllocator // POD
ovl.OffsetHigh = u64_hi(offset);
ovl.hEvent = 0; // (notification is via IOCP and/or polling)
cpu_AtomicAdd(&extant, +1);
++extant;
return &ovl;
}
void Deallocate(OVERLAPPED* ovl)
{
cpu_AtomicAdd(&extant, -1);
--extant;
const uintptr_t address = uintptr_t(ovl);
ENSURE(uintptr_t(storage) <= address && address < uintptr_t(storage)+storageSize);
@@ -236,7 +236,7 @@ struct OvlAllocator // POD
# pragma warning(pop)
#endif
volatile intptr_t extant;
std::atomic<intptr_t> extant{ 0 };
};
@@ -306,7 +306,7 @@ struct FileControlBlocks // POD
static const int firstDescriptor = 4000;
FileControlBlock fcbs[maxFiles];
CACHE_ALIGNED(volatile intptr_t) inUse[maxFiles];
CACHE_ALIGNED(std::atomic<intptr_t>) inUse[maxFiles]{ 0,0,0,0,0,0,0,0 };
void Init()
{
@@ -330,7 +330,8 @@ struct FileControlBlocks // POD
{
for(size_t i = 0; i < maxFiles; i++)
{
if(cpu_CAS(&inUse[i], 0, 1))
intptr_t expected{ 0 };
if(inUse[i].compare_exchange_strong(expected, 1))
return &fcbs[i];
}
@@ -366,7 +367,7 @@ static FileControlBlocks fileControlBlocks;
//-----------------------------------------------------------------------------
// init/shutdown
static ModuleInitState waio_initState;
static ModuleInitState waio_initState{ 0 };
// called from waio_Open (avoids overhead if this module is never used)
static Status waio_Init()
@@ -1,4 +1,4 @@
/* Copyright (C) 2023 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -24,12 +24,12 @@
#include "lib/sysdep/filesystem.h"
#include "lib/debug.h"
#include "lib/sysdep/cpu.h" // cpu_CAS
#include "lib/sysdep/os/win/wutil.h" // StatusFromWin
#include "lib/sysdep/os/win/wposix/waio.h" // waio_reopen
#include "lib/sysdep/os/win/wposix/wtime_internal.h" // wtime_utc_filetime_to_time_t
#include "lib/sysdep/os/win/wposix/crt_posix.h" // _close, _lseeki64 etc.
#include <atomic>
//-----------------------------------------------------------------------------
// WDIR suballocator
@@ -57,11 +57,11 @@ struct WDIR // POD
};
static WDIR wdir_storage;
static volatile intptr_t wdir_in_use;
static std::atomic<bool> wdir_in_use{ false };
static inline WDIR* wdir_alloc()
{
if(cpu_CAS(&wdir_in_use, 0, 1)) // gained ownership
if(!wdir_in_use.exchange(true)) // gained ownership
return &wdir_storage;
// already in use (rare) - allocate from heap
@@ -72,7 +72,7 @@ static inline void wdir_free(WDIR* d)
{
if(d == &wdir_storage)
{
const bool ok = cpu_CAS(&wdir_in_use, 1, 0); // relinquish ownership
const bool ok = wdir_in_use.exchange(false); // relinquish ownership
ENSURE(ok); // ensure it wasn't double-freed
}
else // allocated from heap
+5 -12
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2023 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -30,7 +30,6 @@
#include <new>
#include <process.h>
#include "lib/sysdep/cpu.h" // cpu_CAS
#include "lib/posix/posix_filesystem.h" // O_CREAT
#include "lib/sysdep/os/win/wposix/wposix_internal.h"
#include "lib/sysdep/os/win/wposix/wtime.h" // timespec
@@ -86,14 +85,6 @@ pthread_t pthread_self()
}
int pthread_once(pthread_once_t* once, void (*init_routine)())
{
if(cpu_CAS((volatile intptr_t*)once, 0, 1))
init_routine();
return 0;
}
int pthread_getschedparam(pthread_t thread, int* policy, struct sched_param* param)
{
if(policy)
@@ -147,7 +138,8 @@ static const size_t MAX_DTORS = 4;
static struct
{
pthread_key_t key;
void (*dtor)(void*);
using dtortype = void (*)(void*);
std::atomic<dtortype> dtor{ nullptr };
}
dtors[MAX_DTORS];
@@ -165,7 +157,8 @@ int pthread_key_create(pthread_key_t* key, void (*dtor)(void*))
size_t i;
for(i = 0; i < MAX_DTORS; i++)
{
if(cpu_CAS((volatile intptr_t*)&dtors[i].dtor, (intptr_t)0, (intptr_t)dtor))
void (*zero)(void*) { nullptr };
if(dtors[i].dtor.compare_exchange_strong(zero, dtor))
goto have_slot;
}
+1 -8
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2022 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -27,7 +27,6 @@
#ifndef INCLUDED_WPTHREAD
#define INCLUDED_WPTHREAD
//
// <sched.h>
//
@@ -53,12 +52,6 @@ enum
// <pthread.h>
//
// one-time init
typedef intptr_t pthread_once_t; // required for cpu_CAS
#define PTHREAD_ONCE_INIT 0 // static pthread_once_t x = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t*, void (*init_routine)());
// thread
typedef uintptr_t pthread_t;
+4 -4
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2022 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -29,11 +29,11 @@
#include "lib/byte_order.h" // FOURCC
#include "lib/utf8.h"
#include "lib/sysdep/cpu.h"
#include "lib/sysdep/os/win/win.h"
#include "lib/sysdep/os/win/wutil.h"
#include "lib/sysdep/os/win/wdbg_sym.h" // wdbg_sym_WriteMinidump
#include <atomic>
#include <process.h> // __security_init_cookie
#define NEED_COOKIE_INIT
@@ -249,8 +249,8 @@ long __stdcall wseh_ExceptionFilter(struct _EXCEPTION_POINTERS* ep)
// make sure we don't recurse infinitely if this function raises an
// SEH exception. (we may only have the guard page's 4 KB worth of
// stack space if the exception is EXCEPTION_STACK_OVERFLOW)
static intptr_t nestingLevel = 0;
cpu_AtomicAdd(&nestingLevel, 1);
static std::atomic<intptr_t> nestingLevel{ 0 };
++nestingLevel;
if(nestingLevel >= 3)
return EXCEPTION_CONTINUE_SEARCH;
+19 -18
View File
@@ -31,11 +31,11 @@
#include "lib/alignment.h" // CACHE_ALIGNED
#include "lib/bits.h" // round_down
#include "lib/module_init.h"
#include "lib/sysdep/cpu.h" // cpu_AtomicAdd
#include "lib/sysdep/numa.h"
#include "lib/sysdep/os/win/wutil.h"
#include "lib/timer.h"
#include <atomic>
#include <excpt.h>
namespace vm
@@ -51,16 +51,16 @@ CACHE_ALIGNED(struct Statistics) // POD
// thread-safe (required due to concurrent commits)
void NotifyLargePageCommit()
{
cpu_AtomicAdd(&largePageCommits, +1);
++largePageCommits;
}
void NotifySmallPageCommit()
{
cpu_AtomicAdd(&smallPageCommits, +1);
++smallPageCommits;
}
intptr_t largePageCommits;
intptr_t smallPageCommits;
std::atomic<size_t> largePageCommits{ 0 };
std::atomic<size_t> smallPageCommits{ 0 };
};
static CACHE_ALIGNED(Statistics) statistics[os_cpu_MaxProcessors];
@@ -209,8 +209,9 @@ CACHE_ALIGNED(struct AddressRangeDescriptor) // POD
Status Allocate(size_t size, size_t commitSize, PageType pageType, int prot)
{
// if this descriptor wasn't yet in use, mark it as busy
// (double-checking is cheaper than cpu_CAS)
if(base != 0 || !cpu_CAS(&base, intptr_t(0), intptr_t(this)))
// (double-checking is cheaper than compare_exchange)
void* unused{ nullptr };
if(base != nullptr || !base.compare_exchange_strong(unused, static_cast<void*>(this)))
return INFO::SKIPPED;
ENSURE(size != 0); // probably indicates a bug in caller
@@ -225,7 +226,7 @@ CACHE_ALIGNED(struct AddressRangeDescriptor) // POD
// NB: it is meaningless to ask for large pages when reserving
// (see ShouldUseLargePages). pageType only affects subsequent commits.
base = (intptr_t)AllocateLargeOrSmallPages(0, m_TotalSize, MEM_RESERVE);
base = AllocateLargeOrSmallPages(0, m_TotalSize, MEM_RESERVE);
if(!base)
{
debug_printf("AllocateLargeOrSmallPages of %lld failed\n", (u64)m_TotalSize);
@@ -233,25 +234,25 @@ CACHE_ALIGNED(struct AddressRangeDescriptor) // POD
return ERR::NO_MEM; // NOWARN (error string is more helpful)
}
alignedBase = round_up(uintptr_t(base), m_Alignment);
alignedBase = round_up(reinterpret_cast<uintptr_t>(base.load()), m_Alignment);
alignedEnd = alignedBase + round_up(size, m_Alignment);
return INFO::OK;
}
void Free()
{
vm::Free((void*)base, m_TotalSize);
m_Alignment = alignedBase = alignedEnd = 0;
vm::Free(base, m_TotalSize);
m_Alignment = 0;
m_TotalSize = 0;
COMPILER_FENCE;
base = 0; // release descriptor for subsequent reuse
alignedBase = alignedEnd = 0;
}
bool Contains(uintptr_t address) const
{
// safety check: we should never see pointers in the no-man's-land
// between the original and rounded up base addresses.
ENSURE(!(uintptr_t(base) <= address && address < alignedBase));
ENSURE(!(reinterpret_cast<uintptr_t>(base.load()) <= address && address < alignedBase));
return (alignedBase <= address && address < alignedEnd);
}
@@ -274,7 +275,7 @@ CACHE_ALIGNED(struct AddressRangeDescriptor) // POD
// (actual requested size / allocated address is required by
// ReleaseAddressSpace due to variable alignment.)
volatile intptr_t base; // (type is dictated by cpu_CAS)
std::atomic<void*> base{ nullptr };
size_t m_TotalSize;
// parameters to be relayed to vm::Commit
@@ -444,8 +445,8 @@ static LONG CALLBACK VectoredHandler(const PEXCEPTION_POINTERS ep)
static PVOID handler;
static ModuleInitState initState;
static volatile intptr_t references = 0; // atomic
static ModuleInitState initState{ 0 };
static std::atomic<intptr_t> references{ 0 };
static Status InitHandler()
{
@@ -466,12 +467,12 @@ static void ShutdownHandler()
void BeginOnDemandCommits()
{
ModuleInit(&initState, InitHandler);
cpu_AtomicAdd(&references, +1);
++references;
}
void EndOnDemandCommits()
{
if(cpu_AtomicAdd(&references, -1) == 1)
if(references.fetch_sub(1) == 1)
ModuleShutdown(&initState, ShutdownHandler);
}
+2 -2
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2020 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -690,7 +690,7 @@ void FieldStringizer::operator()<const char*>(size_t flags, const char*& value,
const Structures* GetStructures()
{
static ModuleInitState initState;
static ModuleInitState initState{ 0 };
Status ret = ModuleInit(&initState, InitStructures);
// (callers have to check if member pointers are nonzero anyway, so
// we always return a valid pointer to simplify most use cases.)
+2 -2
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2021 Wildfire Games.
/* Copyright (C) 2024 Wildfire Games.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@@ -111,7 +111,7 @@ void timer_Init()
ENSURE(gettimeofday(&start, 0) == 0);
#endif
static ModuleInitState initState;
static ModuleInitState initState{ 0 };
ModuleInit(&initState, InitResolution);
ENSURE(resolution != 0.0);
}