## along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
set -m
+set -x
oldpwd=`pwd`
cd `dirname $0`
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
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. */
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
\f
-/* 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 *);
/* 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);
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
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
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;
__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);
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;
}