aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2023-06-10 09:21:48 +0800
committerPo Lu2023-06-10 09:21:48 +0800
commit674373bed8632093ab8ed118618b05e085ffd5cd (patch)
treebcdc1ed05206c423c8746ea593bee52560542030 /src
parent8cbe35a84621edf4dd7cc71d6a6ae7e55699fc5a (diff)
downloademacs-674373bed8632093ab8ed118618b05e085ffd5cd.tar.gz
emacs-674373bed8632093ab8ed118618b05e085ffd5cd.zip
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'.
Diffstat (limited to 'src')
-rw-r--r--src/android.c113
-rw-r--r--src/android.h2
-rw-r--r--src/keyboard.c14
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/>. */
29#include <math.h> 29#include <math.h>
30#include <string.h> 30#include <string.h>
31#include <stdckdint.h> 31#include <stdckdint.h>
32#include <timespec.h>
32 33
33#include <sys/stat.h> 34#include <sys/stat.h>
34#include <sys/mman.h> 35#include <sys/mman.h>
@@ -693,6 +694,17 @@ android_write_event (union android_event *event)
693 } 694 }
694} 695}
695 696
697
698
699/* Whether or not the UI thread has been waiting for a significant
700 amount of time for a function to run in the main thread, and Emacs
701 should answer the query ASAP. */
702static bool android_urgent_query;
703
704/* Forward declaration. */
705
706static void android_check_query (void);
707
696int 708int
697android_select (int nfds, fd_set *readfds, fd_set *writefds, 709android_select (int nfds, fd_set *readfds, fd_set *writefds,
698 fd_set *exceptfds, struct timespec *timeout) 710 fd_set *exceptfds, struct timespec *timeout)
@@ -702,6 +714,11 @@ android_select (int nfds, fd_set *readfds, fd_set *writefds,
702 static char byte; 714 static char byte;
703#endif 715#endif
704 716
717 /* Since Emacs is reading keyboard input again, signify that queries
718 from input methods are no longer ``urgent''. */
719
720 __atomic_clear (&android_urgent_query, __ATOMIC_SEQ_CST);
721
705 /* Check for and run anything the UI thread wants to run on the main 722 /* Check for and run anything the UI thread wants to run on the main
706 thread. */ 723 thread. */
707 android_check_query (); 724 android_check_query ();
@@ -7066,7 +7083,7 @@ static void *android_query_context;
7066/* Run any function that the UI thread has asked to run, and then 7083/* Run any function that the UI thread has asked to run, and then
7067 signal its completion. */ 7084 signal its completion. */
7068 7085
7069void 7086static void
7070android_check_query (void) 7087android_check_query (void)
7071{ 7088{
7072 void (*proc) (void *); 7089 void (*proc) (void *);
@@ -7088,6 +7105,49 @@ android_check_query (void)
7088 __atomic_store_n (&android_query_context, NULL, __ATOMIC_SEQ_CST); 7105 __atomic_store_n (&android_query_context, NULL, __ATOMIC_SEQ_CST);
7089 __atomic_store_n (&android_query_function, NULL, __ATOMIC_SEQ_CST); 7106 __atomic_store_n (&android_query_function, NULL, __ATOMIC_SEQ_CST);
7090 __atomic_store_n (&android_servicing_query, 0, __ATOMIC_SEQ_CST); 7107 __atomic_store_n (&android_servicing_query, 0, __ATOMIC_SEQ_CST);
7108 __atomic_clear (&android_urgent_query, __ATOMIC_SEQ_CST);
7109
7110 /* Signal completion. */
7111 sem_post (&android_query_sem);
7112}
7113
7114/* Run any function that the UI thread has asked to run, if the UI
7115 thread has been waiting for more than two seconds.
7116
7117 Call this from `process_pending_signals' to ensure that the UI
7118 thread always receives an answer within a reasonable amount of
7119 time. */
7120
7121void
7122android_check_query_urgent (void)
7123{
7124 void (*proc) (void *);
7125 void *closure;
7126
7127 if (!__atomic_load_n (&android_urgent_query, __ATOMIC_SEQ_CST))
7128 return;
7129
7130 __android_log_print (ANDROID_LOG_VERBOSE, __func__,
7131 "Responding to urgent query...");
7132
7133 if (!__atomic_load_n (&android_servicing_query, __ATOMIC_SEQ_CST))
7134 return;
7135
7136 /* First, load the procedure and closure. */
7137 __atomic_load (&android_query_context, &closure, __ATOMIC_SEQ_CST);
7138 __atomic_load (&android_query_function, &proc, __ATOMIC_SEQ_CST);
7139
7140 if (!proc)
7141 return;
7142
7143 proc (closure);
7144
7145 /* Finish the query. Don't clear `android_urgent_query'; instead,
7146 do that the next time Emacs enters the keyboard loop. */
7147
7148 __atomic_store_n (&android_query_context, NULL, __ATOMIC_SEQ_CST);
7149 __atomic_store_n (&android_query_function, NULL, __ATOMIC_SEQ_CST);
7150 __atomic_store_n (&android_servicing_query, 0, __ATOMIC_SEQ_CST);
7091 7151
7092 /* Signal completion. */ 7152 /* Signal completion. */
7093 sem_post (&android_query_sem); 7153 sem_post (&android_query_sem);
@@ -7118,6 +7178,7 @@ android_answer_query (void)
7118 /* Finish the query. */ 7178 /* Finish the query. */
7119 __atomic_store_n (&android_query_context, NULL, __ATOMIC_SEQ_CST); 7179 __atomic_store_n (&android_query_context, NULL, __ATOMIC_SEQ_CST);
7120 __atomic_store_n (&android_query_function, NULL, __ATOMIC_SEQ_CST); 7180 __atomic_store_n (&android_query_function, NULL, __ATOMIC_SEQ_CST);
7181 __atomic_clear (&android_urgent_query, __ATOMIC_SEQ_CST);
7121 7182
7122 /* Signal completion. */ 7183 /* Signal completion. */
7123 sem_post (&android_query_sem); 7184 sem_post (&android_query_sem);
@@ -7175,6 +7236,7 @@ static void
7175android_end_query (void) 7236android_end_query (void)
7176{ 7237{
7177 __atomic_store_n (&android_servicing_query, 0, __ATOMIC_SEQ_CST); 7238 __atomic_store_n (&android_servicing_query, 0, __ATOMIC_SEQ_CST);
7239 __atomic_clear (&android_urgent_query, __ATOMIC_SEQ_CST);
7178} 7240}
7179 7241
7180/* Synchronously ask the Emacs thread to run the specified PROC with 7242/* 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)
7193{ 7255{
7194 union android_event event; 7256 union android_event event;
7195 char old; 7257 char old;
7258 int rc;
7259 struct timespec timeout;
7196 7260
7197 event.xaction.type = ANDROID_WINDOW_ACTION; 7261 event.xaction.type = ANDROID_WINDOW_ACTION;
7198 event.xaction.serial = ++event_serial; 7262 event.xaction.serial = ++event_serial;
@@ -7227,9 +7291,50 @@ android_run_in_emacs_thread (void (*proc) (void *), void *closure)
7227 time it is entered. */ 7291 time it is entered. */
7228 android_write_event (&event); 7292 android_write_event (&event);
7229 7293
7230 /* Start waiting for the function to be executed. */ 7294 /* Start waiting for the function to be executed. First, wait two
7231 while (sem_wait (&android_query_sem) < 0) 7295 seconds for the query to execute normally. */
7232 ;; 7296
7297 timeout.tv_sec = 2;
7298 timeout.tv_nsec = 0;
7299 timeout = timespec_add (current_timespec (), timeout);
7300
7301 /* See if an urgent query was recently answered without entering the
7302 keyboard loop in between. When that happens, raise SIGIO to
7303 continue processing queries as soon as possible. */
7304
7305 if (__atomic_load_n (&android_urgent_query, __ATOMIC_SEQ_CST))
7306 raise (SIGIO);
7307
7308 again:
7309 rc = sem_timedwait (&android_query_sem, &timeout);
7310
7311 if (rc < 0)
7312 {
7313 if (errno == EINTR)
7314 goto again;
7315
7316 eassert (errno == ETIMEDOUT);
7317
7318 __android_log_print (ANDROID_LOG_VERBOSE, __func__,
7319 "Timed out waiting for response"
7320 " from main thread...");
7321
7322 /* The query timed out. At this point, set
7323 `android_urgent_query' to true. */
7324 __atomic_store_n (&android_urgent_query, true, __ATOMIC_SEQ_CST);
7325
7326 /* And raise SIGIO. Now that the query is considered urgent,
7327 the main thread will reply while reading async input.
7328
7329 Normally, the main thread waits for the keyboard loop to be
7330 entered before responding, in order to avoid responding with
7331 inaccurate results taken during command executioon. */
7332 raise (SIGIO);
7333
7334 /* Wait for the query to complete. */
7335 while (sem_wait (&android_query_sem) < 0)
7336 ;;
7337 }
7233 7338
7234 /* At this point, `android_servicing_query' should either be zero if 7339 /* At this point, `android_servicing_query' should either be zero if
7235 the query was answered or two if the main thread has started a 7340 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 *);
185 185
186/* Event loop functions. */ 186/* Event loop functions. */
187 187
188extern void android_check_query (void); 188extern void android_check_query_urgent (void);
189extern int android_run_in_emacs_thread (void (*) (void *), void *); 189extern int android_run_in_emacs_thread (void (*) (void *), void *);
190extern void android_write_event (union android_event *); 190extern void android_write_event (union android_event *);
191 191
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/>. */
47 47
48#ifdef HAVE_TEXT_CONVERSION 48#ifdef HAVE_TEXT_CONVERSION
49#include "textconv.h" 49#include "textconv.h"
50#endif 50#endif /* HAVE_TEXT_CONVERSION */
51
52#ifdef HAVE_ANDROID
53#include "android.h"
54#endif /* HAVE_ANDROID */
51 55
52#include <errno.h> 56#include <errno.h>
53 57
@@ -7906,6 +7910,14 @@ tty_read_avail_input (struct terminal *terminal,
7906static void 7910static void
7907handle_async_input (void) 7911handle_async_input (void)
7908{ 7912{
7913#if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
7914 /* Check and respond to an ``urgent'' query from the UI thread.
7915 A query becomes urgent once the UI thread has been waiting
7916 for more than two seconds. */
7917
7918 android_check_query_urgent ();
7919#endif /* HAVE_ANDROID && !ANDROID_STUBIFY */
7920
7909#ifndef DOS_NT 7921#ifndef DOS_NT
7910 while (1) 7922 while (1)
7911 { 7923 {