## along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
set -m
-set -x
oldpwd=`pwd`
cd `dirname $0`
gdbserver_cmd=
is_root=
if [ -z "$gdbserver" ]; then
- gdbserver_bin=/system/bin/gdbserver
+ gdbserver_bin=/system/bin/gdbserver64
else
gdbserver_bin=/data/local/tmp/gdbserver
gdbserver_cat="cat $gdbserver_bin | run-as $package sh -c \
if [ -z "$gdbserver" ]; then
if [ "$is_root" = "yes" ]; then
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"
+ "0.0.0.0:7564" --attach $pid >&5 &
+ gdb_socket="tcp:7564"
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"
+ adb -s $device shell $gdbserver_bin --multi \
+ "0.0.0.0:7564" --attach $pid >&5 &
+ gdb_socket="tcp:7564"
fi
else
# Normally the program cannot access $gdbserver_bin when it is
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
import android.graphics.Matrix;
import android.graphics.Point;
performing drawing calls. */
private static final boolean DEBUG_THREADS = false;
- /* Whether or not onCreateInputMethod is calling getSelection. */
- public static volatile boolean imSyncInProgress;
+ /* Atomic integer used for synchronization between
+ icBeginSynchronous/icEndSynchronous and viewGetSelection.
+
+ Value is 0 if no query is in progress, 1 if viewGetSelection is
+ being called, and 2 if icBeginSynchronous was called. */
+ public static final AtomicInteger servicingQuery;
+
+ static
+ {
+ servicingQuery = new AtomicInteger ();
+ };
/* Return the directory leading to the directory in which native
library files are stored on behalf of CONTEXT. */
EmacsNative.endSynchronous ();
}
+\f
+
+ /* IMM functions such as `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. */
+
+ public static void
+ icBeginSynchronous ()
+ {
+ /* Set servicingQuery to 2, so viewGetSelection knows it shouldn't
+ proceed. */
+
+ if (servicingQuery.getAndSet (2) == 1)
+ /* But if viewGetSelection is already in progress, answer it
+ first. */
+ EmacsNative.answerQuerySpin ();
+ }
+
+ public static void
+ icEndSynchronous ()
+ {
+ if (servicingQuery.getAndSet (0) != 2)
+ throw new RuntimeException ("incorrect value of `servicingQuery': "
+ + "likely 1");
+ }
+
+ public static int[]
+ viewGetSelection (short window)
+ {
+ int[] selection;
+
+ /* See if a query is already in progress from the other
+ direction. */
+ if (!servicingQuery.compareAndSet (0, 1))
+ return null;
+
+ /* Now call the regular getSelection. Note that this can't race
+ with answerQuerySpin, as `android_servicing_query' can never be
+ 2 when icBeginSynchronous is called, so a query will always be
+ started. */
+ selection = EmacsNative.getSelection (window);
+
+ /* Finally, clear servicingQuery if its value is still 1. If a
+ query has started from the other side, it ought to be 2. */
+
+ servicingQuery.compareAndSet (1, 0);
+ return selection;
+ }
+
+\f
+
public void
updateIC (EmacsWindow window, int newSelectionStart,
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;
- }
-
+ icBeginSynchronous ();
window.view.imManager.updateSelection (window.view,
newSelectionStart,
newSelectionEnd,
composingRegionStart,
composingRegionEnd);
-
- if (wasSynchronous)
- EmacsNative.endSynchronous ();
+ icEndSynchronous ();
}
public void
Log.d (TAG, "resetIC: " + window);
window.view.setICMode (icMode);
+
+ icBeginSynchronous ();
window.view.imManager.restartInput (window.view);
+ icEndSynchronous ();
}
public void
0);
info = builder.build ();
+
+
if (DEBUG_IC)
Log.d (TAG, ("updateCursorAnchorInfo: " + x + " " + y
+ " " + yBaseline + "-" + yBottom));
+ icBeginSynchronous ();
window.view.imManager.updateCursorAnchorInfo (window.view, info);
+ icEndSynchronous ();
}
/* Open a content URI described by the bytes BYTES, a non-terminated
/* Obtain the current position of point and set it as the
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. */
+ to synchronize with it can cause a dead lock in the IM manager.
+ See icBeginSynchronous in EmacsService.java for more
+ details. */
- EmacsService.imSyncInProgress = true;
- selection = EmacsNative.getSelection (window.handle);
- EmacsService.imSyncInProgress = false;
+ selection = EmacsService.viewGetSelection (window.handle);
if (selection != null)
Log.d (TAG, "onCreateInputConnection: current selection is: "
if (inputConnection == null)
inputConnection = new EmacsInputConnection (this);
+ else
+ /* Reset the composing region, in case there is still composing
+ text. */
+ inputConnection.finishComposingText ();
/* Return the input connection. */
return inputConnection;
static void android_begin_query (void);
static void android_end_query (void);
+static void android_answer_query_spin (void);
JNIEXPORT void JNICALL
NATIVE_NAME (beginSynchronous) (JNIEnv *env, jobject object)
android_end_query ();
}
+JNIEXPORT void JNICALL
+NATIVE_NAME (answerQuerySpin) (JNIEnv *env, jobject object)
+{
+ JNI_STACK_ALIGNMENT_PROLOGUE;
+
+ android_answer_query_spin ();
+}
+
#ifdef __clang__
#pragma clang diagnostic pop
#else
sem_post (&android_query_sem);
}
+/* Like `android_answer_query'. However, the query may not have
+ begun; spin until it has. */
+
+static void
+android_answer_query_spin (void)
+{
+ int n;
+
+ while (!(n = __atomic_load_n (&android_servicing_query,
+ __ATOMIC_SEQ_CST)))
+ eassert (!n);
+
+ /* Note that this function is supposed to be called before
+ `android_begin_query' starts, so clear the service flag. */
+ android_check_query ();
+}
+
/* Notice that the Emacs thread will start blocking waiting for a
response from the UI thread. Process any pending queries from the
UI thread.