emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 94e3d115933: Simplify code relating to UI thread synchronization


From: Po Lu
Subject: master 94e3d115933: Simplify code relating to UI thread synchronization
Date: Fri, 29 Dec 2023 21:57:34 -0500 (EST)

branch: master
commit 94e3d1159334d08fd1d54464bf6173755ba606b7
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Simplify code relating to UI thread synchronization
    
    * java/org/gnu/emacs/EmacsContextMenu.java (display):
    
    * java/org/gnu/emacs/EmacsDialog.java (display):
    
    * java/org/gnu/emacs/EmacsService.java (getEmacsView)
    (getLocationOnScreen, getClipboardManager)
    (requestDirectoryAccess): Replace manual synchronization within
    Runnable objects by usage of FutureTask.
    (syncRunnable): Accept FutureTask<V> in place of Runnables, and
    obtain and return results from calls to its get method.
---
 java/org/gnu/emacs/EmacsContextMenu.java |  28 ++---
 java/org/gnu/emacs/EmacsDialog.java      |  25 ++--
 java/org/gnu/emacs/EmacsService.java     | 208 ++++++++++++++-----------------
 3 files changed, 115 insertions(+), 146 deletions(-)

diff --git a/java/org/gnu/emacs/EmacsContextMenu.java 
b/java/org/gnu/emacs/EmacsContextMenu.java
index 2652f35b545..b6c63c3cbe1 100644
--- a/java/org/gnu/emacs/EmacsContextMenu.java
+++ b/java/org/gnu/emacs/EmacsContextMenu.java
@@ -22,6 +22,9 @@ package org.gnu.emacs;
 import java.util.List;
 import java.util.ArrayList;
 
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+
 import android.content.Context;
 import android.content.Intent;
 
@@ -344,8 +347,7 @@ public final class EmacsContextMenu
   display (final EmacsWindow window, final int xPosition,
           final int yPosition, final int serial)
   {
-    Runnable runnable;
-    final EmacsHolder<Boolean> rc;
+    FutureTask<Boolean> task;
 
     /* Android will permanently cease to display any popup menus at
        all if the list of menu items is empty.  Prevent this by
@@ -354,25 +356,17 @@ public final class EmacsContextMenu
     if (menuItems.isEmpty ())
       return false;
 
-    rc = new EmacsHolder<Boolean> ();
-    rc.thing = false;
-
-    runnable = new Runnable () {
+    task = new FutureTask<Boolean> (new Callable<Boolean> () {
        @Override
-       public void
-       run ()
+       public Boolean
+       call ()
        {
-         synchronized (this)
-           {
-             lastMenuEventSerial = serial;
-             rc.thing = display1 (window, xPosition, yPosition);
-             notify ();
-           }
+         lastMenuEventSerial = serial;
+         return display1 (window, xPosition, yPosition);
        }
-      };
+      });
 
-    EmacsService.syncRunnable (runnable);
-    return rc.thing;
+    return EmacsService.<Boolean>syncRunnable (task);
   }
 
   /* Dismiss this context menu.  WINDOW is the window where the
diff --git a/java/org/gnu/emacs/EmacsDialog.java 
b/java/org/gnu/emacs/EmacsDialog.java
index bad1ddde227..7552b16b370 100644
--- a/java/org/gnu/emacs/EmacsDialog.java
+++ b/java/org/gnu/emacs/EmacsDialog.java
@@ -22,6 +22,9 @@ package org.gnu.emacs;
 import java.util.List;
 import java.util.ArrayList;
 
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+
 import android.app.AlertDialog;
 
 import android.content.Context;
@@ -388,26 +391,18 @@ public final class EmacsDialog implements 
DialogInterface.OnDismissListener
   public boolean
   display ()
   {
-    Runnable runnable;
-    final EmacsHolder<Boolean> rc;
+    FutureTask<Boolean> task;
 
-    rc = new EmacsHolder<Boolean> ();
-    rc.thing = false;
-    runnable = new Runnable () {
+    task = new FutureTask<Boolean> (new Callable<Boolean> () {
        @Override
-       public void
-       run ()
+       public Boolean
+       call ()
        {
-         synchronized (this)
-           {
-             rc.thing = display1 ();
-             notify ();
-           }
+         return display1 ();
        }
-      };
+      });
 
-    EmacsService.syncRunnable (runnable);
-    return rc.thing;
+    return EmacsService.<Boolean>syncRunnable (task);
   }
 
 
diff --git a/java/org/gnu/emacs/EmacsService.java 
b/java/org/gnu/emacs/EmacsService.java
index c71670b3e47..7934d6f9cd3 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -27,6 +27,10 @@ import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+
 import java.util.concurrent.atomic.AtomicInteger;
 
 import android.database.Cursor;
@@ -331,52 +335,45 @@ public final class EmacsService extends Service
                final boolean isFocusedByDefault)
   {
     Runnable runnable;
-    final EmacsHolder<EmacsView> view;
-
-    view = new EmacsHolder<EmacsView> ();
+    FutureTask<EmacsView> task;
 
-    runnable = new Runnable () {
+    task = new FutureTask<EmacsView> (new Callable<EmacsView> () {
        @Override
-       public void
-       run ()
+       public EmacsView
+       call ()
        {
-         synchronized (this)
-           {
-             view.thing = new EmacsView (window);
-             view.thing.setVisibility (visibility);
+         EmacsView view;
 
-             /* The following function is only present on Android 26
-                or later.  */
-             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
-               view.thing.setFocusedByDefault (isFocusedByDefault);
+         view = new EmacsView (window);
+         view.setVisibility (visibility);
 
-             notify ();
-           }
+         /* The following function is only present on Android 26
+            or later.  */
+         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
+           view.setFocusedByDefault (isFocusedByDefault);
+
+         return view;
        }
