eldbus: make connections fork-safe

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
This commit is contained in:
Mike Blumenkrantz 2018-02-02 16:59:56 -05:00
parent 10ce0cbd8a
commit 95a339733a
1 changed files with 45 additions and 20 deletions

View 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)
{
@ -131,7 +170,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:
@ -205,6 +244,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");
@ -548,24 +588,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)
{
@ -1256,7 +1278,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;
}