Blob Blame History Raw
From 37a007317e5de27eb68a667bace42961c5c73b33 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
Date: Thu, 28 Nov 2019 19:24:55 +0100
Subject: [PATCH 062/181] fpi-ssm: Make delayed actions cancellable

Add a GCancellable parameter to fpi_ssm_nex_state_delayed and
fpi_ssm_jump_to_state_delayed() so that it's possible to cancel an action
from the caller and in case the driver wants to cancel a delayed operation
when a device action has been cancelled.
---
 libfprint/drivers/elan.c    |   2 +-
 libfprint/drivers/uru4000.c |   6 +-
 libfprint/drivers/vfs0050.c |   5 +-
 libfprint/drivers/vfs101.c  |  14 ++--
 libfprint/drivers/vfs301.c  |   4 +-
 libfprint/drivers/vfs5011.c |   2 +-
 libfprint/fpi-ssm.c         | 123 ++++++++++++++++++++++++++++++------
 libfprint/fpi-ssm.h         |  12 ++--
 8 files changed, 127 insertions(+), 41 deletions(-)

diff --git a/libfprint/drivers/elan.c b/libfprint/drivers/elan.c
index f622988..7c7fb26 100644
--- a/libfprint/drivers/elan.c
+++ b/libfprint/drivers/elan.c
@@ -752,7 +752,7 @@ calibrate_run_state (FpiSsm *ssm, FpDevice *dev)
           if (self->calib_status == 0x00 &&
               self->last_read[0] == 0x01)
             self->calib_status = 0x01;
-          fpi_ssm_next_state_delayed (ssm, 50);
+          fpi_ssm_next_state_delayed (ssm, 50, NULL);
         }
       break;
 
diff --git a/libfprint/drivers/uru4000.c b/libfprint/drivers/uru4000.c
index e15f1ca..122544d 100644
--- a/libfprint/drivers/uru4000.c
+++ b/libfprint/drivers/uru4000.c
@@ -864,7 +864,7 @@ rebootpwr_run_state (FpiSsm *ssm, FpDevice *_dev)
         }
       else
         {
-          fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT);
+          fpi_ssm_jump_to_state_delayed (ssm, 10, REBOOTPWR_GET_HWSTAT, NULL);
         }
       break;
     }
@@ -946,11 +946,11 @@ powerup_run_state (FpiSsm *ssm, FpDevice *_dev)
         }
       else if (!self->profile->auth_cr)
         {
-          fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10);
+          fpi_ssm_jump_to_state_delayed (ssm, POWERUP_SET_HWSTAT, 10, NULL);
         }
       else
         {
-          fpi_ssm_next_state_delayed (ssm, 10);
+          fpi_ssm_next_state_delayed (ssm, 10, NULL);
         }
       break;
 
diff --git a/libfprint/drivers/vfs0050.c b/libfprint/drivers/vfs0050.c
index 22e9ae9..9b99dc3 100644
--- a/libfprint/drivers/vfs0050.c
+++ b/libfprint/drivers/vfs0050.c
@@ -608,7 +608,7 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
       clear_data (self);
 
       /* Wait for probable vdev->active changing */
-      fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT);
+      fpi_ssm_next_state_delayed (ssm, VFS_SSM_TIMEOUT, NULL);
       break;
 
     case SSM_NEXT_RECEIVE:
@@ -627,7 +627,8 @@ activate_ssm (FpiSsm *ssm, FpDevice *dev)
 
     case SSM_WAIT_ANOTHER_SCAN:
       /* Orange light is on now */
-      fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT);
+      fpi_ssm_jump_to_state_delayed (ssm, SSM_TURN_ON, VFS_SSM_ORANGE_TIMEOUT,
+                                     NULL);
       break;
 
     default:
diff --git a/libfprint/drivers/vfs101.c b/libfprint/drivers/vfs101.c
index 7020726..ccce7db 100644
--- a/libfprint/drivers/vfs101.c
+++ b/libfprint/drivers/vfs101.c
@@ -785,7 +785,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
 
     case M_LOOP_0_SLEEP:
       /* Wait fingerprint scanning */
