emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/android 674373bed86 1/2: Prevent hangs from IM requests with the


From: Po Lu
Subject: feature/android 674373bed86 1/2: Prevent hangs from IM requests with the main thread busy
Date: Fri, 9 Jun 2023 21:25:28 -0400 (EDT)

branch: feature/android
commit 674373bed8632093ab8ed118618b05e085ffd5cd
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Prevent hangs from IM requests with the main thread busy
    
    * src/android.c (android_select): Clear `android_urgent_query'.
    (android_check_query): Make static.  Clear
    `android_urgent_query'.
    (android_check_query_urgent): New function; work like
    `android_check_query', but only answer urgent queries.
    (android_answer_query, android_end_query): Clear urgent query
    flag.
    (android_run_in_emacs_thread): Initially wait two seconds for
    the query to run from the keyboard loop; upon a timeout, set
    `android_urgent_query' to true and wait for it to run while
    reading async input.
    * src/android.h: Update prototypes.
    * src/keyboard.c (handle_async_input): Call
    `android_check_query_urgent'.
---
 src/android.c  | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 src/android.h  |   2 +-
 src/keyboard.c |  14 ++++++-
 3 files changed, 123 insertions(+), 6 deletions(-)

diff --git a/src/android.c b/src/android.c
index f45e0abbea6..cfc777c3caa 100644
--- a/src/android.c
+++ b/src/android.c
@@ -29,6 +29,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <math.h>
 #include <string.h>
 #include <stdckdint.h>
+#include <timespec.h>
 
 #include <sys/stat.h>
 #include <sys/mman.h>
@@ -693,6 +694,17 @@ android_write_event (union android_event *event)
     }
 }
 
+
+
+/* Whether or not the UI thread has been waiting for a significant
+   amount of time for a function to run in the main thread, and Emacs
+   should answer the query ASAP.  */
+static bool android_urgent_query;
+
+/* Forward declaration.  */
+
+static void android_check_query (void);
+
 int
 android_select (int nfds, fd_set *readfds, fd_set *writefds,
                fd_set *exceptfds, struct timespec *timeout)
@@ -702,6 +714,11 @@ android_select (int nfds, fd_set *readfds, fd_set 
*writefds,
   static char byte;
 #endif
 
+  /* Since Emacs is reading keyboard input again, signify that queries
+     from input methods are no longer ``urgent''.  */
+
+  __atomic_clear (&android_urgent_query, __ATOMIC_SEQ_CST);
+
   /* Check for and run anything the UI thread wants to run on the main
      thread.  */
   android_check_query ();
@@ -7066,7 +7083,7 @@ static void *android_query_context;
 /* Run any function that the UI thread has asked to run, and then
    signal its completion.  */
 
-void
+static void
 android_check_query (void)
 {
   void (*proc) (void *);
@@ -7088,6 +7105,49 @@ android_check_query (void)
   __atomic_store_n (&android_query_context, NULL, __ATOMIC_SEQ_CST);
   __atomic_store_n (&android_query_function, NULL, __ATOMIC_SEQ_CST);
   __atomic_store_n (&android_servicing_query, 0, __ATOMIC_SEQ_CST);
+  __atomic_clear (&android_urgent_query, __ATOMIC_SEQ_CST);
+
+  /* Signal completion.  */
+  sem_post (&android_query_sem);
+}
+
+/* Run any function that the UI thread has asked to run, if the UI
+   thread has been waiting for more than two seconds.
+
+   Call this from `process_pending_signals' to ensure that the UI
+   thread always receives an answer within a reasonable amount of
+   time.  */
+
+void
+android_check_query_urgent (void)
+{
+  void (*proc) (void *);
+  void *closure;
+
+  if (!__atomic_load_n (&android_urgent_query, __ATOMIC_SEQ_CST))
+    return;
+
+  __android_log_print (ANDROID_LOG_VERBOSE, __func__,
+              "Responding to urgent query...");
+
+  if (!__atomic_load_n (&android_servicing_query, __ATOMIC_SEQ_CST))
+    return;
+
+  /* First, load the procedure and closure.  */
+  __atomic_load (&android_query_context, &closure, __ATOMIC_SEQ_CST);
+  __atomic_load (&android_query_function, &proc, __ATOMIC_SEQ_CST);
+
+  if (!proc)
+    return;
+
+  proc (closure);
+
+  /* Finish the query.  Don't clear `android_urgent_query'; instead,
+     do that the next time Emacs enters the keyboard loop.  */
+
+  __atomic_store_n (&android_query_context, NULL, __ATOMIC_SEQ_CST);
+  __atomic_store_n (&android_query_function, NULL, __ATOMIC_SEQ_CST);
+  __atomic_store_n (&android_servicing_query, 0, __ATOMIC_SEQ_CST);
 
   /* Signal completion.  */
   sem_post (&android_query_sem);
@@ -7118,6 +7178,7 @@ android_answer_query (void)
   /* Finish the query.  */
   __atomic_store_n (&android_query_context, NULL, __ATOMIC_SEQ_CST);
   __atomic_store_n (&android_query_function, NULL, __ATOMIC_SEQ_CST);
+  __atomic_clear (&android_urgent_query, __ATOMIC_SEQ_CST);
 
   /* Signal completion.  */
   sem_post (&android_query_sem);
@@ -7175,6 +7236,7 @@ static void
 android_end_query (void)
 {
   __atomic_store_n (&android_servicing_query, 0, __ATOMIC_SEQ_CST);
+  __atomic_clear (&android_urgent_query, __ATOMIC_SEQ_CST);
 }
 
 /* Synchronously ask the Emacs thread to run the specified PROC with
@@ -7193,6 +7255,8 @@ android_run_in_emacs_thread (void (*proc) (void *), void 
*closure)
 {
   union android_event event;
   char old;
+  int rc;
+  struct timespec timeout;
 
   event.xaction.type = ANDROID_WINDOW_ACTION;
   event.xaction.serial = ++event_serial;
@@ -7227,9 +7291,50 @@ android_run_in_emacs_thread (void (*proc) (void *), void 
*closure)
      time it is entered.  */
   android_write_event (&event);
 
-  /* Start waiting for the function to be executed.  */
-  while (sem_wait (&android_query_sem) < 0)
-    ;;
+  /* Start waiting for the function to be executed.  First, wait two
+     seconds for the query to execute normally.  */
+
+  timeout.tv_sec = 2;
+  timeout.tv_nsec = 0;
+  timeout = timespec_add (current_timespec (), timeout);
+
+  /* See if an urgent query was recently answered without entering the
+     keyboard loop in between.  When that happens, raise SIGIO to
+     continue processing queries as soon as possible.  */
+
+  if (__atomic_load_n (&android_urgent_query, __ATOMIC_SEQ_CST))
+    raise (SIGIO);
+
+ again:
+  rc = sem_timedwait (&android_query_sem, &timeout);
+
+  if (rc < 0)
+    {
+      if (errno == EINTR)
+       goto again;
+
+      eassert (errno == ETIMEDOUT);
+
+      __android_log_print (ANDROID_LOG_VERBOSE, __func__,
+                          "Timed out waiting for response"
+                          " from main thread...");
+
+      /* The query timed out.  At this point, set
+        `android_urgent_query' to true.  */
+      __atomic_store_n (&android_urgent_query, true, __ATOMIC_SEQ_CST);
+
+      /* And raise SIGIO.  Now that the query is considered urgent,
+        the main thread will reply while reading async input.
+
+        Normally, the main thread waits for the keyboard loop to be
+        entered before responding, in order to avoid responding with
+        inaccurate results taken during command executioon.  */
+      raise (SIGIO);
+
+      /* Wait for the query to complete.  */
+      while (sem_wait (&android_query_sem) < 0)
+       ;;
+    }
 
   /* At this point, `android_servicing_query' should either be zero if
      the query was answered or two if the main thread has started a
diff --git a/src/android.h b/src/android.h
index c748d99a09a..8634ba01a3d 100644
--- a/src/android.h
+++ b/src/android.h
@@ -185,7 +185,7 @@ extern void android_display_toast (const char *);
 
 /* Event loop functions.  */
 
-extern void android_check_query (void);
+extern void android_check_query_urgent (void);
 extern int android_run_in_emacs_thread (void (*) (void *), void *);
 extern void android_write_event (union android_event *);
 
diff --git a/src/keyboard.c b/src/keyboard.c
index f31f717195b..523718cdbaa 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -47,7 +47,11 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 
 #ifdef HAVE_TEXT_CONVERSION
 #include "textconv.h"
-#endif
+#endif /* HAVE_TEXT_CONVERSION */
+
+#ifdef HAVE_ANDROID
+#include "android.h"
+#endif /* HAVE_ANDROID */
 
 #include <errno.h>
 
@@ -7906,6 +7910,14 @@ tty_read_avail_input (struct terminal *terminal,
 static void
 handle_async_input (void)
 {
+#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
+  /* Check and respond to an ``urgent'' query from the UI thread.
+     A query becomes urgent once the UI thread has been waiting
+     for more than two seconds.  */
+
+  android_check_query_urgent ();
+#endif /* HAVE_ANDROID && !ANDROID_STUBIFY */
+
 #ifndef DOS_NT
   while (1)
     {



reply via email to

[Prev in Thread] Current Thread [Next in Thread]