]> git.tdb.fi Git - ext/subsurface.git/commitdiff
Do libdivecomputer imports in a separate thread
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 16 Sep 2011 05:58:02 +0000 (22:58 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 16 Sep 2011 05:58:02 +0000 (22:58 -0700)
This is the hackiest thing ever, unless you count the previous code that
was even hackier (and just called the gtk main routine at random
places).

The libdivecomputer library is not really set up to be part of the gtk
main loop, and cannot afford (for example) to have lots of mainloop
events while it's parsing.  Some dive computers are very timing
sensitive for the communication.

So just start a thread for doing the libdivecomputer stuff, and just
continually call the gtk main loop while that thread is running.  I'm
sure we could actually use some gtk signalling thing to make the thread
exit do the right thing, but instead we just poll the status every
100ms.

I did say it was hacky.  It does seem to work, though.  No more
temporary graying out of the windows when they don't react in a timely
manner because libdivecomputer does some blocking operation.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Makefile
libdivecomputer.c

index fb84494fc970ff16dc393474c901895609c1b58a..2f24eb7de8f589119c3c97948a9bac0da6b5d82f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ subsurface: $(OBJS)
        $(CC) $(LDFLAGS) -o subsurface $(OBJS) \
                `xml2-config --libs` \
                `pkg-config --libs gtk+-2.0 glib-2.0 gconf-2.0` \
-               $(LIBDIVECOMPUTERARCHIVE)
+               $(LIBDIVECOMPUTERARCHIVE) -lpthread
 
 parse-xml.o: parse-xml.c dive.h
        $(CC) $(CFLAGS) `pkg-config --cflags glib-2.0` -c `xml2-config --cflags`  parse-xml.c
index 49c4f3695da6ca60bf3d42904d26c3f1b61e2588..c53a81e68201316a5de844e1fbd784d5fecda0e2 100644 (file)
@@ -1,5 +1,6 @@
 #include <stdio.h>
 #include <gtk/gtk.h>
+#include <pthread.h>
 
 #include "dive.h"
 #include "divelist.h"
 /* handling uemis Zurich SDA files */
 #include "uemis.h"
 
-/*
- * I'd love to do a while-loop here for pending events, but
- * that seems to screw up with the dive computer reading timing.
- *
- * I may need to spawn a new thread to do the computer
- * reading stuff..
- */
-static int run_gtk_mainloop(void)
-{
-       return gtk_main_iteration_do(0);
-}
-
 static void error(const char *fmt, ...)
 {
        va_list args;
@@ -230,18 +219,15 @@ static int dive_cb(const unsigned char *data, unsigned int size,
        struct tm tm;
        struct dive *dive;
 
-       /* Christ, this is hacky */
-       run_gtk_mainloop();
-
        rc = create_parser(devdata, &parser);
        if (rc != PARSER_STATUS_SUCCESS) {
-               error("Unable to create parser for %s", devdata->name);
+               fprintf(stderr, "Unable to create parser for %s", devdata->name);
                return rc;
        }
 
        rc = parser_set_data(parser, data, size);
        if (rc != PARSER_STATUS_SUCCESS) {
-               error("Error registering the data.");
+               fprintf(stderr, "Error registering the data.");
                parser_destroy(parser);
                return rc;
        }
@@ -249,7 +235,7 @@ static int dive_cb(const unsigned char *data, unsigned int size,
        dive = alloc_dive();
        rc = parser_get_datetime(parser, &dt);
        if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
-               error("Error parsing the datetime.");
+               fprintf(stderr, "Error parsing the datetime.");
                parser_destroy (parser);
                return rc;
        }
@@ -267,7 +253,7 @@ static int dive_cb(const unsigned char *data, unsigned int size,
        unsigned int divetime = 0;
        rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime);
        if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
-               error("Error parsing the divetime.");
+               fprintf(stderr, "Error parsing the divetime.");
                parser_destroy(parser);
                return rc;
        }
@@ -278,7 +264,7 @@ static int dive_cb(const unsigned char *data, unsigned int size,
        double maxdepth = 0.0;
        rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth);
        if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
-               error("Error parsing the maxdepth.");
+               fprintf(stderr, "Error parsing the maxdepth.");
                parser_destroy(parser);
                return rc;
        }
@@ -289,14 +275,14 @@ static int dive_cb(const unsigned char *data, unsigned int size,
        unsigned int ngases = 0;
        rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases);
        if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
-               error("Error parsing the gas mix count.");
+               fprintf(stderr, "Error parsing the gas mix count.");
                parser_destroy(parser);
                return rc;
        }
 
        rc = parse_gasmixes(dive, parser, ngases);
        if (rc != PARSER_STATUS_SUCCESS) {
-               error("Error parsing the gas mix.");
+               fprintf(stderr, "Error parsing the gas mix.");
                parser_destroy(parser);
                return rc;
        }
