Blob Blame History Raw
From d35cadd5fd81067bfc5bf6f5595b98d4227ad190 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
Date: Fri, 22 Nov 2019 17:19:27 +0100
Subject: [PATCH 058/181] fpi-ssm: Add possibility to jump to a state (or next
 one) with delay

This allows to have an automatic cleanup of the timeout source when the
the callback is reached and to avoid to do further state changes in the
middle.
---
 doc/libfprint-sections.txt |   3 +
 libfprint/fpi-ssm.c        | 118 +++++++++++++++++++++++++++++++++++++
 libfprint/fpi-ssm.h        |   6 ++
 3 files changed, 127 insertions(+)

diff --git a/doc/libfprint-sections.txt b/doc/libfprint-sections.txt
index 0abe584..9fb01bd 100644
--- a/doc/libfprint-sections.txt
+++ b/doc/libfprint-sections.txt
@@ -215,7 +215,10 @@ fpi_ssm_free
 fpi_ssm_start
 fpi_ssm_start_subsm
 fpi_ssm_next_state
+fpi_ssm_next_state_delayed
 fpi_ssm_jump_to_state
+fpi_ssm_jump_to_state_delayed
+fpi_ssm_cancel_delayed_state_change
 fpi_ssm_mark_completed
 fpi_ssm_mark_failed
 fpi_ssm_set_data
diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c
index 5299e2d..38186d2 100644
--- a/libfprint/fpi-ssm.c
+++ b/libfprint/fpi-ssm.c
@@ -87,6 +87,7 @@ struct _FpiSsm
   int                     nr_states;
   int                     cur_state;
   gboolean                completed;
+  GSource                *timeout;
   GError                 *error;
   FpiSsmCompletedCallback callback;
   FpiSsmHandlerCallback   handler;
@@ -170,6 +171,7 @@ fpi_ssm_free (FpiSsm *machine)
   if (machine->ssm_data_destroy)
     g_clear_pointer (&machine->ssm_data, machine->ssm_data_destroy);
   g_clear_pointer (&machine->error, g_error_free);
+  g_clear_pointer (&machine->timeout, g_source_destroy);
   g_free (machine);
 }
 
@@ -231,7 +233,9 @@ __subsm_complete (FpiSsm *ssm, FpDevice *_dev, GError *error)
 void
 fpi_ssm_start_subsm (FpiSsm *parent, FpiSsm *child)
 {
+  BUG_ON (parent->timeout);
   child->parentsm = parent;
+  g_clear_pointer (&parent->timeout, g_source_destroy);
   fpi_ssm_start (child, __subsm_complete);
 }
 
@@ -246,7 +250,12 @@ void
 fpi_ssm_mark_completed (FpiSsm *machine)
 {
   BUG_ON (machine->completed);
+  BUG_ON (machine->timeout);
+  BUG_ON (machine->timeout != NULL);
+
+  g_clear_pointer (&machine->timeout, g_source_destroy);
   machine->completed = TRUE;
+
   if (machine->error)
     fp_dbg ("%p completed with error: %s", machine, machine->error->message);
   else
@@ -297,6 +306,10 @@ fpi_ssm_next_state (FpiSsm *machine)
   g_return_if_fail (machine != NULL);
 
   BUG_ON (machine->completed);
+  BUG_ON (machine->timeout != NULL);
+
+  g_clear_pointer (&machine->timeout, g_source_destroy);
+
   machine->cur_state++;
   if (machine->cur_state == machine->nr_states)
     fpi_ssm_mark_completed (machine);
@@ -304,6 +317,56 @@ fpi_ssm_next_state (FpiSsm *machine)
     __ssm_call_handler (machine);
 }
 
