eldbus: Handle removal of last reference of connection inside of callback
authorJosé Roberto de Souza <jose.souza@intel.com>
Fri, 5 Jul 2013 17:45:48 +0000 (14:45 -0300)
committerJosé Roberto de Souza <jose.souza@intel.com>
Fri, 5 Jul 2013 19:08:01 +0000 (16:08 -0300)
src/examples/eldbus/client.c
src/lib/eldbus/eldbus_core.c

index 18a1fcdf3d25c0923b68d8e24f4ea2c321dfa051..fe8391f57966c3d6309935664154da5554b796cd 100644 (file)
@@ -12,6 +12,9 @@
 static int _client_log_dom = -1;
 #define ERR(...)      EINA_LOG_DOM_ERR(_client_log_dom, __VA_ARGS__)
 
+static Eldbus_Connection *conn = NULL;
+static Ecore_Timer *timeout = NULL;
+
 static void
 _on_alive(void *context EINA_UNUSED, const Eldbus_Message *msg EINA_UNUSED)
 {
@@ -53,7 +56,12 @@ test(void)
    static int n = 0;
    n++;
    if (n >= NTESTS)
-    printf("Passed in all tests\n");
+     {
+        printf("Passed in all tests\nExiting...\n");
+        eldbus_connection_unref(conn);
+        conn = NULL;
+        ecore_main_loop_quit();
+     }
    else
     printf("Passed in %d/%d tests\n", n, NTESTS);
 }
@@ -270,14 +278,15 @@ on_name_owner_changed(void *data EINA_UNUSED, const char *bus, const char *old_i
 static Eina_Bool
 finish(void *data EINA_UNUSED)
 {
+   ERR("Timeout\nSome error happened or server is taking too much time to respond.");
    ecore_main_loop_quit();
+   timeout = NULL;
    return ECORE_CALLBACK_CANCEL;
 }
 
 int
 main(void)
 {
-   Eldbus_Connection *conn;
    Eldbus_Object *obj;
    Eldbus_Proxy *proxy;
 
@@ -317,11 +326,14 @@ main(void)
 
    eldbus_name_owner_changed_callback_add(conn, BUS, on_name_owner_changed,
                                          conn, EINA_TRUE);
-   ecore_timer_add(30, finish, NULL);
+   timeout = ecore_timer_add(30, finish, NULL);
 
    ecore_main_loop_begin();
 
-   eldbus_connection_unref(conn);
+   if (timeout)
+      ecore_timer_del(timeout);
+   if (conn)
+      eldbus_connection_unref(conn);
 
    eldbus_shutdown();
    ecore_shutdown();
index 56fcd4038a75540112a9812da2df56a3e73b820b..61ae802b38b912bdb92e27630ecfdce21611c3ab 100644 (file)
@@ -756,26 +756,22 @@ static Eina_Bool
 eldbus_idler(void *data)
 {
    Eldbus_Connection *conn = data;
-   DBusConnection *dbus_conn;
 
    DBG("Connection@%p: Dispatch status: %d", conn,
-      dbus_connection_get_dispatch_status(conn->dbus_conn));
+       dbus_connection_get_dispatch_status(conn->dbus_conn));
 
-   if (DBUS_DISPATCH_COMPLETE ==
-       dbus_connection_get_dispatch_status(conn->dbus_conn))
+   if (dbus_connection_get_dispatch_status(conn->dbus_conn) ==
+       DBUS_DISPATCH_COMPLETE)
      {
         DBG("Connection@%p: Dispatch complete, idler@%p finishing",
-           conn, conn->idler);
+            conn, conn->idler);
         conn->idler = NULL;
         return ECORE_CALLBACK_CANCEL;
      }
-   // make local copy of dbus_conn because something in dispatch can set
-   // conn->dbus_conn to NULL, thus losing our handle
-   dbus_conn = conn->dbus_conn;
-   dbus_connection_ref(dbus_conn);
    DBG("Connection@%p: Dispatching", conn);
-   dbus_connection_dispatch(dbus_conn);
-   dbus_connection_unref(dbus_conn);
+   eldbus_connection_ref(conn);
+   dbus_connection_dispatch(conn->dbus_conn);
+   eldbus_connection_unref(conn);
    return ECORE_CALLBACK_RENEW;
 }
 
@@ -784,18 +780,24 @@ cb_dispatch_status(DBusConnection *dbus_conn EINA_UNUSED, DBusDispatchStatus new
 {
    Eldbus_Connection *conn = data;
 
+   if (!conn->refcount)
+     {
+        DBG("Connection[%p] being freed, dispatch blocked", conn);
+        return;
+     }
+
    DBG("Connection@%p: Dispatch status: %d", conn, new_status);
 
    if ((new_status == DBUS_DISPATCH_DATA_REMAINS) && (!conn->idler))
      {
         conn->idler = ecore_idler_add(eldbus_idler, conn);
         DBG("Connection@%p: Adding idler@%p to handle remaining dispatch data",
-           conn, conn->idler);
+            conn, conn->idler);
      }
    else if ((new_status != DBUS_DISPATCH_DATA_REMAINS) && (conn->idler))
      {
         DBG("Connection@%p: No remaining dispatch data, clearing idler@%p",
-           conn, conn->idler);
+            conn, conn->idler);
 
         ecore_idler_del(conn->idler);
         conn->idler = NULL;
@@ -1010,14 +1012,14 @@ _connection_get(Eldbus_Connection_Type type, const char *address)
         return NULL;
      }
 
-   eldbus_connection_setup(conn);
    conn->type = type;
    conn->refcount = 1;
    EINA_MAGIC_SET(conn, ELDBUS_CONNECTION_MAGIC);
    conn->names = eina_hash_string_superfast_new(NULL);
+   eldbus_connection_setup(conn);
 
    eldbus_signal_handler_add(conn, NULL, DBUS_PATH_LOCAL, DBUS_INTERFACE_LOCAL,
-                            "Disconnected", _disconnected, conn);
+                             "Disconnected", _disconnected, conn);
    obj = eldbus_object_get(conn, ELDBUS_FDO_BUS, ELDBUS_FDO_PATH);
    conn->fdo_proxy = eldbus_proxy_get(obj, ELDBUS_FDO_INTERFACE);
 
@@ -1201,6 +1203,7 @@ _eldbus_connection_free(Eldbus_Connection *conn)
      }
 
    EINA_MAGIC_SET(conn, EINA_MAGIC_NONE);
+   //will trigger a cb_dispatch_status()
    dbus_connection_close(conn->dbus_conn);
    dbus_connection_unref(conn->dbus_conn);
    conn->dbus_conn = NULL;