foxygit / doom Log in
commit cdd3680b9e94640cc4956ae30de734cbe1e9bf76
Author:     Simon Howard <fraggle@gmail.com>
AuthorDate: Tue Mar 3 19:26:20 2009 +0000
Commit:     Simon Howard <fraggle@gmail.com>
CommitDate: Tue Mar 3 19:26:20 2009 +0000

    Look up SetProcessAffinityMask function at runtime, so that the program
    should work under Win9x again.

    Subversion-branch: /trunk/chocolate-doom
    Subversion-revision: 1443
---
 src/i_main.c | 92 ++++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 68 insertions(+), 24 deletions(-)

diff --git a/src/i_main.c b/src/i_main.c
index c103296b..7c5b16e7 100644
--- a/src/i_main.c
+++ b/src/i_main.c
@@ -46,47 +46,91 @@
 #include "m_argv.h"
 #include "d_main.h"

-#if !defined(_WIN32) && !defined(HAVE_SCHED_SETAFFINITY)
-#warning No known way to set processor affinity on this platform.
-#warning You may experience crashes due to SDL_mixer.
-#endif
+#if defined(_WIN32)

-int main(int argc, char **argv)
-{
-    // save arguments
+typedef BOOL WINAPI (*SetAffinityFunc)(HANDLE hProcess, DWORD_PTR mask);

-    myargc = argc;
-    myargv = argv;
+// This is a bit more complicated than it really needs to be.  We really
+// just need to call the SetProcessAffinityMask function, but that
+// function doesn't exist on systems before Windows 2000.  Instead,
+// dynamically look up the function and call the pointer to it.  This
+// way, the program will run on older versions of Windows (Win9x, etc.)

-#ifdef _WIN32
+static void LockCPUAffinity(void)
+{
+    HMODULE kernel32_dll;
+    SetAffinityFunc SetAffinity;

-    // Set the process affinity mask so that all threads
-    // run on the same processor.  This is a workaround for a bug in
-    // SDL_mixer that causes occasional crashes.
+    // Find the kernel interface DLL.

-    if (!SetProcessAffinityMask(GetCurrentProcess(), 1))
+    kernel32_dll = LoadLibrary("kernel32.dll");
+
+    if (kernel32_dll == NULL)
     {
-        fprintf(stderr, "Failed to set process affinity mask (%d)\n",
-                (int) GetLastError());
+        // This should never happen...
+
+        fprintf(stderr, "Failed to load kernel32.dll\n");
+        return;
     }

-#endif
+    // Find the SetProcessAffinityMask function.

-#ifdef HAVE_SCHED_SETAFFINITY
+    SetAffinity = GetProcAddress(kernel32_dll, "SetProcessAffinityMask");

-    // Linux version:
+    // If the function was not found, we are on an old (Win9x) system
+    // that doesn't have this function.  That's no problem, because
+    // those systems don't support SMP anyway.

+    if (SetAffinity != NULL)
     {
-        cpu_set_t set;
+        if (!SetAffinity(GetCurrentProcess(), 1))
+        {
+            fprintf(stderr, "Failed to set process affinity (%d)\n",
+                            (int) GetLastError());
+        }
+    }
+}

-        CPU_ZERO(&set);
-        CPU_SET(0, &set);
+#elif defined(HAVE_SCHED_SETAFFINITY)

-        sched_setaffinity(getpid(), sizeof(set), &set);
-    }
+// Unix (Linux) version:
+
+static void LockCPUAffinity(void)
+{
+    cpu_set_t set;
+
+    CPU_ZERO(&set);
+    CPU_SET(0, &set);
+
+    sched_setaffinity(getpid(), sizeof(set), &set);
+}
+
+#else
+
+#warning No known way to set processor affinity on this platform.
+#warning You may experience crashes due to SDL_mixer.
+
+static void LockCPUAffinity(void)
+{
+    fprintf(stderr,
+    "WARNING: No known way to set processor affinity on this platform.\n"
+    "         You may experience crashes due to SDL_mixer.\n");
+}

 #endif

+int main(int argc, char **argv)
+{
+    // save arguments
+
+    myargc = argc;
+    myargv = argv;
+
+    // Only schedule on a single core, if we have multiple
+    // cores.  This is to work around a bug in SDL_mixer.
+
+    LockCPUAffinity();
+
     // start doom

     D_DoomMain ();