From 73fd8884e4e2d7e66911f13767d7b7bb184d0081 Mon Sep 17 00:00:00 2001
From: Jeffrey Lee <jlee@gitlab.riscosopen.org>
Date: Sun, 10 Jun 2018 22:59:58 +0000
Subject: [PATCH] Try and avoid blocking callbacks

Detail:
  The kernel has a 'callback postponement flag' which will be set whenever an X SWI, called from user mode, returns a pointer to an error (and the error block looks like it's in RAM).
  Although this flag will help prevent the error buffer from being overwritten by any errors generated by callbacks, it will also have the effect of blocking Alt-Break and CLib's Escape handler, due to them both being reliant on callbacks.
  Since the flag may persist for a long time, it can be dangerous to leave the OS in this state (the flag can only be cleared by a SWI call from user mode - which may never happen if the program is stuck in a bad state).
  So to combat this, CLib will now make some effort to try and avoid leaving the postponement flag in situations where it shouldn't be needed.
  File changes:
  - c/armsys:
    - Change _sys_flen to return 0 for TTY streams, since calling OS_Args for them isn't going to generate any useful result (previously it was generating an error, causing the postponement flag to be left set on entry to main())
    - Be extra vigilant when entering main() to make sure the callback postponement flag isn't set, just in case other checks don't resolve it
  - kernel/s/k_body:
    - Change CopyError to attempt to clear the callback postponement flag if we suspect it's set. We've just copied the error to our own buffer, so it should be our job to worry about preventing that buffer being prematurely overwritten, not the kernel's.
Admin:
  Tested on BB-xM
  'while (1) {}' (and similar variants) now multitasks in task windows and is no longer unkillable
  Fixes issue reported on forums:
  https://www.riscosopen.org/forum/forums/4/topics/11542#posts-79767


Version 5.96. Tagged as 'RISC_OSLib-5_96'
---
 VersionASM      | 12 ++++++------
 VersionNum      | 20 ++++++++++----------
 c/armsys        |  4 ++++
 kernel/s/k_body | 19 +++++++++++++++++++
 4 files changed, 39 insertions(+), 16 deletions(-)

diff --git a/VersionASM b/VersionASM
index 84b80dc..068e314 100644
--- a/VersionASM
+++ b/VersionASM
@@ -11,13 +11,13 @@
                         GBLS    Module_HelpVersion
                         GBLS    Module_ComponentName
                         GBLS    Module_ComponentPath
-Module_MajorVersion     SETS    "5.95"
-Module_Version          SETA    595
+Module_MajorVersion     SETS    "5.96"
+Module_Version          SETA    596
 Module_MinorVersion     SETS    ""
-Module_Date             SETS    "14 Apr 2018"
-Module_ApplicationDate  SETS    "14-Apr-18"
+Module_Date             SETS    "10 Jun 2018"
+Module_ApplicationDate  SETS    "10-Jun-18"
 Module_ComponentName    SETS    "RISC_OSLib"
 Module_ComponentPath    SETS    "castle/RiscOS/Sources/Lib/RISC_OSLib"
-Module_FullVersion      SETS    "5.95"
-Module_HelpVersion      SETS    "5.95 (14 Apr 2018)"
+Module_FullVersion      SETS    "5.96"
+Module_HelpVersion      SETS    "5.96 (10 Jun 2018)"
                         END
diff --git a/VersionNum b/VersionNum
index 73aa5b2..fa3214d 100644
--- a/VersionNum
+++ b/VersionNum
@@ -1,23 +1,23 @@
-/* (5.95)
+/* (5.96)
  *
  * This file is automatically maintained by srccommit, do not edit manually.
  * Last processed by srccommit version: 1.1.
  *
  */
-#define Module_MajorVersion_CMHG        5.95
+#define Module_MajorVersion_CMHG        5.96
 #define Module_MinorVersion_CMHG        
-#define Module_Date_CMHG                14 Apr 2018
+#define Module_Date_CMHG                10 Jun 2018
 
-#define Module_MajorVersion             "5.95"
-#define Module_Version                  595
+#define Module_MajorVersion             "5.96"
+#define Module_Version                  596
 #define Module_MinorVersion             ""
-#define Module_Date                     "14 Apr 2018"
+#define Module_Date                     "10 Jun 2018"
 
-#define Module_ApplicationDate          "14-Apr-18"
+#define Module_ApplicationDate          "10-Jun-18"
 
 #define Module_ComponentName            "RISC_OSLib"
 #define Module_ComponentPath            "castle/RiscOS/Sources/Lib/RISC_OSLib"
 
-#define Module_FullVersion              "5.95"
-#define Module_HelpVersion              "5.95 (14 Apr 2018)"
-#define Module_LibraryVersionInfo       "5:95"
+#define Module_FullVersion              "5.96"
+#define Module_HelpVersion              "5.96 (10 Jun 2018)"
+#define Module_LibraryVersionInfo       "5:96"
diff --git a/c/armsys b/c/armsys
index 776c0f5..4f3c6a7 100644
--- a/c/armsys
+++ b/c/armsys
@@ -395,6 +395,7 @@ int _sys_seek(FILEHANDLE fh, off64_t pos)
 
 off64_t _sys_flen(FILEHANDLE fh)
 {
+    if istty(fh) return 0;
 #if 1
     /* Can't use _kernel_osargs, even for 32-bit file pointers, because it can't handle files of size 4G-2 .*/
     /* Use _kernel_swi instead so that _kernel_last_oserror is set up on failure like it always was. */
@@ -866,6 +867,9 @@ no_redirection:
         exit(EXIT_FAILURE);
     }
 
+    /* Clear any callback postponement flag in the kernel - otherwise programs which execute no SWIs may be completely uninterruptible */
+    _swix(OS_IntOn,0);
+
     argv[argc] = 0;      /* for ANSI spec */
     exit(/* hmm, relies on lots of things, but fast! */
          (argc > 0 && (*(int *)argv[0] & ~0x20202020) == *(int *)"RUN") ?
diff --git a/kernel/s/k_body b/kernel/s/k_body
index b56cac3..b3f0c34 100644
--- a/kernel/s/k_body
+++ b/kernel/s/k_body
@@ -2512,7 +2512,26 @@ CopyErrorString
         STRB    a3, [a2], #+1
         BICS    a3, a3, #&1F            ; replaces CMP a3, #' '
         BNE     %B01                    ; replaces BCS %B01
+        ; We're probably here because a SWI returned an error. This probably
+        ; also means that the kernel has set the callback postponement flag -
+        ; a flag designed to prevent global error buffers being clobbered by
+        ; callbacks. However we've just copied the error into our own private
+        ; buffer, so there's no need for the kernel to postpone callbacks. In
+        ; fact, postponing callbacks can be harmful, potentially preventing the
+        ; user from quitting a malfunctioning app, due to both CLib's Escape
+        ; handler and Alt-Break being reliant on callbacks. So if we're in user
+        ; mode, do a dummy SWI to clear the postponement flag.
+ [ {CONFIG} = 26
+        TST     lr, #PSRIBit+PSRPrivileged
+        SWIEQ   XOS_IntOn
+        MOVS    pc, lr
+ |
+        MRS     a3, CPSR
+        TST     a3, #PSR32IBit+PSR32Privileged
+        SWIEQ   XOS_IntOn
+        MSR     CPSR_c, a3
         MOV     pc, lr
+ ]
 
 |_kernel_getenv|
 ; _kernel_oserror *_kernel_getenv(const char *name, char *buffer, unsigned size);
-- 
GitLab