+void
+fpi_ssm_cancel_delayed_state_change (FpiSsm *machine)
+{
+  g_return_if_fail (machine);
+  BUG_ON (machine->completed);
+  BUG_ON (machine->timeout == NULL);
+
+  g_clear_pointer (&machine->timeout, g_source_destroy);
+}
+
+static void
+on_device_timeout_next_state (FpDevice *dev,
+                              gpointer  user_data)
+{
+  FpiSsm *machine = user_data;
+
+  machine->timeout = NULL;
+  fpi_ssm_next_state (machine);
+}
+
+/**
+ * fpi_ssm_next_state_delayed:
+ * @machine: an #FpiSsm state machine
+ * @delay: the milliseconds to wait before switching to the next state
+ *
+ * Iterate to next state of a state machine with a delay of @delay ms. If the
+ * current state is the last state, then the state machine will be marked as
+ * completed, as if calling fpi_ssm_mark_completed().
+ */
+void
+fpi_ssm_next_state_delayed (FpiSsm *machine,
+                            int     delay)
+{
+  g_autofree char *source_name = NULL;
+
+  g_return_if_fail (machine != NULL);
+  BUG_ON (machine->completed);
+  BUG_ON (machine->timeout != NULL);
+
+  g_clear_pointer (&machine->timeout, g_source_destroy);
+  machine->timeout = fpi_device_add_timeout (machine->dev, delay,
+                                             on_device_timeout_next_state,
+                                             machine);
+
+  source_name = g_strdup_printf ("[%s] ssm %p jump to next state %d",
+                                 fp_device_get_device_id (machine->dev),
+                                 machine, machine->cur_state + 1);
+  g_source_set_name (machine->timeout, source_name);
+}
+
 /**
  * fpi_ssm_jump_to_state:
  * @machine: an #FpiSsm state machine
@@ -318,10 +381,65 @@ fpi_ssm_jump_to_state (FpiSsm *machine, int state)
 {
   BUG_ON (machine->completed);
   BUG_ON (state < 0 || state >= machine->nr_states);
+  BUG_ON (machine->timeout != NULL);
+
+  g_clear_pointer (&machine->timeout, g_source_destroy);
   machine->cur_state = state;
   __ssm_call_handler (machine);
 }
 
+typedef struct
+{
+  FpiSsm *machine;
+  int     next_state;
+} FpiSsmJumpToStateDelayedData;
+
+static void
+on_device_timeout_jump_to_state (FpDevice *dev,
+                                 gpointer  user_data)
+{
+  FpiSsmJumpToStateDelayedData *data = user_data;
+
+  data->machine->timeout = NULL;
+  fpi_ssm_jump_to_state (data->machine, data->next_state);
+}
+
+/**
+ * fpi_ssm_jump_to_state_delayed:
+ * @machine: an #FpiSsm state machine
+ * @state: the state to jump to
+ * @delay: the milliseconds to wait before switching to @state state
+ *
+ * Jump to the @state state with a delay of @delay milliseconds, bypassing
+ * intermediary states.
+ */
+void
+fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
+                               int     state,
+                               int     delay)
+{
+  FpiSsmJumpToStateDelayedData *data;
+  g_autofree char *source_name = NULL;
+
+  g_return_if_fail (machine != NULL);
+  BUG_ON (machine->completed);
+  BUG_ON (machine->timeout != NULL);
+
+  data = g_new0 (FpiSsmJumpToStateDelayedData, 1);
+  data->machine = machine;
+  data->next_state = state;
+
+  g_clear_pointer (&machine->timeout, g_source_destroy);
+  machine->timeout = fpi_device_add_timeout_full (machine->dev, delay,
+                                                  on_device_timeout_jump_to_state,
+                                                  data, g_free);
+
+  source_name = g_strdup_printf ("[%s] ssm %p jump to state %d",
+                                 fp_device_get_device_id (machine->dev),
+                                 machine, state);
+  g_source_set_name (machine->timeout, source_name);
+}
+
 /**
  * fpi_ssm_get_cur_state:
  * @machine: an #FpiSsm state machine
diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h
index 57e7d10..05e6cf0 100644
--- a/libfprint/fpi-ssm.h
+++ b/libfprint/fpi-ssm.h
@@ -73,6 +73,12 @@ void fpi_ssm_start_subsm (FpiSsm *parent,
 void fpi_ssm_next_state (FpiSsm *machine);
 void fpi_ssm_jump_to_state (FpiSsm *machine,
                             int     state);
+void fpi_ssm_next_state_delayed (FpiSsm *machine,
+                                 int     delay);
+void fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
+                                    int     state,
+                                    int     delay);
+void fpi_ssm_cancel_delayed_state_change (FpiSsm *machine);
 void fpi_ssm_mark_completed (FpiSsm *machine);
 void fpi_ssm_mark_failed (FpiSsm *machine,
                           GError *error);
-- 
2.24.1