Add cancellation support.

To be able to cancel an operation, an application should register a
callback function that returns a non-zero value whenever the active
operaton should be cancelled. A backend can invoke this callback function
to query the application for a pending cancellation request.
This commit is contained in:
Jef Driesen 2010-02-15 13:16:26 +00:00
parent de889f9d46
commit f6d35fa2c2
15 changed files with 125 additions and 1 deletions

View File

@ -22,6 +22,7 @@
#include <stdio.h> // fopen, fwrite, fclose
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#ifndef _MSC_VER
#include <unistd.h>
@ -122,6 +123,25 @@ fpconvert (const char *fingerprint)
return buffer;
}
volatile sig_atomic_t g_cancel = 0;
void
sighandler (int signum)
{
#ifndef _WIN32
// Restore the default signal handler.
signal (signum, SIG_DFL);
#endif
g_cancel = 1;
}
static int
cancel_cb (void *userdata)
{
return g_cancel;
}
static void
event_cb (device_t *device, device_event_t event, const void *data, void *userdata)
{
@ -189,6 +209,8 @@ errmsg (device_status_t rc)
return "Protocol error";
case DEVICE_STATUS_TIMEOUT:
return "Timeout";
case DEVICE_STATUS_CANCELLED:
return "Cancelled";
default:
return "Unknown error";
}
@ -308,6 +330,15 @@ dowork (device_type_t backend, const char *devname, const char *filename, int me
return rc;
}
// Register the cancellation handler.
message ("Registering the cancellation handler.\n");
rc = device_set_cancel (device, cancel_cb, NULL);
if (rc != DEVICE_STATUS_SUCCESS) {
WARNING ("Error registering the cancellation handler.");
device_close (device);
return rc;
}
// Register the fingerprint data.
if (fingerprint) {
message ("Registering the fingerprint data.\n");
@ -425,6 +456,8 @@ main (int argc, char *argv[])
return EXIT_FAILURE;
}
signal (SIGINT, sighandler);
message_set_logfile (logfile);
dc_buffer_t *fp = fpconvert (fingerprint);

View File

@ -43,6 +43,9 @@ struct device_t {
unsigned int event_mask;
device_event_callback_t event_callback;
void *event_userdata;
// Cancellation support.
device_cancel_callback_t cancel_callback;
void *cancel_userdata;
};
struct device_backend_t {
@ -69,6 +72,9 @@ device_init (device_t *device, const device_backend_t *backend);
void
device_event_emit (device_t *device, device_event_t event, const void *data);
int
device_is_cancelled (device_t *device);
device_status_t
device_dump_read (device_t *device, unsigned char data[], unsigned int size, unsigned int blocksize);

View File

@ -33,6 +33,9 @@ device_init (device_t *device, const device_backend_t *backend)
device->event_mask = 0;
device->event_callback = NULL;
device->event_userdata = NULL;
device->cancel_callback = NULL;
device->cancel_userdata = NULL;
}
@ -46,6 +49,19 @@ device_get_type (device_t *device)
}
device_status_t
device_set_cancel (device_t *device, device_cancel_callback_t callback, void *userdata)
{
if (device == NULL)
return DEVICE_STATUS_UNSUPPORTED;
device->cancel_callback = callback;
device->cancel_userdata = userdata;
return DEVICE_STATUS_SUCCESS;
}
device_status_t
device_set_events (device_t *device, unsigned int events, device_event_callback_t callback, void *userdata)
{
@ -223,3 +239,16 @@ device_event_emit (device_t *device, device_event_t event, const void *data)
device->event_callback (device, event, data, device->event_userdata);
}
int
device_is_cancelled (device_t *device)
{
if (device == NULL)
return 0;
if (device->cancel_callback == NULL)
return 0;
return device->cancel_callback (device->cancel_userdata);
}

View File