-      };
+      });
 
-    syncRunnable (runnable);
-    return view.thing;
+    return EmacsService.<EmacsView>syncRunnable (task);
   }
 
   public void
   getLocationOnScreen (final EmacsView view, final int[] coordinates)
   {
-    Runnable runnable;
+    FutureTask<Void> task;
 
-    runnable = new Runnable () {
-       public void
-       run ()
+    task = new FutureTask<Void> (new Callable<Void> () {
+       public Void
+       call ()
        {
-         synchronized (this)
-           {
-             view.getLocationOnScreen (coordinates);
-             notify ();
-           }
+         view.getLocationOnScreen (coordinates);
+         return null;
        }
-      };
+      });
 
-    syncRunnable (runnable);
+    EmacsService.<Void>syncRunnable (task);
   }
 
 
@@ -702,28 +699,17 @@ public final class EmacsService extends Service
   public ClipboardManager
   getClipboardManager ()
   {
-    final EmacsHolder<ClipboardManager> manager;
-    Runnable runnable;
+    FutureTask<Object> task;
 
-    manager = new EmacsHolder<ClipboardManager> ();
-
-    runnable = new Runnable () {
-       public void
-       run ()
+    task = new FutureTask<Object> (new Callable<Object> () {
+       public Object
+       call ()
        {
-         Object tem;
-
-         synchronized (this)
-           {
-             tem = getSystemService (Context.CLIPBOARD_SERVICE);
-             manager.thing = (ClipboardManager) tem;
-             notify ();
-           }
+         return getSystemService (Context.CLIPBOARD_SERVICE);
        }
-      };
+      });
 
-    syncRunnable (runnable);
-    return manager.thing;
+    return (ClipboardManager) EmacsService.<Object>syncRunnable (task);
   }
 
   public void
@@ -738,33 +724,37 @@ public final class EmacsService extends Service
     System.exit (0);
   }
 
-  /* Wait synchronously for the specified RUNNABLE to complete in the
-     UI thread.  Must be called from the Emacs thread.  */
+  /* Wait synchronously for the specified TASK to complete in the UI
+     thread, then return its result.  Must be called from the Emacs
+     thread.  */
 
