From d08117e30a52bedff8fced26bc9f12856cba9134 Mon Sep 17 00:00:00 2001
From: capehill <juha.niemimaki@gmail.com>
Date: Thu, 10 Oct 2019 20:55:32 +0300
Subject: [PATCH] Tweak timer logic. Now a single CTRL-C signal should quit
 properly

---
 main.c              | 123 ++++++++++++++++++++++++++++++++++++++------
 timer.c             |   1 +
 warp3dnova_module.c |  22 ++++++--
 warp3dnova_module.h |   2 +-
 4 files changed, 125 insertions(+), 23 deletions(-)

diff --git a/main.c b/main.c
index bf8ec6f..627511c 100644
--- a/main.c
+++ b/main.c
@@ -31,9 +31,14 @@ static struct Params params = { 0, 0, 0, 0, NULL, NULL, NULL };
 
 static struct MsgPort* port;
 
+struct Task* mainTask;
+BYTE mainSig = -1;
+
 static ULONG startTime;
 static ULONG duration;
 
+static BOOL running = TRUE;
+
 static BOOL already_running(void)
 {
     IExec->Forbid();
@@ -64,6 +69,38 @@ static void remove_port()
     }
 }
 
+static void sanitiseParams(void)
+{
+    if (params.gui) {
+        // Some of these limitations may be lifted in the future
+        if (startTime) {
+            puts("Using STARTTIME with GUI is not possible yet");
+            startTime = 0;
+        }
+
+        if (duration) {
+            puts("Using DURATION with GUI is not possible yet");
+            duration = 0;
+        }
+    }
+
+    if (!params.profiling) {
+        if (startTime) {
+            puts("STARTTIME is meant to be used with PROFILE");
+            startTime = 0;
+        }
+        if (duration) {
+            puts("DURATION is meant to be used with PROFILE");
+            duration = 0;
+        }
+    }
+
+    if (!params.ogles2 && !params.nova) {
+        // If user gives nothing, assume everything
+        params.ogles2 = params.nova = TRUE;
+    }
+}
+
 static BOOL parse_args(void)
 {
     const char* const enabled = "enabled";
@@ -93,10 +130,7 @@ static BOOL parse_args(void)
         return FALSE;
     }
 
-    if (!params.ogles2 && !params.nova) {
-        // If user gives nothing, assume everything
-        params.ogles2 = params.nova = TRUE;
-    }
+    sanitiseParams();
 
     puts("--- Configuration ---");
     printf("  OGLES2 module: [%s]\n", params.ogles2 ? enabled : disabled);
@@ -118,7 +152,7 @@ static void install_patches(void)
     }
 
     if (params.nova) {
-        warp3dnova_install_patches(startTime);
+        warp3dnova_install_patches(startTime, duration);
     }
 }
 
@@ -150,22 +184,33 @@ static void remove_patches(void)
     ogles2_free();
 }
 
-static void waitForStartAndStop()
+// When STARTTIME > 0
+static void waitForStartTimer()
 {
     const uint32 timerSig = timer_signal(&triggerTimer);
 
-    if (timer_wait_for_signal(timerSig, "Start") == ESignalType_Timer) {
-        puts("First timer signal - start profiling");
+    const ESignalType type = timer_wait_for_signal(timerSig, "Start");
+
+    if (type == ESignalType_Timer) {
+        puts("Timer signal - start profiling");
 
         timer_handle_events(&triggerTimer);
 
         ogles2_start_profiling();
         warp3dnova_start_profiling();
+    } else if (type == ESignalType_Break) {
+        running = FALSE;
+    }
+}
 
-        if (duration) {
-            timer_start(&triggerTimer, duration, 0);
-            puts("Waiting...");
-        }
+static void waitForEndTimer()
+{
+    if (running) {
+        timer_start(&triggerTimer, duration, 0);
+
+        const uint32 timerSig = timer_signal(&triggerTimer);
+
+        puts("Waiting for timer...");
 
         if (timer_wait_for_signal(timerSig, "Stop") == ESignalType_Timer) {
             puts("Timer signal - stop profiling");
@@ -174,10 +219,41 @@ static void waitForStartAndStop()
     }
 }
 
-static void waitForBreakSignal()
+static void waitForSignal()
+{
+    if (running) {
+        const uint32 sigMask = 1L << mainSig;
+        const uint32 wait = IExec->Wait(sigMask | SIGBREAKF_CTRL_C);
+
+        if (wait & sigMask) {
+            puts("Start signal received");
+        }
+
+        if (wait & SIGBREAKF_CTRL_C) {
+            puts("Break signal received");
+            running = FALSE;
+        }
+    }
+}
+
+static void waitForTimers()
 {
-    if (IExec->Wait(SIGBREAKF_CTRL_C)) {
-        puts("*** Control-C detected ***");
+    if (startTime) {
+        waitForStartTimer();
+    }
+
+    if (duration) {
+        if (!startTime) {
+            // NOVA module Signal()s us
+            puts("Waiting for signal...");
+            waitForSignal();
+        }
+
+        waitForEndTimer();
+    } else {
+        if (startTime) {
+            waitForSignal();
+        }
     }
 }
 
@@ -187,9 +263,9 @@ static void run(void)
         run_gui(params.profiling);
     } else {
         if (startTime || duration) {
-            waitForStartAndStop();
+            waitForTimers();
         } else {
-            waitForBreakSignal();
+            waitForSignal();
         }
     }
 }
@@ -207,6 +283,8 @@ int main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
         goto out;
     }
 