@ -59,7 +59,8 @@ typedef enum device_status_t {
DEVICE_STATUS_IO = -4,
DEVICE_STATUS_TIMEOUT = -5,
DEVICE_STATUS_PROTOCOL = -6,
DEVICE_STATUS_MEMORY = -7
DEVICE_STATUS_MEMORY = -7,
DEVICE_STATUS_CANCELLED = -8
} device_status_t;
typedef enum device_event_t {
@ -87,12 +88,16 @@ typedef struct device_clock_t {
dc_ticks_t systime;
} device_clock_t;
typedef int (*device_cancel_callback_t) (void *userdata);
typedef void (*device_event_callback_t) (device_t *device, device_event_t event, const void *data, void *userdata);
typedef int (*dive_callback_t) (const unsigned char *data, unsigned int size, const unsigned char *fingerprint, unsigned int fsize, void *userdata);
device_type_t device_get_type (device_t *device);
device_status_t device_set_cancel (device_t *device, device_cancel_callback_t callback, void *userdata);
device_status_t device_set_events (device_t *device, unsigned int events, device_event_callback_t callback, void *userdata);
device_status_t device_set_fingerprint (device_t *device, const unsigned char data[], unsigned int size);

View File

@ -43,6 +43,7 @@ device_dump
device_foreach
device_get_type
device_read
device_set_cancel
device_set_events
device_set_fingerprint
device_version

View File

@ -228,6 +228,11 @@ mares_puck_make_ascii (const unsigned char raw[], unsigned int rsize, unsigned c
static device_status_t
mares_puck_packet (mares_puck_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
{
device_t *abstract = (device_t *) device;
if (device_is_cancelled (abstract))
return DEVICE_STATUS_CANCELLED;
// Send the command to the device.
int n = serial_write (device->port, command, csize);
if (n != csize) {

View File

@ -88,6 +88,8 @@ device_is_oceanic_atom2 (device_t *abstract)
static device_status_t
oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
{
device_t *abstract = (device_t *) device;
// Send the command to the device. If the device responds with an
// ACK byte, the command was received successfully and the answer
// (if any) follows after the ACK byte. If the device responds with
@ -97,6 +99,9 @@ oceanic_atom2_transfer (oceanic_atom2_device_t *device, const unsigned char comm
unsigned int nretries = 0;
unsigned char response = NAK;
while (response == NAK) {
if (device_is_cancelled (abstract))
return DEVICE_STATUS_CANCELLED;
// Send the command to the dive computer.
int n = serial_write (device->port, command, csize);
if (n != csize) {

View File

@ -89,6 +89,8 @@ device_is_oceanic_veo250 (device_t *abstract)
static device_status_t
oceanic_veo250_transfer (oceanic_veo250_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
{
device_t *abstract = (device_t *) device;
// Send the command to the device. If the device responds with an
// ACK byte, the command was received successfully and the answer
// (if any) follows after the ACK byte. If the device responds with
@ -98,6 +100,9 @@ oceanic_veo250_transfer (oceanic_veo250_device_t *device, const unsigned char co
unsigned int nretries = 0;
unsigned char response = NAK;
while (response == NAK) {
if (device_is_cancelled (abstract))
return DEVICE_STATUS_CANCELLED;
// Discard garbage bytes.
serial_flush (device->port, SERIAL_QUEUE_INPUT);

View File

@ -89,6 +89,8 @@ device_is_oceanic_vtpro (device_t *abstract)
static device_status_t
oceanic_vtpro_transfer (oceanic_vtpro_device_t *device, const unsigned char command[], unsigned int csize, unsigned char answer[], unsigned int asize)
{
device_t *abstract = (device_t *) device;
// Send the command to the device. If the device responds with an
// ACK byte, the command was received successfully and the answer
// (if any) follows after the ACK byte. If the device responds with
@ -98,6 +100,9 @@ oceanic_vtpro_transfer (oceanic_vtpro_device_t *device, const unsigned char comm
unsigned int nretries = 0;
unsigned char response = NAK;
while (response == NAK) {
if (device_is_cancelled (abstract))
return DEVICE_STATUS_CANCELLED;
// Send the command to the dive computer.
int n = serial_write (device->port, command, csize);
if (n != csize) {

View File

@ -273,6 +273,11 @@ reefnet_sensusultra_packet (reefnet_sensusultra_device_t *device, unsigned char
{
assert (size >= header + 2);
device_t *abstract = (device_t *) device;
if (device_is_cancelled (abstract))
return DEVICE_STATUS_CANCELLED;
// Receive the data packet.
int rc = serial_read (device->port, data, size);
if (rc != size) {

View File

@ -157,6 +157,9 @@ suunto_d9_device_packet (device_t *abstract, const unsigned char command[], unsi
{
suunto_d9_device_t *device = (suunto_d9_device_t *) abstract;
if (device_is_cancelled (abstract))
return DEVICE_STATUS_CANCELLED;
// Clear RTS to send the command.
serial_set_rts (device->port, 0);

View File

@ -238,6 +238,11 @@ suunto_vyper_transfer (suunto_vyper_device_t *device, const unsigned char comman
{
assert (asize >= size + 2);
device_t *abstract = (device_t *) device;
if (device_is_cancelled (abstract))
return DEVICE_STATUS_CANCELLED;
// Send the command to the dive computer.
device_status_t rc = suunto_vyper_send (device, command, csize);
if (rc != DEVICE_STATUS_SUCCESS) {
@ -359,6 +364,9 @@ suunto_vyper_read_dive (device_t *abstract, dc_buffer_t *buffer, int init, devic
{
suunto_vyper_device_t *device = (suunto_vyper_device_t*) abstract;
if (device_is_cancelled (abstract))
return DEVICE_STATUS_CANCELLED;
// Erase the current contents of the buffer.
if (!dc_buffer_clear (buffer)) {
WARNING ("Insufficient buffer space available.");

View File

@ -157,6 +157,9 @@ suunto_vyper2_device_packet (device_t *abstract, const unsigned char command[],
{
suunto_vyper2_device_t *device = (suunto_vyper2_device_t *) abstract;
if (device_is_cancelled (abstract))
return DEVICE_STATUS_CANCELLED;
serial_sleep (0x190 + 0xC8);
// Set RTS to send the command.

View File

@ -218,6 +218,9 @@ uwatec_aladin_device_dump (device_t *abstract, dc_buffer_t *buffer)
// Receive the header of the package.
for (unsigned int i = 0; i < 4;) {
if (device_is_cancelled (abstract))
return DEVICE_STATUS_CANCELLED;
int rc = serial_read (device->port, answer + i, 1);
if (rc != 1) {
WARNING ("Failed to receive the answer.");

View File

@ -349,12 +349,17 @@ uwatec_memomouse_read_packet_inner (uwatec_memomouse_device_t *device, dc_buffer
static device_status_t
uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t *buffer)
{
device_t *abstract = (device_t *) device;
// Enable progress notifications.
device_progress_t progress = DEVICE_PROGRESS_INITIALIZER;
device_event_emit (&device->base, DEVICE_EVENT_PROGRESS, &progress);
// Waiting for greeting message.
while (serial_get_received (device->port) == 0) {
if (device_is_cancelled (abstract))
return DEVICE_STATUS_CANCELLED;
// Flush the input buffer.
serial_flush (device->port, SERIAL_QUEUE_INPUT);
@ -421,6 +426,9 @@ uwatec_memomouse_dump_internal (uwatec_memomouse_device_t *device, dc_buffer_t *
// Wait for the data packet.
while (serial_get_received (device->port) == 0) {
if (device_is_cancelled (abstract))
return DEVICE_STATUS_CANCELLED;
device_event_emit (&device->base, DEVICE_EVENT_WAITING, NULL);
serial_sleep (100);
}