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;
|
||||
FpFingerStatusFlags finger_status;
|
||||
|
||||
/* Driver critical sections */
|
||||
guint critical_section;
|
||||
GSource *critical_section_flush_source;
|
||||
gboolean cancel_queued;
|
||||
|
||||
/* Device temperature model information and state */
|
||||
GSource *temp_timeout;
|
||||
FpTemperature temp_current;
|
||||
|
|
|
@ -94,7 +94,10 @@ fp_device_cancel_in_idle_cb (gpointer user_data)
|
|||
|
||||
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);
|
||||
|
||||
|
|
|
@ -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
|
||||
clear_device_cancel_action (FpDevice *device)
|
||||
{
|
||||
|
|
|
@ -264,6 +264,9 @@ void fpi_device_update_features (FpDevice *device,
|
|||
void fpi_device_action_error (FpDevice *device,
|
||||
GError *error);
|
||||
|
||||
void fpi_device_critical_enter (FpDevice *device);
|
||||
void fpi_device_critical_leave (FpDevice *device);
|
||||
|
||||
void fpi_device_probe_complete (FpDevice *device,
|
||||
const gchar *device_id,
|
||||
const gchar *device_name,
|
||||
|
|
Loading…
Reference in a new issue