Update Android port
* java/debug.sh (is_root): Go back to using unix sockets; allow adb to forward them correctly. * java/org/gnu/emacs/EmacsInputConnection.java (getExtractedText): Don't print text if NULL. * java/org/gnu/emacs/EmacsService.java (EmacsService): New field `imSyncInProgress'. (updateIC): If an IM sync might be in progress, avoid deadlocks. * java/org/gnu/emacs/EmacsView.java (onCreateInputConnection): Set `imSyncInProgress' across synchronization point. * src/android.c (android_check_query): Use __atomic_store_n. (android_answer_query): New function. (android_begin_query): Set `android_servicing_query' to 2. Check once, and don't spin waiting for query to complete. (android_end_query): Use __atomic_store_n. (android_run_in_emacs_thread): Compare-and-exchange flag. If originally 1, fail. * src/textconv.c (really_set_composing_text): Clear conversion region if text is empty.
This commit is contained in:
parent
733a6776f9
commit
57903519eb
6 changed files with 126 additions and 22 deletions
|
@ -19,6 +19,7 @@
|
|||
## along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
set -m
|
||||
set -x
|
||||
oldpwd=`pwd`
|
||||
cd `dirname $0`
|
||||
|
||||
|
@ -310,22 +311,26 @@ rm -f /tmp/file-descriptor-stamp
|
|||
|
||||
if [ -z "$gdbserver" ]; then
|
||||
if [ "$is_root" = "yes" ]; then
|
||||
adb -s $device shell $gdbserver_bin --once \
|
||||
adb -s $device shell $gdbserver_bin --multi \
|
||||
"+/data/local/tmp/debug.$package.socket" --attach $pid >&5 &
|
||||
gdb_socket="localfilesystem:/data/local/tmp/debug.$package.socket"
|
||||
else
|
||||
adb -s $device shell run-as $package $gdbserver_bin --once \
|
||||
else
|
||||
adb -s $device shell run-as $package $gdbserver_bin --multi \
|
||||
"+debug.$package.socket" --attach $pid >&5 &
|
||||
gdb_socket="localfilesystem:$app_data_dir/debug.$package.socket"
|
||||
fi
|
||||
else
|
||||
# Normally the program cannot access $gdbserver_bin when it is
|
||||
# placed in /data/local/tmp.
|
||||
adb -s $device shell run-as $package $gdbserver_cmd --once \
|
||||
"0.0.0.0:7654" --attach $pid >&5 &
|
||||
gdb_socket="tcp:7654"
|
||||
adb -s $device shell run-as $package $gdbserver_cmd --multi \
|
||||
"+debug.$package.socket" --attach $pid >&5 &
|
||||
gdb_socket="localfilesystem:$app_data_dir/debug.$package.socket"
|
||||
fi
|
||||
|
||||
# In order to allow adb to forward to the gdbserver socket, make the
|
||||
# app data directory a+x.
|
||||
adb -s $device shell run-as $package chmod a+x $app_data_dir
|
||||
|
||||
# Wait until gdbserver successfully runs.
|
||||
line=
|
||||
while read -u 5 line; do
|
||||
|
|
|
@ -286,6 +286,14 @@ public final class EmacsInputConnection extends BaseInputConnection
|
|||
text = EmacsNative.getExtractedText (windowHandle, request,
|
||||
flags);
|
||||
|
||||
if (text == null)
|
||||
{
|
||||
if (EmacsService.DEBUG_IC)
|
||||
Log.d (TAG, "getExtractedText: text is NULL");
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (EmacsService.DEBUG_IC)
|
||||
Log.d (TAG, "getExtractedText: " + text.text + " @"
|
||||
+ text.startOffset + ":" + text.selectionStart
|
||||
|
|
|
@ -104,6 +104,9 @@ public final class EmacsService extends Service
|
|||
performing drawing calls. */
|
||||
private static final boolean DEBUG_THREADS = false;
|
||||
|
||||
/* Whether or not onCreateInputMethod is calling getSelection. */
|
||||
public static volatile boolean imSyncInProgress;
|
||||
|
||||
/* Return the directory leading to the directory in which native
|
||||
library files are stored on behalf of CONTEXT. */
|
||||
|
||||
|
@ -636,16 +639,41 @@ invocation of app_process (through android-emacs) can
|
|||
int newSelectionEnd, int composingRegionStart,
|
||||
int composingRegionEnd)
|
||||
{
|
||||
boolean wasSynchronous;
|
||||
|
||||
if (DEBUG_IC)
|
||||
Log.d (TAG, ("updateIC: " + window + " " + newSelectionStart
|
||||
+ " " + newSelectionEnd + " "
|
||||
+ composingRegionStart + " "
|
||||
+ composingRegionEnd));
|
||||
|
||||
/* `updateSelection' holds an internal lock that is also taken
|
||||
before `onCreateInputConnection' (in EmacsView.java) is called;
|
||||
when that then asks the UI thread for the current selection, a
|
||||
dead lock results. To remedy this, reply to any synchronous
|
||||
queries now -- and prohibit more queries for the duration of
|
||||
`updateSelection' -- if EmacsView may have been asking for the
|
||||
value of the region. */
|
||||
|
||||
wasSynchronous = false;
|
||||
if (EmacsService.imSyncInProgress)
|
||||
{
|
||||
/* `beginSynchronous' will answer any outstanding queries and
|
||||
signal that one is now in progress, thereby preventing
|
||||
`getSelection' from blocking. */
|
||||
|
||||
EmacsNative.beginSynchronous ();
|
||||
wasSynchronous = true;
|
||||
}
|
||||
|
||||
window.view.imManager.updateSelection (window.view,
|
||||
newSelectionStart,
|
||||
newSelectionEnd,
|
||||
composingRegionStart,
|
||||
composingRegionEnd);
|
||||
|
||||
if (wasSynchronous)
|
||||
EmacsNative.endSynchronous ();
|
||||
}
|
||||
|
||||
public void
|
||||
|
|
|
@ -628,8 +628,14 @@ else if (child.getVisibility () != GONE)
|
|||
}
|
||||
|
||||
/* Obtain the current position of point and set it as the
|
||||
selection. */
|
||||
selection. Don't do this under one specific situation: if
|
||||
`android_update_ic' is being called in the main thread, trying
|
||||
to synchronize with it can cause a dead lock in the IM
|
||||
manager. */
|
||||
|
||||
EmacsService.imSyncInProgress = true;
|
||||
selection = EmacsNative.getSelection (window.handle);
|
||||
EmacsService.imSyncInProgress = false;
|
||||
|
||||
if (selection != null)
|
||||
Log.d (TAG, "onCreateInputConnection: current selection is: "
|
||||
|
|
|
@ -6959,8 +6959,11 @@ android_display_toast (const char *text)
|
|||
|
||||
|
||||
|
||||
/* Whether or not a query is currently being made. */
|
||||
static bool android_servicing_query;
|
||||
/* The thread from which a query against a thread is currently being
|
||||
made, if any. Value is 0 if no query is in progress, 1 if a query
|
||||
is being made from the UI thread to the main thread, and 2 if a
|
||||
query is being made the other way around. */
|
||||
static char android_servicing_query;
|
||||
|
||||
/* Function that is waiting to be run in the Emacs thread. */
|
||||
static void (*android_query_function) (void *);
|
||||
|
@ -7010,7 +7013,37 @@ android_check_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_servicing_query, __ATOMIC_SEQ_CST);
|
||||
__atomic_store_n (&android_servicing_query, 0, __ATOMIC_SEQ_CST);
|
||||
|
||||
/* Signal completion. */
|
||||
sem_post (&android_query_sem);
|
||||
}
|
||||
|
||||
/* Run the function that the UI thread has asked to run, and then
|
||||
signal its completion. Do not change `android_servicing_query'
|
||||
after it completes. */
|
||||
|
||||
static void
|
||||
android_answer_query (void)
|
||||
{
|
||||
void (*proc) (void *);
|
||||
void *closure;
|
||||
|
||||
eassert (__atomic_load_n (&android_servicing_query, __ATOMIC_SEQ_CST)
|
||||
== 1);
|
||||
|
||||
/* 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. */
|
||||
__atomic_store_n (&android_query_context, NULL, __ATOMIC_SEQ_CST);
|
||||
__atomic_store_n (&android_query_function, NULL, __ATOMIC_SEQ_CST);
|
||||
|
||||
/* Signal completion. */
|
||||
sem_post (&android_query_sem);
|
||||
|
@ -7025,18 +7058,23 @@ android_check_query (void)
|
|||
static void
|
||||
android_begin_query (void)
|
||||
{
|
||||
if (__atomic_test_and_set (&android_servicing_query,
|
||||
__ATOMIC_SEQ_CST))
|
||||
char old;
|
||||
|
||||
/* Load the previous value of `android_servicing_query' and upgrade
|
||||
it to 2. */
|
||||
|
||||
old = __atomic_exchange_n (&android_servicing_query,
|
||||
2, __ATOMIC_SEQ_CST);
|
||||
|
||||
/* See if a query was previously in progress. */
|
||||
if (old == 1)
|
||||
{
|
||||
/* Answer the query that is currently being made. */
|
||||
assert (android_query_function != NULL);
|
||||
android_check_query ();
|
||||
|
||||
/* Wait for that query to complete. */
|
||||
while (__atomic_load_n (&android_servicing_query,
|
||||
__ATOMIC_SEQ_CST))
|
||||
;;
|
||||
android_answer_query ();
|
||||
}
|
||||
|
||||
/* `android_servicing_query' is now 2. */
|
||||
}
|
||||
|
||||
/* Notice that a query has stopped. This function may be called from
|
||||
|
@ -7045,7 +7083,7 @@ android_begin_query (void)
|
|||
static void
|
||||
android_end_query (void)
|
||||
{
|
||||
__atomic_clear (&android_servicing_query, __ATOMIC_SEQ_CST);
|
||||
__atomic_store_n (&android_servicing_query, 0, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
|
||||
/* Synchronously ask the Emacs thread to run the specified PROC with
|
||||
|
@ -7063,6 +7101,7 @@ int
|
|||
android_run_in_emacs_thread (void (*proc) (void *), void *closure)
|
||||
{
|
||||
union android_event event;
|
||||
char old;
|
||||
|
||||
event.xaction.type = ANDROID_WINDOW_ACTION;
|
||||
event.xaction.serial = ++event_serial;
|
||||
|
@ -7074,10 +7113,13 @@ android_run_in_emacs_thread (void (*proc) (void *), void *closure)
|
|||
__atomic_store_n (&android_query_function, proc, __ATOMIC_SEQ_CST);
|
||||
|
||||
/* Don't allow deadlocks to happen; make sure the Emacs thread is
|
||||
not waiting for something to be done. */
|
||||
not waiting for something to be done (in that case,
|
||||
`android_query_context' is 2.) */
|
||||
|
||||
if (__atomic_test_and_set (&android_servicing_query,
|
||||
__ATOMIC_SEQ_CST))
|
||||
old = 0;
|
||||
if (!__atomic_compare_exchange_n (&android_servicing_query, &old,
|
||||
1, false, __ATOMIC_SEQ_CST,
|
||||
__ATOMIC_SEQ_CST))
|
||||
{
|
||||
__atomic_store_n (&android_query_context, NULL,
|
||||
__ATOMIC_SEQ_CST);
|
||||
|
@ -7098,6 +7140,15 @@ android_run_in_emacs_thread (void (*proc) (void *), void *closure)
|
|||
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
|
||||
query. */
|
||||
|
||||
eassert (!__atomic_load_n (&android_servicing_query,
|
||||
__ATOMIC_SEQ_CST)
|
||||
|| (__atomic_load_n (&android_servicing_query,
|
||||
__ATOMIC_SEQ_CST) == 2));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -792,6 +792,12 @@ really_set_composing_text (struct frame *f, ptrdiff_t position,
|
|||
/* Move the composition overlay. */
|
||||
sync_overlay (f);
|
||||
|
||||
/* If TEXT is empty, remove the composing region. This goes against
|
||||
the documentation, but is ultimately what programs expect. */
|
||||
|
||||
if (!SCHARS (text))
|
||||
really_finish_composing_text (f);
|
||||
|
||||
/* If PT hasn't changed, the conversion region definitely has.
|
||||
Otherwise, redisplay will update the input method instead. */
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue