diff options
| author | Po Lu | 2023-06-10 09:21:48 +0800 |
|---|---|---|
| committer | Po Lu | 2023-06-10 09:21:48 +0800 |
| commit | 674373bed8632093ab8ed118618b05e085ffd5cd (patch) | |
| tree | bcdc1ed05206c423c8746ea593bee52560542030 /src | |
| parent | 8cbe35a84621edf4dd7cc71d6a6ae7e55699fc5a (diff) | |
| download | emacs-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.c | 113 | ||||
| -rw-r--r-- | src/android.h | 2 | ||||
| -rw-r--r-- | 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/>. */ | |||
| 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. */ | ||
| 702 | static bool android_urgent_query; | ||
| 703 | |||
| 704 | /* Forward declaration. */ | ||
| 705 | |||
| 706 | static void android_check_query (void); | ||
| 707 | |||
| 696 | int | 708 | int |
| 697 | android_select (int nfds, fd_set *readfds, fd_set *writefds, | 709 | android_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 | ||
| 7069 | void | 7086 | static void |
| 7070 | android_check_query (void) | 7087 | android_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 | |||
| 7121 | void | ||
| 7122 | android_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 | |||
| 7175 | android_end_query (void) | 7236 | android_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 | ||
| 188 | extern void android_check_query (void); | 188 | extern void android_check_query_urgent (void); |
| 189 | extern int android_run_in_emacs_thread (void (*) (void *), void *); | 189 | extern int android_run_in_emacs_thread (void (*) (void *), void *); |
| 190 | extern void android_write_event (union android_event *); | 190 | extern 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, | |||
| 7906 | static void | 7910 | static void |
| 7907 | handle_async_input (void) | 7911 | handle_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 | { |