+static void trigger_command_start(struct uloop_timeout *timeout)
+{
+ static const struct runqueue_task_type trigger_command_type = {
+ .run = trigger_command_run,
+ .cancel = runqueue_process_cancel_cb,
+ .kill = runqueue_process_kill_cb,
+ };
+ struct trigger_command *cmd = container_of(timeout, struct trigger_command, delay);
+
+ cmd->proc.task.type = &trigger_command_type;
+ cmd->proc.task.complete = trigger_command_complete;
+ runqueue_task_add(&q, &cmd->proc.task, false);
+}
+
+static void trigger_command_add(struct trigger *t, struct blob_attr *data)
+{
+ struct trigger_command *cmd;
+ int remaining;
+
+ cmd = avl_find_element(&trigger_pending, data, cmd, avl);
+ if (cmd) {
+ /* Command currently running? */
+ if (!cmd->delay.pending) {
+ cmd->requeue = true;
+ return;
+ }
+
+ /* Extend timer if trigger timeout is bigger than remaining time */
+ remaining = uloop_timeout_remaining(&cmd->delay);
+ if (remaining < t->timeout)
+ uloop_timeout_set(&cmd->delay, t->timeout);
+
+ return;
+ }
+
+ cmd = calloc(1, sizeof(*cmd) + blob_pad_len(data));
+ if (!cmd)
+ return;
+
+ cmd->avl.key = cmd->data;
+ cmd->delay.cb = trigger_command_start;
+ memcpy(cmd->data, data, blob_pad_len(data));
+ avl_insert(&trigger_pending, &cmd->avl);
+ uloop_timeout_set(&cmd->delay, t->timeout > 0 ? t->timeout : 1);
+}