Keep RPC calls in the same thread
authorSam Thursfield <samthursfield@codethink.co.uk>
Wed, 18 May 2011 14:52:56 +0000 (15:52 +0100)
committerSam Thursfield <samthursfield@codethink.co.uk>
Fri, 20 May 2011 13:59:26 +0000 (14:59 +0100)
It seems it's not possible to reply to an async RPC call outside
of the thread it's executing in. This means to communicate with the
Gtk+ main loop we must wait in the get_identity() function on a
GCond until the identity has been chosen.

src/moonshot-msrpc-server.vala

index 937f616..660f0e6 100644 (file)
@@ -5,18 +5,22 @@ using MoonshotRpcInterface;
  * to the GLib main loop thread; we need to be executing inside the main
  * loop before we can access any state or make any Gtk+ calls.
  */
+/* Fixme: can you make *this* an async callback? */
 public class IdentityRequest : Object {
-    private Rpc.AsyncCall call;
     private MainWindow main_window;
     private Identity **result;
+    private unowned Mutex mutex;
+    private unowned Cond cond;
 
-    public IdentityRequest (Rpc.AsyncCall _call,
-                            Gtk.Window window,
-                            Identity **_result)
+    public IdentityRequest (Gtk.Window window,
+                            Identity **_result,
+                            Mutex _mutex,
+                            Cond _cond)
     {
-        call = _call;
         main_window = (MainWindow)window;
         result = _result;
+        mutex = _mutex;
+        cond = _cond;
     }
 
     public bool main_loop_cb ()
@@ -31,15 +35,19 @@ public class IdentityRequest : Object {
     {
         var id_card = this.main_window.selected_id_card_widget.id_card;
 
+        mutex.lock ();
         *result = new Identity();
 
         (*result)->identity = "identity";
         (*result)->password = id_card.password;
         (*result)->service = "certificate";
 
-        call.return (null);
+        print ("Result %x, *%x - strs %x, %x, %x\n", (uint)result, (uint)(*result), (uint)((*result)->identity), (uint)((*result)->password), (uint)((*result)->service));
+
+        cond.signal ();
+        mutex.unlock ();
 
-        //delete result;
+        // 'result' is freed by the RPC runtime
 
         return false;
     }
@@ -90,9 +98,21 @@ public class MoonshotServer : Object {
                                               string in_service,
                                               Identity **result)
     {
-        IdentityRequest request = new IdentityRequest (call, main_window, result);
+        Mutex mutex = new Mutex ();
+        Cond cond = new Cond ();
+
+        mutex.lock ();
 
-        // Pass execution to the main loop thread
+        *result = null;
+        IdentityRequest request = new IdentityRequest (main_window, result, mutex, cond);
+
+        // Pass execution to the main loop thread and wait for
+        // the 'send' action to be signalled.
         Idle.add (request.main_loop_cb);
+        while (*result == null)
+            cond.wait (mutex);
+        mutex.unlock ();
+
+        call.return (null);
     }
 }