@@ -304,7 +290,7 @@ static int dive_cb(const unsigned char *data, unsigned int size,
        // Initialize the sample data.
        rc = parse_samples(&dive, parser);
        if (rc != PARSER_STATUS_SUCCESS) {
-               error("Error parsing the samples.");
+               fprintf(stderr, "Error parsing the samples.");
                parser_destroy(parser);
                return rc;
        }
@@ -401,9 +387,6 @@ event_cb(device_t *device, device_event_t event, const void *data, void *userdat
        const device_clock_t *clock = (device_clock_t *) data;
        device_data_t *devdata = (device_data_t *) userdata;
 
-       /* Christ, this is hacky */
-       run_gtk_mainloop();
-
        switch (event) {
        case DEVICE_EVENT_WAITING:
                printf("Event: waiting for user action\n");
@@ -429,52 +412,80 @@ event_cb(device_t *device, device_event_t event, const void *data, void *userdat
        }
 }
 
+static int import_thread_done = 0, import_thread_cancelled;
+
 static int
 cancel_cb(void *userdata)
 {
-       return run_gtk_mainloop();
+       return import_thread_cancelled;
 }
 
-static void do_import(device_data_t *data)
+static const char *do_libdivecomputer_import(device_data_t *data)
 {
        device_t *device = NULL;
        device_status_t rc;
 
-       if (data->type == DEVICE_TYPE_UEMIS) {
-               return uemis_import();
-       }
-
        rc = device_open(data->devname, data->type, &device);
-       if (rc != DEVICE_STATUS_SUCCESS) {
-               error("Unable to open %s (%s)", data->name, data->devname);
-               return;
-       }
+       if (rc != DEVICE_STATUS_SUCCESS)
+               return "Unable to open %s (%s)";
 
        // Register the event handler.
        int events = DEVICE_EVENT_WAITING | DEVICE_EVENT_PROGRESS | DEVICE_EVENT_DEVINFO | DEVICE_EVENT_CLOCK;
        rc = device_set_events(device, events, event_cb, data);
        if (rc != DEVICE_STATUS_SUCCESS) {
-               error("Error registering the event handler.");
                device_close(device);
-               return;
+               return "Error registering the event handler.";
        }
 
        // Register the cancellation handler.
        rc = device_set_cancel(device, cancel_cb, data);
        if (rc != DEVICE_STATUS_SUCCESS) {
-               error("Error registering the cancellation handler.");
                device_close(device);
-               return;
+               return "Error registering the cancellation handler.";
        }
 
        rc = import_device_data(device, data);
        if (rc != DEVICE_STATUS_SUCCESS) {
-               error("Dive data import error");
                device_close(device);
-               return;
+               return "Dive data import error";
        }
 
        device_close(device);
+       return NULL;
+}
+
+static void *pthread_wrapper(void *_data)
+{
+       device_data_t *data = _data;
+       const char *err_string = do_libdivecomputer_import(data);
+       import_thread_done = 1;
+       return (void *)err_string;
+}
+
+static void do_import(device_data_t *data)
+{
+       pthread_t pthread;
+       void *retval;
+
+       if (data->type == DEVICE_TYPE_UEMIS)
+               return uemis_import();
+
+       /* I'm sure there is some better interface for waiting on a thread in a gtk main loop */
+       import_thread_done = 0;
+       pthread_create(&pthread, NULL, pthread_wrapper, data);
+       while (!import_thread_done) {
+               while (gtk_events_pending()) {
+                       if (gtk_main_iteration_do(0)) {
+                               import_thread_cancelled = 1;
+                               break;
+                       }
+               }
+               usleep(100000);
+       }
+       if (pthread_join(pthread, &retval) < 0)
+               retval = "Odd pthread error return";
+       if (retval)
+               error(retval, data->name, data->devname);
 }
 
 /*