[PATCH 1/1] core: add nm_device_add_pending_action_with_timeout()



Signed-off-by: Thomas Haller <thaller redhat com>
---
This patch was part of branch th/rh1086906_start_complete_for_dynamic_ip,
which was merged with:
  
http://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?id=f5b82f49ddfb2ecbf2e865b914d639ddca5a28c8

It applies on current master
  
http://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?id=9ef23947cc8f074767bd63b984b73740766377b0

This functionality was not needed, so the patch is obsolete. It may be useful
in the future, so I park it on the mailing list.

No action required!! :)

Thomas

 src/devices/nm-device.c | 142 ++++++++++++++++++++++++++++++++++++++++++------
 src/devices/nm-device.h |   2 +
 2 files changed, 127 insertions(+), 17 deletions(-)

diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 384460e..0af565d 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -7684,6 +7684,52 @@ nm_device_set_hw_addr (NMDevice *device, const guint8 *addr,
        return success;
 }
 
+typedef gboolean (*PendingActionTimeoutCb) (NMDevice *device, const char *action, gboolean is_timeout, 
gpointer user_data);
+
+typedef struct pending_action_data
+{
+       NMDevice *device;
+       PendingActionTimeoutCb handler;
+       gpointer user_data;
+       guint timeout_id;
+       char action[1];
+} PendingActionData;
+
+static PendingActionData *
+pending_action_data_new (NMDevice *device, const char *action, PendingActionTimeoutCb timeout_handler, 
gpointer user_data)
+{
+       PendingActionData *data;
+       gsize len;
+
+       len = strlen (action);
+       data = g_malloc (sizeof (PendingActionData) - 1 + len + 1);
+
+       data->device = device;
+       data->handler = timeout_handler;
+       data->user_data = user_data;
+       data->timeout_id = 0;
+       memcpy (&data->action[0], action, len + 1);
+
+       return data;
+}
+
+static gboolean
+pending_action_timeout_cb (gpointer user_data)
+{
+       PendingActionData *data = user_data;
+
+       nm_log_dbg (LOGD_DEVICE, "(%s): timeout_pending_action: '%s' (timeout=%u)",
+                   nm_device_get_iface (data->device),
+                   data->action,
+                   data->timeout_id);
+       data->timeout_id = 0;
+       if (data->handler (data->device, data->action, TRUE, data->user_data) &&
+           g_slist_find (NM_DEVICE_GET_PRIVATE (data->device)->pending_actions, data) != NULL)
+               nm_device_remove_pending_action (data->device, data->action, TRUE);
+
+       return G_SOURCE_REMOVE;
+}
+
 /**
  * nm_device_add_pending_action():
  * @device: the #NMDevice to add the pending action to
@@ -7691,24 +7737,65 @@ nm_device_set_hw_addr (NMDevice *device, const guint8 *addr,
  * @assert_not_yet_pending: if %TRUE, assert that the @action is currently not yet pending.
  * Otherwise, ignore duplicate scheduling of the same action silently.
  *
- * Adds a pending action to the device.
+ * Adds a pending action to the device without timeout. This is a shorthand for
+ * nm_device_add_pending_action_with_timeout().
+ *
+ * Returns: %TRUE if the action was added (and not already added before). %FALSE
+ * if the same action is already scheduled.
+ **/
+gboolean
+nm_device_add_pending_action (NMDevice *device, const char *action, gboolean assert_not_yet_pending)
+{
+       return nm_device_add_pending_action_with_timeout (device, action, assert_not_yet_pending, 0, NULL, 
NULL);
+}
+
+/**
+ * nm_device_add_pending_action_with_timeout():
+ * @device: the #NMDevice to add the pending action to
+ * @action: a static string that identifies the action
+ * @assert_not_yet_pending: if %TRUE, assert that the @action is currently not yet pending.
+ * Otherwise, ignore duplicate scheduling of the same action silently.
+ * @timeout_ms: schedule a callback in @timeout_ms milliseconds. Set to 0 for no timeout.
+ * @timeout_handler: call this function after timeout or when removing the action.
+ * @user_data: argument for @timeout_handler.
+ *
+ * Adds a pending action to the device. If such an action is already pending, this call
+ * does nothing. Especially, it does not cancel any pending timeout or schedule a further one.
+ * If the action is not yet pending it will be added and the timeout started.
+ *
+ * The @timeout_handler will be called exactly once, either when removing the action or on timeout.
+ *
+ * When the action is removed, it calls the handler after the action is removed (with argument
+ * @is_timeout==%FALSE) but before notify::NM_DEVICE_HAS_PENDING_ACTION. In this case, the return
+ * value of @timeout_handler will be ignored.
+ *
+ * If the timeout hits first, @timeout_handler will be called, with the pending action still pending (the
+ * handler is allowed to call nm_device_remove_pending_action() -- which will not call @timeout_handler
+ * again). If the callback returns %TRUE and the very same action is still pending, it will call
+ * nm_device_remove_pending_action() to remove the action. Otherwise, the pending action will not
+ * be removed.
  *
  * Returns: %TRUE if the action was added (and not already added before). %FALSE
  * if the same action is already scheduled. In the latter case, the action was not scheduled
  * a second time.
- */
+ **/
 gboolean