+    mainTask = IExec->FindTask(NULL);
+
     if (!timer_init(&timer)) {
         goto out;
     }
@@ -217,6 +295,12 @@ int main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
         }
     }
 
+    mainSig = IExec->AllocSignal(-1);
+    if (mainSig == -1) {
+        puts("Failed to allocate signal");
+        goto out;
+    }
+
     create_port();
 
     if (!load_filters(filterFile)) {
@@ -239,6 +323,11 @@ int main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
     puts("Patches removed. glSnoop terminating");
 
 out:
+    if (mainSig != -1) {
+        IExec->FreeSignal(mainSig);
+        mainSig = -1;
+    }
+
     remove_port();
 
     free_filters();
diff --git a/timer.c b/timer.c
index 59d7c9d..03a7dbb 100644
--- a/timer.c
+++ b/timer.c
@@ -166,6 +166,7 @@ void timer_stop(TimerContext * tc)
     }
 
     if (!IExec->CheckIO((struct IORequest *) tc->request)) {
+        logLine("%s: aborting timer IO request %p", __func__, tc->request);
         IExec->AbortIO((struct IORequest *) tc->request);
         IExec->WaitIO((struct IORequest *) tc->request);
     }
diff --git a/warp3dnova_module.c b/warp3dnova_module.c
index 4427603..e526301 100644
--- a/warp3dnova_module.c
+++ b/warp3dnova_module.c
@@ -11,6 +11,9 @@
 #include <stdio.h>
 #include <string.h>
 
+extern BYTE mainSig;
+extern struct Task* mainTask;
+
 typedef enum NovaFunction {
     BindBitMapAsTexture,
     BindShaderDataBuffer,
@@ -248,6 +251,7 @@ static unsigned errorCount;
 static BOOL profilingStarted = TRUE;
 
 static ULONG startTime = 0;
+static ULONG duration = 0;
 
 static const char* mapNovaError(const W3DN_ErrorCode code)
 {
@@ -2983,10 +2987,17 @@ static W3DN_Context* my_W3DN_CreateContext(struct Warp3DNovaIFace *Self, W3DN_Er
                     patch_context_functions(nova);
                     PROF_INIT(nova, NovaFunctionCount)
 
-                    logLine("Trigger start timer in %lu seconds", startTime);
-                    // TODO: supports only one app. A proper implementation
-                    // would need a some kind of a timer pool?
-                    timer_start(&triggerTimer, startTime, 0);
+                    if (startTime) {
+                        logLine("Trigger timer in %lu seconds", startTime);
+                        // TODO: supports only one app. A proper implementation
+                        // would need a some kind of a timer pool?
+                        timer_start(&triggerTimer, startTime, 0);
+                    } else {
+                        if (duration) {
+                            logLine("Signal glSnoop task %p with signal %d", mainTask, mainSig);
+                            IExec->Signal(mainTask, 1L << mainSig);
+                        }
+                    }
                 }
             } else {
                 logAlways("Cannot allocate memory for NOVA context data: cannot patch");
@@ -2999,9 +3010,10 @@ static W3DN_Context* my_W3DN_CreateContext(struct Warp3DNovaIFace *Self, W3DN_Er
 
 GENERATE_PATCH(Warp3DNovaIFace, W3DN_CreateContext, my, ContextCreation)
 
-void warp3dnova_install_patches(ULONG startTimeInSeconds)
+void warp3dnova_install_patches(ULONG startTimeInSeconds, ULONG durationTimeInSeconds)
 {
     startTime = startTimeInSeconds;
+    duration = durationTimeInSeconds;
 
     mutex = IExec->AllocSysObject(ASOT_MUTEX, TAG_DONE);
 
diff --git a/warp3dnova_module.h b/warp3dnova_module.h
index 1b6e985..bb8d369 100644
--- a/warp3dnova_module.h
+++ b/warp3dnova_module.h
@@ -3,7 +3,7 @@
 
 #include <exec/types.h>
 
-void warp3dnova_install_patches(ULONG startTimeInSeconds);
+void warp3dnova_install_patches(ULONG startTimeInSeconds, ULONG durationTimeInSeconds);
 void warp3dnova_remove_patches(void);
 void warp3dnova_free(void);