Move common code from __p__osplatform.c and __p__osplatform_emul.c into
new helper function get_osplatform_helper which deduplicate code.

Do not treat zero value in _osplatform as uninitialized value as it is a
valid platform id value. Use additional variable for checking whether
_osplatform is initialized or not.

When function GetVersionExA on non-i386 systems fails then return
value 2 (WinNT) which is better default than the value 0 (Win32s) as
Win32s is i386-only.

On i386 builds use GetVersion function as GetVersionExA is not available on
older Windows NT systems.
---
 mingw-w64-crt/misc/__p__osplatform.c      | 16 +++---
 mingw-w64-crt/misc/__p__osplatform_emul.c | 59 +++++++++++++++++++++--
 2 files changed, 62 insertions(+), 13 deletions(-)

diff --git a/mingw-w64-crt/misc/__p__osplatform.c 
b/mingw-w64-crt/misc/__p__osplatform.c
index b22bf1b1a18a..d36382edb42e 100644
--- a/mingw-w64-crt/misc/__p__osplatform.c
+++ b/mingw-w64-crt/misc/__p__osplatform.c
@@ -15,6 +15,9 @@ unsigned int* (__cdecl 
*__MINGW_IMP_SYMBOL(__p__osplatform))(void) = __p__osplat
 #include <windows.h>
 #include <msvcrt.h>
 
+#define GET_OSPLATFORM_HELPER_ONLY
+#include "__p__osplatform_emul.c"
+
 static unsigned int* _osplatform_ptr;
 static unsigned int _osplatform_static;
 
@@ -23,16 +26,13 @@ unsigned int* __cdecl __p__osplatform(void)
     if (!_osplatform_ptr)
     {
         HMODULE msvcrt = __mingw_get_msvcrt_handle();
-        if (msvcrt)
-            _osplatform_ptr = (unsigned int*)GetProcAddress(msvcrt, 
"_osplatform");
-        if (!_osplatform_ptr)
+        unsigned int* ptr = msvcrt ? (unsigned int*)GetProcAddress(msvcrt, 
"_osplatform") : NULL;
+        if (!ptr)
         {
-            OSVERSIONINFOA osvi;
-            osvi.dwOSVersionInfoSize = sizeof(osvi);
-            if (GetVersionExA(&osvi))
-                _osplatform_static = osvi.dwPlatformId;
-            _osplatform_ptr = &_osplatform_static;
+            _osplatform_static = get_osplatform_helper();
+            ptr = &_osplatform_static;
         }
+        (void)InterlockedExchangePointer((PVOID*)&_osplatform_ptr, ptr);
     }
     return _osplatform_ptr;
 }
diff --git a/mingw-w64-crt/misc/__p__osplatform_emul.c 
b/mingw-w64-crt/misc/__p__osplatform_emul.c
index 5e6f0082dd43..34141e5e7067 100644
--- a/mingw-w64-crt/misc/__p__osplatform_emul.c
+++ b/mingw-w64-crt/misc/__p__osplatform_emul.c
@@ -6,19 +6,68 @@
 
 #include <windows.h>
 
+static unsigned int get_osplatform_helper(void)
+{
+    OSVERSIONINFOA osvi;
+#ifdef __i386__
+    HMODULE kernel32;
+    WINBOOL (WINAPI *kernel32_GetVersionExA)(LPOSVERSIONINFOA);
+    DWORD raw_ver;
+    WORD maj_ver;
+    BOOL is_nt;
+#endif
+
+    osvi.dwOSVersionInfoSize = sizeof(osvi);
+
+#ifdef __i386__
+    /* GetVersionExA is not available on older WinNT and Win32s versions but
+     * returns full 32-bit for platform id (2^32 possible values).
+     * GetVersion returns in highest bit identification if system is WinNT and
+     * in low 8 bits returns major os system version (Win9x starts at 4).
+     * So load GetVersionExA dynamically and on failure fallback to GetVersion.
+     */
+    kernel32 = GetModuleHandleA("kernel32.dll");
+    kernel32_GetVersionExA = kernel32 ? GetProcAddress(kernel32, 
"GetVersionExA") : NULL;
+    if (kernel32_GetVersionExA && kernel32_GetVersionExA(&osvi))
+        return osvi.dwPlatformId;
+
+    raw_ver = GetVersion();
+    maj_ver = raw_ver & 0xff;
+    is_nt = !(raw_ver >> 31);
+    if (is_nt)
+        return VER_PLATFORM_WIN32_NT;
+    else if (maj_ver >= 4)
+        return VER_PLATFORM_WIN32_WINDOWS;
+    else
+        return VER_PLATFORM_WIN32s;
+#else
+    /* On non-i386 platforms is GetVersionExA always available.
+     * In case of failures return value 2 (WinNT) which is sane default.
+     * Value 0 (Win32s) is not a sane default as Win32s is i386-only.
+     */
+    if (GetVersionExA(&osvi))
+        return osvi.dwPlatformId;
+    else
+        return VER_PLATFORM_WIN32_NT;
+#endif
+}
+
+#ifndef GET_OSPLATFORM_HELPER_ONLY
+
 #undef _osplatform
 static unsigned int _osplatform;
 
 unsigned int* __cdecl __p__osplatform(void);
 unsigned int* __cdecl __p__osplatform(void)
 {
-    if (!_osplatform)
+    static long init = 0;
+    if (!init)
     {
-        OSVERSIONINFOA osvi;
-        osvi.dwOSVersionInfoSize = sizeof(osvi);
-        if (GetVersionExA(&osvi))
-            _osplatform = osvi.dwPlatformId;
+        (void)InterlockedExchange((long*)&_osplatform, 
get_osplatform_helper());
+        (void)InterlockedExchange(&init, 1);
     }
     return &_osplatform;
 }
 unsigned int* (__cdecl *__MINGW_IMP_SYMBOL(__p__osplatform))(void) = 
__p__osplatform;
+
+#endif
-- 
2.20.1



_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to