-  public static void
-  syncRunnable (Runnable runnable)
+  public static <V> V
+  syncRunnable (FutureTask<V> task)
   {
+    V object;
+
     EmacsNative.beginSynchronous ();
+    SERVICE.runOnUiThread (task);
 
-    synchronized (runnable)
+    try
       {
-       SERVICE.runOnUiThread (runnable);
-
-       while (true)
-         {
-           try
-             {
-               runnable.wait ();
-               break;
-             }
-           catch (InterruptedException e)
-             {
-               continue;
-             }
-         }
+       object = task.get ();
+      }
+    catch (ExecutionException exception)
+      {
+       /* Wrap this exception in a RuntimeException and signal it to
+          the caller.  */
+       throw new RuntimeException (exception.getCause ());
+      }
+    catch (InterruptedException exception)
+      {
+       EmacsNative.emacsAbort ();
+       object = null;
       }
 
     EmacsNative.endSynchronous ();
+
+    return object;
   }
 
 
@@ -1283,71 +1273,61 @@ public final class EmacsService extends Service
   public int
   requestDirectoryAccess ()
   {
-    Runnable runnable;
-    final EmacsHolder<Integer> rc;
+    FutureTask<Integer> task;
 
     /* Return 1 if Android is too old to support this feature.  */
 
     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
       return 1;
 
-    rc = new EmacsHolder<Integer> ();
-    rc.thing = Integer.valueOf (1);
-
-    runnable = new Runnable () {
+    task = new FutureTask<Integer> (new Callable<Integer> () {
        @Override
-       public void
-       run ()
+       public Integer
+        call ()
        {
          EmacsActivity activity;
          Intent intent;
-         int id;
+         int id, rc;
+
+         /* Try to obtain an activity that will receive the response
+            from the file chooser dialog.  */
 
-         synchronized (this)
+         if (EmacsActivity.focusedActivities.isEmpty ())
            {
-             /* Try to obtain an activity that will receive the
-                response from the file chooser dialog.  */
+             /* If focusedActivities is empty then this dialog may
+                have been displayed immediately after another popup
+                dialog was dismissed.  Try the EmacsActivity to be
+                focused.  */
 
-             if (EmacsActivity.focusedActivities.isEmpty ())
-               {
-                 /* If focusedActivities is empty then this dialog
-                    may have been displayed immediately after another
-                    popup dialog was dismissed.  Try the
-                    EmacsActivity to be focused.  */
-
-                 activity = EmacsActivity.lastFocusedActivity;
-
-                 if (activity == null)
-                   {
-                     /* Still no luck.  Return failure.  */
-                     notify ();
-                     return;
-                   }
-               }
-             else
-               activity = EmacsActivity.focusedActivities.get (0);
+             activity = EmacsActivity.lastFocusedActivity;
 
-             /* Now create the intent.  */
-             intent = new Intent (Intent.ACTION_OPEN_DOCUMENT_TREE);
+             if (activity == null)
+               /* Still no luck.  Return failure.  */
+               return 1;
+           }
+         else
+           activity = EmacsActivity.focusedActivities.get (0);
 
-             try
-               {
-                 id = EmacsActivity.ACCEPT_DOCUMENT_TREE;
-                 activity.startActivityForResult (intent, id, null);
-                 rc.thing = Integer.valueOf (0);
-               }
-             catch (Exception e)
-               {
-                 e.printStackTrace ();
-               }
+         /* Now create the intent.  */
+         intent = new Intent (Intent.ACTION_OPEN_DOCUMENT_TREE);
+         rc = 1;
 
-             notify ();
+         try
+           {
+             id = EmacsActivity.ACCEPT_DOCUMENT_TREE;
+             activity.startActivityForResult (intent, id, null);
+             rc = 0;
            }
+         catch (Exception e)
+           {
+             e.printStackTrace ();
+           }
+
+         return rc;
        }
-      };
+      });
 
-    syncRunnable (runnable);
-    return rc.thing;
+    return EmacsService.<Integer>syncRunnable (task);
   }
 
   /* Return an array of each tree provided by the document PROVIDER
@@ -1969,7 +1949,7 @@ public final class EmacsService extends Service
          /* Now request these permissions.  */
          activity.requestPermissions (new String[] { permission,
                                                      permission1, },
-           0);
+                                      0);
        }
       };
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]