I've just discovered that there are "no fence" versions of atomic-add on Windows, but they are only available starting with Windows 8/Windows Server 2012. A quick search told me that I should use IsWindows8OrGreater() from VersionHelpers.h.
I've tried something like this:
const
hasThreadSupport = compileOption("threads") and not defined(nimscript)
if defined(vcc) and hasThreadSupport:
when defined(cpp):
proc isWindows8OrGreater(): bool
{.importcpp: "_IsWindows8OrGreater(void)", header: "<VersionHelpers.h>".}
else:
proc isWindows8OrGreater(): bool
{.importc: "_IsWindows8OrGreater", header: "<VersionHelpers.h>".}
but trying to use it fails with such errors:
cl.exe /c /nologo /Z7 /IC:\nim-0.17.2\lib ...
atomiks.c
C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um\VersionHelpers.h(39): error C2061: syntax error: identifier 'BOOL'
C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um\VersionHelpers.h(39): error C2059: syntax error: ';'
C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um\VersionHelpers.h(40): error C2146: syntax error: missing ')' before identifier 'wMajorVersion'
C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um\VersionHelpers.h(40): error C2061: syntax error: identifier 'wMajorVersion'
C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um\VersionHelpers.h(40): error C2059: syntax error: ';'
C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um\VersionHelpers.h(40): error C2059: syntax error: ','
C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um\VersionHelpers.h(40): error C2059: syntax error: ')'
C:\Program Files (x86)\Windows Kits\10\include\10.0.14393.0\um\VersionHelpers.h(57): error C2061: syntax error: identifier 'BOOL'
I would like to know how to correctly call IsWindows8OrGreater() OR how to otherwise check the Windows version in some other "Nim way", if available. This would only need to be done once at the start of the application, so "speed" is not relevant in this case.
Another related question is, once I can do:
let WIN8_OR_GREATER = isWindows8OrGreater()
Can I write something like this:
proc atomicIncRelaxed*[T: AtomType](p: VolatilePtr[T], x: T = 1): T =
## Increments a volatile (32/64 bit) value, and returns the new value.
## Performed in RELAXED/No-Fence memory-model.
let pp = cast[pointer](p)
when sizeof(T) == 8:
if WIN8_OR_GREATER:
cast[T](interlockedExchangeAddNoFence64(pp, cast[int64](x)))
else:
cast[T](interlockedExchangeAdd64(pp, cast[int64](x)))
elif sizeof(T) == 4:
if WIN8_OR_GREATER:
cast[T](interlockedExchangeAddNoFence32(pp, cast[int32](x)))
else:
cast[T](interlockedExchangeAdd32(pp, cast[int32](x)))
else:
static: assert(false, "invalid parameter size: " & $sizeof(T))
and expect it to work on Windows 7? Or will it fail/crash because interlockedExchangeAddNoFence64() is not available, even if I never call it, due to the runtime check?
I never used VersionHelpers.h but you should access kernel.dll or similar directly to avoid C compiler specific code. However, for your problem you only need proper C compiler intrinsics, no fence versions of atomic-add are not an OS feature!
Or will it fail/crash because interlockedExchangeAddNoFence64() is not available, even if I never call it, due to the runtime check?
It would fail because the dependency is resolved at program startup, not when you call it for the first time (that would be racy and fragile).