-      fpi_ssm_next_state_delayed (ssm, 50);
+      fpi_ssm_next_state_delayed (ssm, 50, NULL);
       break;
 
     case M_LOOP_0_GET_STATE:
@@ -828,7 +828,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
       img_extract (ssm, dev);
 
       /* Wait handling image */
-      fpi_ssm_next_state_delayed (ssm, 10);
+      fpi_ssm_next_state_delayed (ssm, 10, NULL);
       break;
 
     case M_LOOP_0_CHECK_ACTION:
@@ -851,7 +851,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
       if (vfs_finger_state (self) == VFS_FINGER_PRESENT)
         {
           fpi_image_device_report_finger_status (dev, TRUE);
-          fpi_ssm_next_state_delayed (ssm, 250);
+          fpi_ssm_next_state_delayed (ssm, 250, NULL);
         }
       else
         {
@@ -881,7 +881,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
 
     case M_LOOP_1_SLEEP:
       /* Wait fingerprint scanning */
-      fpi_ssm_next_state_delayed (ssm, 10);
+      fpi_ssm_next_state_delayed (ssm, 10, NULL);
       break;
 
     case M_LOOP_2_ABORT_PRINT:
@@ -917,7 +917,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
         {
           /* Wait aborting */
           self->counter++;
-          fpi_ssm_next_state_delayed (ssm, 100);
+          fpi_ssm_next_state_delayed (ssm, 100, NULL);
         }
       else
         {
@@ -1055,7 +1055,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
         {
           /* Wait aborting */
           self->counter++;
-          fpi_ssm_next_state_delayed (ssm, 100);
+          fpi_ssm_next_state_delayed (ssm, 100, NULL);
         }
       else
         {
@@ -1084,7 +1084,7 @@ m_init_state (FpiSsm *ssm, FpDevice *_dev)
             {
               /* Wait removing finger */
               self->counter++;
-              fpi_ssm_next_state_delayed (ssm, 250);
+              fpi_ssm_next_state_delayed (ssm, 250, NULL);
             }
           else
             {
diff --git a/libfprint/drivers/vfs301.c b/libfprint/drivers/vfs301.c
index 3870879..f912a36 100644
--- a/libfprint/drivers/vfs301.c
+++ b/libfprint/drivers/vfs301.c
@@ -97,7 +97,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
 
     case M_WAIT_PRINT:
       /* Wait fingerprint scanning */
-      fpi_ssm_next_state_delayed (ssm, 200);
+      fpi_ssm_next_state_delayed (ssm, 200, NULL);
       break;
 
     case M_CHECK_PRINT:
@@ -115,7 +115,7 @@ m_loop_state (FpiSsm *ssm, FpDevice *_dev)
 
     case M_READ_PRINT_WAIT:
       /* Wait fingerprint scanning */
-      fpi_ssm_next_state_delayed (ssm, 200);
+      fpi_ssm_next_state_delayed (ssm, 200, NULL);
       break;
 
     case M_READ_PRINT_POLL:
diff --git a/libfprint/drivers/vfs5011.c b/libfprint/drivers/vfs5011.c
index b769e31..ef318f2 100644
--- a/libfprint/drivers/vfs5011.c
+++ b/libfprint/drivers/vfs5011.c
@@ -704,7 +704,7 @@ activate_loop (FpiSsm *ssm, FpDevice *_dev)
       break;
 
     case DEV_ACTIVATE_DATA_COMPLETE:
-      fpi_ssm_next_state_delayed (ssm, 1);
+      fpi_ssm_next_state_delayed (ssm, 1, NULL);
       break;
 
     case DEV_ACTIVATE_PREPARE_NEXT_CAPTURE:
diff --git a/libfprint/fpi-ssm.c b/libfprint/fpi-ssm.c
index 19712ef..0f54b1d 100644
--- a/libfprint/fpi-ssm.c
+++ b/libfprint/fpi-ssm.c
@@ -88,6 +88,8 @@ struct _FpiSsm
   int                     cur_state;
   gboolean                completed;
   GSource                *timeout;
+  GCancellable           *cancellable;
+  gulong                  cancellable_id;
   GError                 *error;
   FpiSsmCompletedCallback callback;
   FpiSsmHandlerCallback   handler;
@@ -155,6 +157,81 @@ fpi_ssm_get_data (FpiSsm *machine)
   return machine->ssm_data;
 }
 
+static void
+fpi_ssm_clear_delayed_action (FpiSsm *machine)
+{
+  if (machine->cancellable_id)
+    {
+      g_cancellable_disconnect (machine->cancellable, machine->cancellable_id);
+      machine->cancellable_id = 0;
+    }
+
+  g_clear_object (&machine->cancellable);
+  g_clear_pointer (&machine->timeout, g_source_destroy);
+}
+
+typedef struct _CancelledActionIdleData
+{
+  gulong        cancellable_id;
+  GCancellable *cancellable;
+} CancelledActionIdleData;
+
+static gboolean
+on_delayed_action_cancelled_idle (gpointer user_data)
+{
+  CancelledActionIdleData *data = user_data;
+
+  g_cancellable_disconnect (data->cancellable, data->cancellable_id);
+  g_object_unref (data->cancellable);
+  g_free (data);
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+on_delayed_action_cancelled (GCancellable *cancellable,
+                             FpiSsm       *machine)
+{
+  CancelledActionIdleData *data;
+
+  g_clear_pointer (&machine->timeout, g_source_destroy);
+
+  data = g_new0 (CancelledActionIdleData, 1);
+  data->cancellable = g_steal_pointer (&machine->cancellable);
+  data->cancellable_id = machine->cancellable_id;
+  machine->cancellable_id = 0;
+
+  g_idle_add_full (G_PRIORITY_HIGH_IDLE, on_delayed_action_cancelled_idle,
+                   data, NULL);
+}
+
+static void
+fpi_ssm_set_delayed_action_timeout (FpiSsm        *machine,
+                                    int            delay,
+                                    FpTimeoutFunc  callback,
+                                    GCancellable  *cancellable,
+                                    gpointer       user_data,
+                                    GDestroyNotify destroy_func)
+{
+  BUG_ON (machine->completed);
+  BUG_ON (machine->timeout != NULL);
+
+  fpi_ssm_clear_delayed_action (machine);
+
+  if (cancellable != NULL)
+    {
+      g_set_object (&machine->cancellable, cancellable);
+
+      machine->cancellable_id =
+        g_cancellable_connect (machine->cancellable,
+                               G_CALLBACK (on_delayed_action_cancelled),
+                               machine, NULL);
+    }
+
+  machine->timeout = fpi_device_add_timeout (machine->dev, delay, callback,
+                                             user_data, destroy_func);
+}
+
 /**
  * fpi_ssm_free:
  * @machine: an #FpiSsm state machine
@@ -173,7 +250,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);
+  fpi_ssm_clear_delayed_action (machine);
   g_free (machine);
 }
 
@@ -254,7 +331,8 @@ fpi_ssm_mark_completed (FpiSsm *machine)
   BUG_ON (machine->completed);
   BUG_ON (machine->timeout != NULL);
 
-  g_clear_pointer (&machine->timeout, g_source_destroy);
+  fpi_ssm_clear_delayed_action (machine);
+
   machine->completed = TRUE;
 
   if (machine->error)
@@ -309,7 +387,7 @@ fpi_ssm_next_state (FpiSsm *machine)
   BUG_ON (machine->completed);
   BUG_ON (machine->timeout != NULL);
 
-  g_clear_pointer (&machine->timeout, g_source_destroy);
+  fpi_ssm_clear_delayed_action (machine);
 
   machine->cur_state++;
   if (machine->cur_state == machine->nr_states)
@@ -325,7 +403,7 @@ fpi_ssm_cancel_delayed_state_change (FpiSsm *machine)
   BUG_ON (machine->completed);
   BUG_ON (machine->timeout == NULL);
 
-  g_clear_pointer (&machine->timeout, g_source_destroy);
+  fpi_ssm_clear_delayed_action (machine);
 }
 
 static void
@@ -342,25 +420,26 @@ on_device_timeout_next_state (FpDevice *dev,
  * fpi_ssm_next_state_delayed:
  * @machine: an #FpiSsm state machine
  * @delay: the milliseconds to wait before switching to the next state
+ * @cancellable: (nullable): a #GCancellable to cancel the delayed operation
  *
  * 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().
+ * Passing a valid #GCancellable will cause the action to be cancelled when
+ * @cancellable is.
  */
 void
-fpi_ssm_next_state_delayed (FpiSsm *machine,
-                            int     delay)
+fpi_ssm_next_state_delayed (FpiSsm       *machine,
+                            int           delay,
+                            GCancellable *cancellable)
 {
   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, NULL);
+  fpi_ssm_set_delayed_action_timeout (machine, delay,
+                                      on_device_timeout_next_state, cancellable,
+                                      machine, NULL);
 
   source_name = g_strdup_printf ("[%s] ssm %p jump to next state %d",
                                  fp_device_get_device_id (machine->dev),
@@ -384,7 +463,8 @@ fpi_ssm_jump_to_state (FpiSsm *machine, int state)
   BUG_ON (state < 0 || state >= machine->nr_states);
   BUG_ON (machine->timeout != NULL);
 
-  g_clear_pointer (&machine->timeout, g_source_destroy);
+  fpi_ssm_clear_delayed_action (machine);
+
   machine->cur_state = state;
   __ssm_call_handler (machine);
 }
@@ -410,14 +490,18 @@ on_device_timeout_jump_to_state (FpDevice *dev,
  * @machine: an #FpiSsm state machine
  * @state: the state to jump to
  * @delay: the milliseconds to wait before switching to @state state
+ * @cancellable: (nullable): a #GCancellable to cancel the delayed operation
  *
  * Jump to the @state state with a delay of @delay milliseconds, bypassing
  * intermediary states.
+ * Passing a valid #GCancellable will cause the action to be cancelled when
+ * @cancellable is.
  */
 void
-fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
-                               int     state,
-                               int     delay)
+fpi_ssm_jump_to_state_delayed (FpiSsm       *machine,
+                               int           state,
+                               int           delay,
+                               GCancellable *cancellable)
 {
   FpiSsmJumpToStateDelayedData *data;
   g_autofree char *source_name = NULL;
@@ -430,10 +514,9 @@ fpi_ssm_jump_to_state_delayed (FpiSsm *machine,
   data->machine = machine;
   data->next_state = state;
 
-  g_clear_pointer (&machine->timeout, g_source_destroy);
-  machine->timeout = fpi_device_add_timeout (machine->dev, delay,
-                                             on_device_timeout_jump_to_state,
-                                             data, g_free);
+  fpi_ssm_set_delayed_action_timeout (machine, delay,
+                                      on_device_timeout_jump_to_state,
+                                      cancellable, data, g_free);
 
   source_name = g_strdup_printf ("[%s] ssm %p jump to state %d",
                                  fp_device_get_device_id (machine->dev),
diff --git a/libfprint/fpi-ssm.h b/libfprint/fpi-ssm.h
index b426fff..8dff27d 100644
--- a/libfprint/fpi-ssm.h
+++ b/libfprint/fpi-ssm.h
@@ -73,11 +73,13 @@ 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_next_state_delayed (FpiSsm       *machine,
+                                 int           delay,
+                                 GCancellable *cancellable);
+void fpi_ssm_jump_to_state_delayed (FpiSsm       *machine,
+                                    int           state,
+                                    int           delay,
+                                    GCancellable *cancellable);
 void fpi_ssm_cancel_delayed_state_change (FpiSsm *machine);
 void fpi_ssm_mark_completed (FpiSsm *machine);
 void fpi_ssm_mark_failed (FpiSsm *machine,
-- 
2.24.1