eldbus: make connections fork-safe
authorMike Blumenkrantz <zmike@osg.samsung.com>
Fri, 2 Feb 2018 21:59:56 +0000 (16:59 -0500)
committerJiyoun Park <jy0703.park@samsung.com>
Tue, 3 Apr 2018 15:26:04 +0000 (00:26 +0900)
after a fork, any existing connection objects can no longer be used,
but it's up to the user to destroy them. internally, this prevents
existing connections from ever being returned as valid connections
and creates new ones after a fork

also destroy fd handlers for connections to ensure that no data is
accidentally clobbered before the connections are cleaned up

src/lib/eldbus/eldbus_core.c

index 638595a..233947f 100644 (file)
@@ -85,6 +85,45 @@ static void _eldbus_connection_context_event_cb_del(Eldbus_Connection_Context_Ev
 static void eldbus_dispatch_name_owner_change(Eldbus_Connection_Name *cn, const char *old_id);
 static void _eldbus_connection_free(Eldbus_Connection *conn);
 
+static void
+eldbus_fd_handler_del(Eldbus_Handler_Data *hd)
+{
+   if (!hd->fd_handler) return;
+
+   DBG("free Eldbus_Handler_Data %d", hd->fd);
+   hd->conn->fd_handlers = eina_inlist_remove(hd->conn->fd_handlers,
+                                              EINA_INLIST_GET(hd));
+   if (hd->fd_handler)
+     {
+        ecore_main_fd_handler_del(hd->fd_handler);
+        hd->fd_handler = NULL;
+     }
+
+   free(hd);
+}
+
+static void
+_eldbus_fork_reset()
+{
+   int i;
+
+   for (i =0; i < ELDBUS_CONNECTION_TYPE_LAST - 1; i++)
+     {
+        Eldbus_Connection *conn = shared_connections[i];
+        if (conn)
+          {
+             Eina_Inlist *list;
+             Eldbus_Handler_Data *fd_handler;
+
+             EINA_INLIST_FOREACH_SAFE(conn->fd_handlers, list, fd_handler)
+               dbus_watch_set_data(fd_handler->watch, NULL, NULL);
+          }
+        shared_connections[i] = NULL;
+     }
+   if (address_connections) eina_hash_free(address_connections);
+   address_connections = NULL;
+}
+
 EAPI int
 eldbus_init(void)
 {
@@ -142,7 +181,7 @@ eldbus_init(void)
    if (!eldbus_object_init()) goto object_failed;
    if (!eldbus_proxy_init()) goto proxy_failed;
    if (!eldbus_service_init()) goto service_failed;
-
+   ecore_fork_reset_callback_add(_eldbus_fork_reset, NULL);
    return _eldbus_init_count;
 
 service_failed:
@@ -216,6 +255,7 @@ eldbus_shutdown(void)
    if (--_eldbus_init_count)
      return _eldbus_init_count;
 
+   ecore_fork_reset_callback_del(_eldbus_fork_reset, NULL);
    if (shared_connections[ELDBUS_CONNECTION_TYPE_SESSION - 1])
      {
         CRI("Alive TYPE_SESSION connection");
@@ -559,24 +599,6 @@ eldbus_connection_name_object_get(Eldbus_Connection *conn, const char *name, con
    return eina_hash_find(cn->objects, path);
 }
 
-
-static void
-eldbus_fd_handler_del(Eldbus_Handler_Data *hd)
-{
-   if (!hd->fd_handler) return;
-
-   DBG("free Eldbus_Handler_Data %d", hd->fd);
-   hd->conn->fd_handlers = eina_inlist_remove(hd->conn->fd_handlers,
-                                              EINA_INLIST_GET(hd));
-   if (hd->fd_handler)
-     {
-        ecore_main_fd_handler_del(hd->fd_handler);
-        hd->fd_handler = NULL;
-     }
-
-   free(hd);
-}
-
 static Eina_Bool
 eldbus_fd_handler(void *data, Ecore_Fd_Handler *fd_handler)
 {
@@ -1260,7 +1282,10 @@ _eldbus_connection_free(Eldbus_Connection *conn)
    if (conn->type && conn->shared)
      {
         if (conn->type == ELDBUS_CONNECTION_TYPE_ADDRESS)
-           eina_hash_del_by_data(address_connections, conn);
+           {
+              if (address_connections)
+                eina_hash_del_by_data(address_connections, conn);
+           }
         else if (shared_connections[conn->type - 1] == (void *) conn)
            shared_connections[conn->type - 1] = NULL;
      }