-nm_device_add_pending_action (NMDevice *device, const char *action, gboolean assert_not_yet_pending)
+nm_device_add_pending_action_with_timeout (NMDevice *device, const char *action, gboolean 
assert_not_yet_pending,
+                                           guint32 timeout_ms, PendingActionTimeoutCb timeout_handler, 
gpointer user_data)
 {
        NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
        GSList *iter;
        guint count = 0;
+       PendingActionData *data;
 
        g_return_val_if_fail (action, FALSE);
+       g_return_val_if_fail ((!timeout_ms && !timeout_handler && !user_data) || (timeout_ms && 
timeout_handler), FALSE);
 
        /* Check if the action is already pending. Cannot add duplicate actions */
        for (iter = priv->pending_actions; iter; iter = iter->next) {
-               if (!strcmp (action, iter->data)) {
+               data = iter->data;
+
+               if (!strcmp (action, data->action)) {
                        if (assert_not_yet_pending) {
                                nm_log_warn (LOGD_DEVICE, "(%s): add_pending_action (%d): '%s' already 
pending",
                                             nm_device_get_iface (device),
@@ -7726,13 +7813,22 @@ nm_device_add_pending_action (NMDevice *device, const char *action, gboolean ass
                count++;
        }
 
-       priv->pending_actions = g_slist_append (priv->pending_actions, g_strdup (action));
+       data = pending_action_data_new (device, action, timeout_handler, user_data);
+       priv->pending_actions = g_slist_append (priv->pending_actions, data);
        count++;
-
-       nm_log_dbg (LOGD_DEVICE, "(%s): add_pending_action (%d): '%s'",
-                   nm_device_get_iface (device),
-                   count,
-                   action);
+       if (timeout_ms) {
+               data->timeout_id = g_timeout_add (timeout_ms, pending_action_timeout_cb, data);
+               nm_log_dbg (LOGD_DEVICE, "(%s): add_pending_action (%d): '%s' (timeout=%u, %lu msec)",
+                           nm_device_get_iface (device),
+                           count,
+                           action,
+                           data->timeout_id, (long unsigned) timeout_ms);
+       } else {
+               nm_log_dbg (LOGD_DEVICE, "(%s): add_pending_action (%d): '%s'",
+                           nm_device_get_iface (device),
+                           count,
+                           action);
+       }
 
        if (count == 1)
                g_object_notify (G_OBJECT (device), NM_DEVICE_HAS_PENDING_ACTION);
@@ -7758,18 +7854,30 @@ nm_device_remove_pending_action (NMDevice *device, const char *action, gboolean
        NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
        GSList *iter;
        guint count = 0;
+       PendingActionData *data;
 
        g_return_val_if_fail (action, FALSE);
 
        for (iter = priv->pending_actions; iter; iter = iter->next) {
-               if (!strcmp (action, iter->data)) {
-                       g_free (iter->data);
-                       priv->pending_actions = g_slist_delete_link (priv->pending_actions, iter);
-                       nm_log_dbg (LOGD_DEVICE, "(%s): remove_pending_action (%d): '%s'",
-                                   nm_device_get_iface (device),
-                                   count + g_slist_length (iter),
-                                   action);
+               data = iter->data;
 
+               if (!strcmp (action, data->action)) {
+                       priv->pending_actions = g_slist_delete_link (priv->pending_actions, iter);
+                       if (data->timeout_id) {
+                               g_source_remove (data->timeout_id);
+                               nm_log_dbg (LOGD_DEVICE, "(%s): remove_pending_action (%d): '%s' 
(timeout=%u)",
+                                           nm_device_get_iface (device),
+                                           count + g_slist_length (iter),
+                                           action,
+                                           data->timeout_id);
+                               data->handler (device, action, FALSE, data->user_data);
+                       } else {
+                               nm_log_dbg (LOGD_DEVICE, "(%s): remove_pending_action (%d): '%s'",
+                                           nm_device_get_iface (device),
+                                           count + g_slist_length (iter),
+                                           action);
+                       }
+                       g_free (data);
                        if (priv->pending_actions == NULL)
                                g_object_notify (G_OBJECT (device), NM_DEVICE_HAS_PENDING_ACTION);
                        return TRUE;
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index d70af3b..9b61f9f 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -351,7 +351,9 @@ void nm_device_queue_activation (NMDevice *device, NMActRequest *req);
 
 gboolean nm_device_supports_vlans (NMDevice *device);
 
+typedef gboolean (*PendingActionTimeoutCb) (NMDevice *device, const char *action, gboolean is_timeout, 
gpointer user_data);
 gboolean nm_device_add_pending_action    (NMDevice *device, const char *action, gboolean 
assert_not_yet_pending);
+gboolean nm_device_add_pending_action_with_timeout (NMDevice *device, const char *action, gboolean 
assert_not_yet_pending, guint32 timeout_ms, PendingActionTimeoutCb timeout_handler, gpointer user_data);
 gboolean nm_device_remove_pending_action (NMDevice *device, const char *action, gboolean assert_is_pending);
 gboolean nm_device_has_pending_action    (NMDevice *device);
 
-- 
1.9.0



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]