This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository enlightenment.
View the commit online.
commit 98d62cf72817df40d7f59ba075e933b4b315d7e7
Author: [email protected] <[email protected]>
AuthorDate: Fri Mar 13 15:20:26 2026 -0600
perf: eliminate ActiveConnection.GetAll round-trip on startup
Reduce D-Bus latency on the critical startup path by deriving active
connection state directly from Device.GetAll instead of calling
ActiveConnection.GetAll as an extra round-trip.
For WiFi: Device.Wireless.GetAll is now issued immediately after
Device.GetAll to fetch ActiveAccessPoint, which is the only new data
needed; connection type is already known to be WiFi.
For Ethernet: all required state (connection type, IP4Config path) is
parsed directly from Device.GetAll without any additional calls.
This parallelizes Device.GetAll and Device.Wireless.GetAll, collapsing
the critical path from 3 sequential round-trips to 2.
Bug fixes from review:
- Icon showed invisible on startup because enm_mod_manager_update() was
called before active_conn_type and active_ap_path were set, causing
WiFi signal strength to render as fully transparent. Update deferred
until device callbacks have real type and AP info.
- Added NULL guards in device callbacks to prevent dereference if NM
exits while D-Bus replies are in-flight.
- Added active_connection_path guard so only the first active device
wins when multiple devices are active at startup.
- Signal handlers from eldbus_proxy_signal_handler_add are now stored
and explicitly deleted in _manager_active_conn_watch_free.
- Removed enm_saved_connections_get from Ethernet path (WiFi-specific).
- Removed dead AP-fetch code in _device_wifi_props_cb.
Runtime update path unchanged (_manager_prop_changed flow).
Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
---
src/modules/networkmanager/e_networkmanager.c | 223 ++++++++++++++++++++++----
src/modules/networkmanager/e_networkmanager.h | 11 +-
2 files changed, 205 insertions(+), 29 deletions(-)
diff --git a/src/modules/networkmanager/e_networkmanager.c b/src/modules/networkmanager/e_networkmanager.c
index 9b53e1bae..404c9f4f8 100644
--- a/src/modules/networkmanager/e_networkmanager.c
+++ b/src/modules/networkmanager/e_networkmanager.c
@@ -259,6 +259,13 @@ _ap_new(const char *path)
static void _device_free(struct NM_Device *dev);
static struct NM_Device *_device_new(const char *path);
+static void _device_wifi_props_cb(void *data, const Eldbus_Message *msg,
+ Eldbus_Pending *pending);
+static void _active_conn_prop_changed(void *data, const Eldbus_Message *msg);
+static void _manager_active_conn_watch_free(struct NM_Manager *nm);
+static void _manager_ip4_watch_free(struct NM_Manager *nm);
+static void _manager_watch_ip4(struct NM_Manager *nm,
+ const char *ip4config_path);
static void
_device_get_aps_cb(void *data, const Eldbus_Message *msg,
@@ -432,6 +439,26 @@ _device_get_props_cb(void *data, const Eldbus_Message *msg,
if (eldbus_message_iter_arguments_get(var, "u", &state))
dev->state = state;
}
+ else if (!strcmp(key, "ActiveConnection"))
+ {
+ const char *aconn_path;
+ if (eldbus_message_iter_arguments_get(var, "o", &aconn_path) &&
+ aconn_path && strcmp(aconn_path, "/") != 0)
+ {
+ free(dev->active_conn_path);
+ dev->active_conn_path = strdup(aconn_path);
+ }
+ }
+ else if (!strcmp(key, "Ip4Config"))
+ {
+ const char *ip4;
+ if (eldbus_message_iter_arguments_get(var, "o", &ip4) &&
+ ip4 && strcmp(ip4, "/") != 0)
+ {
+ free(dev->ip4_path);
+ dev->ip4_path = strdup(ip4);
+ }
+ }
}
/* If this is a WiFi device, get wireless proxy and fetch APs */
@@ -452,7 +479,153 @@ _device_get_props_cb(void *data, const Eldbus_Message *msg,
"GetAccessPoints",
_device_get_aps_cb, dev,
-1, "");
+
+ /* Also fetch WiFi-specific props (ActiveAccessPoint) in parallel
+ * with GetAccessPoints — this avoids the ActiveConnection.GetAll
+ * round-trip on the critical startup path. */
+ dev->pending.get_wifi_props =
+ eldbus_proxy_call(dev->wireless_proxy, "GetAll",
+ _device_wifi_props_cb, dev,
+ -1, "s", NM_IFACE_WIFI);
}
+ else if (dev->type == NM_DEVICE_TYPE_ETHERNET && dev->state >= 100 &&
+ dev->active_conn_path)
+ {
+ /* Guard: nm_manager may have been freed if NM exited while this
+ * D-Bus reply was in flight. */
+ if (!nm_manager) return;
+
+ /* First active device wins — skip if another already adopted. */
+ if (nm_manager->active_connection_path) return;
+
+ /* Ethernet device is active — set manager state directly without
+ * an extra ActiveConnection.GetAll round-trip. */
+ DBG("Ethernet device %s active (state=%u), adopting connection %s",
+ dev->path, dev->state, dev->active_conn_path);
+
+ nm_manager->probe_generation++;
+ _manager_active_conn_watch_free(nm_manager);
+ _manager_ip4_watch_free(nm_manager);
+
+ eina_stringshare_del(nm_manager->active_connection_path);
+ nm_manager->active_connection_path =
+ eina_stringshare_add(dev->active_conn_path);
+
+ nm_manager->active_conn_type = NM_DEVICE_TYPE_ETHERNET;
+
+ eina_stringshare_del(nm_manager->active_ap_path);
+ nm_manager->active_ap_path = NULL;
+
+ /* Set up persistent watcher on the active connection object */
+ {
+ Eldbus_Object *aobj =
+ eldbus_object_get(conn, NM_BUS_NAME, dev->active_conn_path);
+ nm_manager->active_conn_obj = aobj;
+ nm_manager->active_conn_proxy = eldbus_proxy_get(aobj,
+ NM_IFACE_PROPS);
+ nm_manager->active_conn_signal_handler =
+ eldbus_proxy_signal_handler_add(nm_manager->active_conn_proxy,
+ "PropertiesChanged",
+ _active_conn_prop_changed,
+ nm_manager);
+ }
+
+ if (dev->ip4_path)
+ _manager_watch_ip4(nm_manager, dev->ip4_path);
+
+ enm_mod_manager_update(nm_manager);
+ /* Saved connections are WiFi-specific — skip for Ethernet */
+ }
+}
+
+static void
+_device_wifi_props_cb(void *data, const Eldbus_Message *msg,
+ Eldbus_Pending *pending EINA_UNUSED)
+{
+ struct NM_Device *dev = data;
+ Eldbus_Message_Iter *array, *dict;
+ const char *name, *text;
+ const char *ap_path = NULL;
+
+ /* Guard: nm_manager may have been freed if NM exited while this D-Bus
+ * reply was in flight (e.g. eldbus_pending_cancel called synchronously
+ * from _device_free during _e_nm_system_name_owner_exit). */
+ if (!nm_manager) return;
+
+ dev->pending.get_wifi_props = NULL;
+
+ if (eldbus_message_error_get(msg, &name, &text))
+ {
+ WRN("Device Wireless GetAll failed: %s: %s", name, text);
+ return;
+ }
+
+ if (!eldbus_message_arguments_get(msg, "a{sv}", &array))
+ {
+ WRN("Device Wireless GetAll: cannot parse reply");
+ return;
+ }
+
+ while (eldbus_message_iter_get_and_next(array, 'e', &dict))
+ {
+ Eldbus_Message_Iter *var;
+ const char *key;
+
+ if (!eldbus_message_iter_arguments_get(dict, "sv", &key, &var))
+ continue;
+
+ if (!strcmp(key, "ActiveAccessPoint"))
+ {
+ const char *path;
+ if (eldbus_message_iter_arguments_get(var, "o", &path) &&
+ path && strcmp(path, "/") != 0)
+ ap_path = path;
+ }
+ }
+
+ DBG("Device %s ActiveAccessPoint=%s state=%u",
+ dev->path, ap_path ?: "(none)", dev->state);
+
+ /* Only adopt this device as the active connection if it is in activated
+ * state (>= 100) and has an active AP. */
+ if (dev->state < 100 || !ap_path || !dev->active_conn_path)
+ return;
+
+ /* First active device wins — skip if another already adopted. */
+ if (nm_manager->active_connection_path)
+ return;
+
+ nm_manager->probe_generation++;
+ _manager_active_conn_watch_free(nm_manager);
+ _manager_ip4_watch_free(nm_manager);
+
+ nm_manager->active_conn_type = NM_DEVICE_TYPE_WIFI;
+
+ eina_stringshare_del(nm_manager->active_ap_path);
+ nm_manager->active_ap_path = eina_stringshare_add(ap_path);
+
+ eina_stringshare_del(nm_manager->active_connection_path);
+ nm_manager->active_connection_path =
+ eina_stringshare_add(dev->active_conn_path);
+
+ /* Set up persistent watcher on the active connection object */
+ {
+ Eldbus_Object *aobj =
+ eldbus_object_get(conn, NM_BUS_NAME, dev->active_conn_path);
+ nm_manager->active_conn_obj = aobj;
+ nm_manager->active_conn_proxy = eldbus_proxy_get(aobj, NM_IFACE_PROPS);
+ nm_manager->active_conn_signal_handler =
+ eldbus_proxy_signal_handler_add(nm_manager->active_conn_proxy,
+ "PropertiesChanged",
+ _active_conn_prop_changed,
+ nm_manager);
+ }
+
+ if (dev->ip4_path)
+ _manager_watch_ip4(nm_manager, dev->ip4_path);
+
+ enm_mod_manager_update(nm_manager);
+ enm_saved_connections_get(nm_manager);
}
static struct NM_Device *
@@ -492,6 +665,8 @@ _device_free(struct NM_Device *dev)
eldbus_pending_cancel(dev->pending.get_props);
if (dev->pending.get_aps)
eldbus_pending_cancel(dev->pending.get_aps);
+ if (dev->pending.get_wifi_props)
+ eldbus_pending_cancel(dev->pending.get_wifi_props);
while (dev->access_points)
{
@@ -503,6 +678,8 @@ _device_free(struct NM_Device *dev)
}
free(dev->interface);
+ free(dev->active_conn_path);
+ free(dev->ip4_path);
if (dev->wireless_proxy)
{
@@ -689,6 +866,11 @@ _nm_conn_type_parse(const char *type)
static void
_manager_active_conn_watch_free(struct NM_Manager *nm)
{
+ if (nm->active_conn_signal_handler)
+ {
+ eldbus_signal_handler_del(nm->active_conn_signal_handler);
+ nm->active_conn_signal_handler = NULL;
+ }
if (nm->active_conn_proxy)
{
eldbus_proxy_unref(nm->active_conn_proxy);
@@ -849,8 +1031,9 @@ _active_conn_probe_cb(void *data, const Eldbus_Message *msg,
nm->active_ap_path = ap_path ? eina_stringshare_add(ap_path) : NULL;
/* Subscribe to property changes on the now-persistent proxy */
- eldbus_proxy_signal_handler_add(nm->active_conn_proxy, "PropertiesChanged",
- _active_conn_prop_changed, nm);
+ nm->active_conn_signal_handler =
+ eldbus_proxy_signal_handler_add(nm->active_conn_proxy, "PropertiesChanged",
+ _active_conn_prop_changed, nm);
if (ip4path)
_manager_watch_ip4(nm, ip4path);
@@ -1023,7 +1206,6 @@ _manager_get_props_cb(void *data, const Eldbus_Message *msg,
{
Eldbus_Message_Iter *conn_array;
const char *aconn_path;
- Eina_Bool found = EINA_FALSE;
if (!eldbus_message_iter_arguments_get(var, "ao", &conn_array))
{
@@ -1031,36 +1213,23 @@ _manager_get_props_cb(void *data, const Eldbus_Message *msg,
continue;
}
- /* Advance generation and clear old watchers before probing so
- * stale probes are discarded and no stale connection is shown. */
- nm->probe_generation++;
- _manager_active_conn_watch_free(nm);
- _manager_ip4_watch_free(nm);
-
- /* Try each active connection — _active_conn_probe_cb
- * filters out bridge/vpn types and only adopts wifi/ethernet. */
+ /* On startup we do NOT launch ActiveConnection.GetAll probes
+ * here — the device callbacks (_device_wifi_props_cb for WiFi,
+ * _device_get_props_cb for Ethernet) derive all needed info from
+ * Device.GetAll / Device.Wireless.GetAll which are already
+ * running in parallel. */
while (eldbus_message_iter_get_and_next(conn_array, 'o', &aconn_path))
- {
- DBG("ActiveConnections: trying path=%s", aconn_path);
- _manager_probe_active_conn(nm, aconn_path);
- found = EINA_TRUE;
- }
-
- if (!found)
- {
- DBG("ActiveConnections: empty array");
- eina_stringshare_del(nm->active_ap_path);
- nm->active_ap_path = NULL;
- eina_stringshare_del(nm->active_connection_path);
- nm->active_connection_path = NULL;
- free(nm->ip_address);
- nm->ip_address = NULL;
- }
+ DBG("ActiveConnections (startup): path=%s — device probes pending",
+ aconn_path);
}
}
DBG("manager_get_props done: state=%d active_ap=%s conn_type=%d",
nm->state, nm->active_ap_path ?: "(null)", nm->active_conn_type);
+
+ /* Always update the UI now so that disconnected/VPN-only/unassociated
+ * states are shown immediately. Device callbacks will call
+ * enm_mod_manager_update again once they have full type and AP info. */
enm_mod_manager_update(nm);
}
diff --git a/src/modules/networkmanager/e_networkmanager.h b/src/modules/networkmanager/e_networkmanager.h
index 491e3a008..152378184 100644
--- a/src/modules/networkmanager/e_networkmanager.h
+++ b/src/modules/networkmanager/e_networkmanager.h
@@ -76,12 +76,18 @@ struct NM_Device
enum NM_Device_Type type;
uint32_t state;
+ /* Transient paths read from Device.GetAll — used during startup probe
+ * to avoid an extra ActiveConnection.GetAll round-trip. */
+ char *active_conn_path; /* ActiveConnection object path */
+ char *ip4_path; /* Ip4Config object path */
+
Eina_Inlist *access_points; /* NM_Access_Point inlist, WiFi only */
struct
{
Eldbus_Pending *get_props;
Eldbus_Pending *get_aps;
+ Eldbus_Pending *get_wifi_props; /* Device.Wireless GetAll */
} pending;
};
@@ -111,8 +117,9 @@ struct NM_Manager
/* Persistent proxy/obj for watching active connection properties.
* Created when active connection changes, freed when it changes again
* or on manager shutdown. Signal-driven via PropertiesChanged. */
- Eldbus_Proxy *active_conn_proxy;
- Eldbus_Object *active_conn_obj;
+ Eldbus_Proxy *active_conn_proxy;
+ Eldbus_Object *active_conn_obj;
+ Eldbus_Signal_Handler *active_conn_signal_handler; /* for explicit removal */
/* Persistent proxy/obj for watching IP4Config properties. */
Eldbus_Proxy *ip4_proxy;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.