device: Add device critical section API
This commit is contained in:
parent
23a4f5b77a
commit
77756e111d
4 changed files with 110 additions and 1 deletions
|
@ -79,6 +79,11 @@ typedef struct
|
||||||
gboolean wait_for_finger;
|
gboolean wait_for_finger;
|
||||||
FpFingerStatusFlags finger_status;
|
FpFingerStatusFlags finger_status;
|
||||||
|
|
||||||
|
/* Driver critical sections */
|
||||||
|
guint critical_section;
|
||||||
|
GSource *critical_section_flush_source;
|
||||||
|
gboolean cancel_queued;
|
||||||
|
|
||||||
/* Device temperature model information and state */
|
/* Device temperature model information and state */
|
||||||
GSource *temp_timeout;
|
GSource *temp_timeout;
|
||||||
FpTemperature temp_current;
|
FpTemperature temp_current;
|
||||||
|
|
|
@ -94,7 +94,10 @@ fp_device_cancel_in_idle_cb (gpointer user_data)
|
||||||
|
|
||||||
priv->current_idle_cancel_source = NULL;
|
priv->current_idle_cancel_source = NULL;
|
||||||
|
|
||||||
cls->cancel (self);
|
if (priv->critical_section)
|
||||||
|
priv->cancel_queued = TRUE;
|
||||||
|
else
|
||||||
|
cls->cancel (self);
|
||||||
|
|
||||||
fpi_device_report_finger_status (self, FP_FINGER_STATUS_NONE);
|
fpi_device_report_finger_status (self, FP_FINGER_STATUS_NONE);
|
||||||
|
|
||||||
|
|
|
@ -808,6 +808,104 @@ fpi_device_action_error (FpDevice *device,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_device_critical_enter:
|
||||||
|
* @device: The #FpDevice
|
||||||
|
*
|
||||||
|
* Enter a critical section in the driver code where no outside calls from
|
||||||
|
* libfprint should happen. Drivers can already assume that everything
|
||||||
|
* happens from the same thread, however, that still allows e.g. the cancel
|
||||||
|
* vfunc to be called at any point in time.
|
||||||
|
*
|
||||||
|
* Using this kind of critical section, the driver can assume that libfprint
|
||||||
|
* will not forward any external requests to the driver for the time being.
|
||||||
|
* This is for example useful to prevent cancellation while the device is being
|
||||||
|
* set up. Or, said differently, using this feature means that the cancel
|
||||||
|
* handler is able to make more assumptions about the current state.
|
||||||
|
*
|
||||||
|
* Please note that the driver is not shielded from all external changes. For
|
||||||
|
* example the cancellable as returned by fpi_device_get_cancellable() will
|
||||||
|
* still change immediately.
|
||||||
|
*
|
||||||
|
* The driver may call this function multiple times, but must also ensure that
|
||||||
|
* fpi_device_critical_leave() is called an equal amount of times and that all
|
||||||
|
* critical sections are left before command completion.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_device_critical_enter (FpDevice *device)
|
||||||
|
{
|
||||||
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||||
|
|
||||||
|
g_return_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE);
|
||||||
|
|
||||||
|
priv->critical_section += 1;
|
||||||
|
|
||||||
|
/* Stop flushing events if that was previously queued. */
|
||||||
|
if (priv->critical_section_flush_source)
|
||||||
|
g_source_destroy (priv->critical_section_flush_source);
|
||||||
|
priv->critical_section_flush_source = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
fpi_device_critical_section_flush_idle_cb (FpDevice *device)
|
||||||
|
{
|
||||||
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||||
|
FpDeviceClass *cls = FP_DEVICE_GET_CLASS (device);
|
||||||
|
|
||||||
|
if (priv->cancel_queued)
|
||||||
|
{
|
||||||
|
/* Cancellation must only happen if the driver is busy. */
|
||||||
|
if (priv->current_action != FPI_DEVICE_ACTION_NONE &&
|
||||||
|
priv->current_task_idle_return_source == NULL)
|
||||||
|
cls->cancel (device);
|
||||||
|
priv->cancel_queued = FALSE;
|
||||||
|
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->critical_section_flush_source = NULL;
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fpi_device_critical_leave:
|
||||||
|
* @device: The #FpDevice
|
||||||
|
*
|
||||||
|
* Leave a critical section started by fpi_device_critical_enter().
|
||||||
|
*
|
||||||
|
* Once all critical sections have been left, libfprint will start flushing
|
||||||
|
* out the queued up requests. This is done from the mainloop and the driver
|
||||||
|
* is protected from reentrency issues.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
fpi_device_critical_leave (FpDevice *device)
|
||||||
|
{
|
||||||
|
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||||
|
|
||||||
|
g_return_if_fail (priv->current_action != FPI_DEVICE_ACTION_NONE);
|
||||||
|
g_return_if_fail (priv->critical_section);
|
||||||
|
|
||||||
|
priv->critical_section -= 1;
|
||||||
|
if (priv->critical_section)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* We left the critical section, make sure a flush is queued. */
|
||||||
|
if (priv->critical_section_flush_source)
|
||||||
|
return;
|
||||||
|
|
||||||
|
priv->critical_section_flush_source = g_idle_source_new ();
|
||||||
|
g_source_set_callback (priv->critical_section_flush_source,
|
||||||
|
(GSourceFunc) fpi_device_critical_section_flush_idle_cb,
|
||||||
|
device,
|
||||||
|
NULL);
|
||||||
|
g_source_set_name (priv->critical_section_flush_source,
|
||||||
|
"Flush libfprint driver critical section");
|
||||||
|
g_source_attach (priv->critical_section_flush_source,
|
||||||
|
g_task_get_context (priv->current_task));
|
||||||
|
g_source_unref (priv->critical_section_flush_source);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
clear_device_cancel_action (FpDevice *device)
|
clear_device_cancel_action (FpDevice *device)
|
||||||
{
|
{
|
||||||
|
|
|
@ -264,6 +264,9 @@ void fpi_device_update_features (FpDevice *device,
|
||||||
void fpi_device_action_error (FpDevice *device,
|
void fpi_device_action_error (FpDevice *device,
|
||||||
GError *error);
|
GError *error);
|
||||||
|
|
||||||
|
void fpi_device_critical_enter (FpDevice *device);
|
||||||
|
void fpi_device_critical_leave (FpDevice *device);
|
||||||
|
|
||||||
void fpi_device_probe_complete (FpDevice *device,
|
void fpi_device_probe_complete (FpDevice *device,
|
||||||
const gchar *device_id,
|
const gchar *device_id,
|
||||||
const gchar *device_name,
|
const gchar *device_name,
|
||||||
|
|
Loading…
Reference in a new issue