From ff67bf5a16cdbc9d738b1f3072fca7fd93f25fa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 28 Nov 2019 19:24:55 +0100 Subject: [PATCH] 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,