From 62edff6b6adbbf5d7d57c1de7a8d64053ba37649 Mon Sep 17 00:00:00 2001
From: Mauller <26652186+Mauller@users.noreply.github.com>
Date: Tue, 20 May 2025 18:33:20 +0100
Subject: [PATCH] [GEN][ZH] Implement interlocked compat helper functions (#)
---
.../Utility/Utility/interlocked_compat.h | 178 ++++++++++++++++++
1 file changed, 178 insertions(+)
create mode 100644 Dependencies/Utility/Utility/interlocked_compat.h
diff --git a/Dependencies/Utility/Utility/interlocked_compat.h b/Dependencies/Utility/Utility/interlocked_compat.h
new file mode 100644
index 00000000000..0a27903fbe3
--- /dev/null
+++ b/Dependencies/Utility/Utility/interlocked_compat.h
@@ -0,0 +1,178 @@
+/*
+** Command & Conquer Generals Zero Hour(tm)
+** Copyright 2025 TheSuperHackers
+**
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation, either version 3 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program. If not, see .
+*/
+
+// This file contains macros to help with simple atomic integer interlocked operations.
+#pragma once
+
+#include
+
+
+// Interlocked helper function data types
+#if defined(__linux__) || defined(__CYGWIN__)
+typedef int16_t AtomicType16;
+typedef int32_t AtomicType32;
+typedef int64_t AtomicType64;
+
+#elif defined(__APPLE__)
+typedef SInt16 AtomicType16;
+typedef SInt32 AtomicType32;
+typedef SInt64 AtomicType64;
+
+#elif defined(__OpenBSD__)
+typedef uint16_t AtomicType16;
+typedef uint32_t AtomicType32;
+typedef uint64_t AtomicType64;
+
+#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
+typedef uint16_t AtomicType16;
+typedef uint32_t AtomicType32;
+typedef uint64_t AtomicType64;
+
+#elif defined(_WIN32) || defined(_WIN64)
+typedef int16_t AtomicType16;
+typedef long AtomicType32;
+typedef int64_t AtomicType64;
+
+#else
+#error platform not supported
+#endif
+
+
+#if defined(__linux__) || defined(__CYGWIN__)
+inline AtomicType16 interlockedIncrement16(volatile AtomicType16 *addend) { return __sync_fetch_and_add(addend, AtomicType16{ 1 }); }
+inline AtomicType32 interlockedIncrement32(volatile AtomicType32 *addend) { return __sync_fetch_and_add(addend, AtomicType32{ 1 }); }
+inline AtomicType64 interlockedIncrement64(volatile AtomicType64 *addend) { return __sync_fetch_and_add(addend, AtomicType64{ 1 }); }
+
+inline AtomicType16 interlockedDecrement16(volatile AtomicType16 *addend) { return __sync_fetch_and_sub(addend, AtomicType16{ 1 }); }
+inline AtomicType32 interlockedDecrement32(volatile AtomicType32 *addend) { return __sync_fetch_and_sub(addend, AtomicType32{ 1 }); }
+inline AtomicType64 interlockedDecrement64(volatile AtomicType64 *addend) { return __sync_fetch_and_sub(addend, AtomicType64{ 1 }); }
+
+#elif defined(__APPLE__)
+#include
+inline AtomicType16 interlockedIncrement16(volatile AtomicType16 *addend) { return OSIncrementAtomic16(addend); }
+inline AtomicType32 interlockedIncrement32(volatile AtomicType32 *addend) { return OSIncrementAtomic(addend); }
+inline AtomicType64 interlockedIncrement64(volatile AtomicType64 *addend) { return OSIncrementAtomic64(addend); }
+
+inline AtomicType16 interlockedIncrement16(volatile AtomicType16 *addend) { return OSDecrementAtomic16(addend); }
+inline AtomicType32 interlockedIncrement32(volatile AtomicType32 *addend) { return OSDecrementAtomic(addend); }
+inline AtomicType64 interlockedIncrement64(volatile AtomicType64 *addend) { return OSDecrementAtomic64(addend); }
+
+#elif defined(__OpenBSD__)
+#include
+// Appears to have no native atomic operations for 16 bit integers.
+inline AtomicType32 interlockedIncrement32(volatile AtomicType32 *addend) { return atomic_inc_int_nv(addend); }
+inline AtomicType64 interlockedIncrement64(volatile AtomicType64 *addend) { return atomic_inc_long_nv(addend); }
+
+inline AtomicType32 interlockedIncrement32(volatile AtomicType32 *addend) { return atomic_dec_int_nv(addend); }
+inline AtomicType64 interlockedIncrement64(volatile AtomicType64 *addend) { return atomic_dec_long_nv(addend); }
+
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+#include
+// Appears to have no native atomic operations for 16, 64 bit integers.
+inline AtomicType32 interlockedIncrement32(volatile AtomicType32 *addend) { return atomic_fetchadd_32(addend, AtomicType32{ 1 }); }
+
+inline AtomicType32 interlockedDecrement32(volatile AtomicType32 *addend) { return atomic_fetchadd_32(addend, ~AtomicType32{ 0 }); }
+
+#elif defined(__NetBSD__)
+#include
+// Appears to have no native atomic operations for 16 bit integers.
+inline AtomicType32 interlockedIncrement32(volatile AtomicType32 *addend) { return atomic_inc_32_nv(addend); }
+inline AtomicType64 interlockedIncrement64(volatile AtomicType64 *addend) { return atomic_inc_64_nv(addend); }
+
+inline AtomicType32 interlockedDecrement32(volatile AtomicType32 *addend) { return atomic_dec_32_nv(addend); }
+inline AtomicType32 interlockedDecrement64(volatile AtomicType64 *addend) { return atomic_dec_64_nv(addend); }
+
+#elif defined(_WIN32) || defined(_WIN64)
+#include
+#if !(defined(_MSC_VER) && _MSC_VER < 1300)
+inline AtomicType16 interlockedIncrement16(volatile AtomicType16 *addend) { return InterlockedIncrement16(addend); }
+inline AtomicType32 interlockedIncrement32(volatile AtomicType32 *addend) { return InterlockedIncrement(addend); }
+inline AtomicType64 interlockedIncrement64(volatile AtomicType64 *addend) { return InterlockedIncrement64(addend); }
+
+inline AtomicType16 interlockedDecrement16(volatile AtomicType16 *addend) { return InterlockedDecrement16(addend); }
+inline AtomicType32 interlockedDecrement32(volatile AtomicType32 *addend) { return InterlockedDecrement(addend); }
+inline AtomicType64 interlockedDecrement64(volatile AtomicType64 *addend) { return InterlockedDecrement64(addend); }
+#else
+inline AtomicType16 interlockedIncrement16(volatile AtomicType16* ptr) {
+ __asm {
+ mov ecx, ptr ; Load address of the value into ECX
+ mov ax, 1 ; Value to add (1)
+ lock xadd [ecx], ax ; Atomically add and exchange
+ inc ax ; Increment the value in AX
+ movzx eax, ax ; Zero extend AX to EAX
+ }
+}
+inline AtomicType32 interlockedIncrement32(volatile AtomicType32 *addend) { return InterlockedIncrement(addend); }
+// 64 bit interlockedIncrement64 does not handle carryover into the upper 32bits
+inline AtomicType64 interlockedIncrement64(volatile AtomicType64* ptr) {
+ __asm {
+ mov eax, ptr ; Load address of the value into EAX
+ mov ecx, 1 ; Value to add (1)
+ lock xadd [eax], ecx ; Atomically add and exchange the lower 32 bits
+ mov edx, [eax + 4] ; Load the upper 32 bits
+ add edx, 0 ; Add 0 to the upper 32 bits (no change)
+ mov [eax + 4], edx ; Store the upper 32 bits back
+ mov eax, [ptr] ; Move the new value (after increment) into EAX
+ add eax, 1 ; Increment EAX to return the new value
+ }
+}
+
+inline AtomicType16 interlockedDecrement16(volatile AtomicType16* ptr) {
+ __asm {
+ mov ecx, ptr ; Load address of the value into ECX
+ mov ax, 1 ; Value to subtract (1)
+ neg ax ; Negate the value to make it -1
+ lock xadd [ecx], ax ; Atomically add and exchange
+ dec ax ; Decrement the value in AX
+ movzx eax, ax ; Zero extend AX to EAX
+ }
+}
+inline AtomicType32 interlockedDecrement32(volatile AtomicType32 *addend) { return InterlockedDecrement(addend); }
+// 64 bit interlockedDecrement64 does not handle borrow from the upper 32bits
+inline AtomicType64 interlockedDecrement64(volatile AtomicType64* ptr) {
+ __asm {
+ mov eax, ptr ; Load address of the value into EAX
+ mov ecx, 1 ; Value to subtract (1)
+ lock xadd [eax], ecx ; Atomically add and exchange the lower 32 bits
+ neg ecx ; Negate ECX to get -1
+ lock xadd [eax], ecx ; Atomically subtract 1 from the lower 32 bits
+ mov edx, [eax + 4] ; Load the upper 32 bits
+ add edx, 0 ; Add 0 to the upper 32 bits (no change)
+ mov [eax + 4], edx ; Store the upper 32 bits back
+ mov eax, [ptr] ; Move the new value (after decrement) into EAX
+ sub eax, 1 ; Decrement EAX to return the new value
+ }
+}
+#endif // !(_MSC_VER < 1300)
+
+#else
+#error platform not supported
+#endif
+
+
+// c++ template Interlocked helper functions, prevent compiler errors when implementation is not present and function is unused for a missing type
+template inline Type interlockedIncrement(volatile Type *addend);
+template inline Type interlockedDecrement(volatile Type *addend);
+
+template<> inline AtomicType16 interlockedIncrement(volatile AtomicType16 *addend) { return interlockedIncrement16(addend); }
+template<> inline AtomicType32 interlockedIncrement(volatile AtomicType32 *addend) { return interlockedIncrement32(addend); }
+template<> inline AtomicType64 interlockedIncrement(volatile AtomicType64 *addend) { return interlockedIncrement64(addend); }
+
+template<> inline AtomicType16 interlockedDecrement(volatile AtomicType16 *addend) { return interlockedDecrement16(addend); }
+template<> inline AtomicType32 interlockedDecrement(volatile AtomicType32 *addend) { return interlockedDecrement32(addend); }
+template<> inline AtomicType64 interlockedDecrement(volatile AtomicType64 *addend) { return interlockedDecrement64(addend); }
\ No newline at end of file