aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarry Jeffery <harry@exec64.co.uk>2019-02-04 02:34:46 +0000
committerHarry Jeffery <harry@exec64.co.uk>2019-02-04 03:48:03 +0000
commit05db4c452cbf6d314be60b86524629ef22798adf (patch)
treeaf4830b00a8ccfd70a9d5563ef0534924da080ca
parent09928120e31edbfa63791f0c2f5e14374ae518de (diff)
downloadimv-05db4c452cbf6d314be60b86524629ef22798adf.tar.gz
Make sources thread-safe
-rw-r--r--src/backend_freeimage.c33
-rw-r--r--src/backend_libjpeg.c23
-rw-r--r--src/backend_libpng.c18
-rw-r--r--src/backend_librsvg.c19
-rw-r--r--src/backend_libtiff.c23
-rw-r--r--src/source.h16
6 files changed, 105 insertions, 27 deletions
diff --git a/src/backend_freeimage.c b/src/backend_freeimage.c
index 8a24725..c0fb655 100644
--- a/src/backend_freeimage.c
+++ b/src/backend_freeimage.c
@@ -19,6 +19,7 @@ struct private {
static void source_free(struct imv_source *src)
{
+ pthread_mutex_lock(&src->busy);
free(src->name);
src->name = NULL;
@@ -42,6 +43,8 @@ static void source_free(struct imv_source *src)
free(private);
src->private = NULL;
+ pthread_mutex_unlock(&src->busy);
+ pthread_mutex_destroy(&src->busy);
free(src);
}
@@ -71,6 +74,7 @@ static void report_error(struct imv_source *src)
msg.bitmap = NULL;
msg.error = "Internal error";
+ pthread_mutex_unlock(&src->busy);
src->callback(&msg);
}
@@ -89,11 +93,17 @@ static void send_bitmap(struct imv_source *src, FIBITMAP *fibitmap, int frametim
msg.frametime = frametime;
msg.error = NULL;
+ pthread_mutex_unlock(&src->busy);
src->callback(&msg);
}
-static void first_frame(struct imv_source *src)
+static int first_frame(struct imv_source *src)
{
+ /* Don't run if this source is already active */
+ if (pthread_mutex_trylock(&src->busy)) {
+ return -1;
+ }
+
FIBITMAP *bmp = NULL;
struct private *private = src->private;
@@ -113,12 +123,12 @@ static void first_frame(struct imv_source *src)
/* flags */ GIF_LOAD256);
} else {
report_error(src);
- return;
+ return -1;
}
if (!private->multibitmap) {
report_error(src);
- return;
+ return -1;
}
FIBITMAP *frame = FreeImage_LockPage(private->multibitmap, 0);
@@ -147,7 +157,7 @@ static void first_frame(struct imv_source *src)
}
if (!fibitmap) {
report_error(src);
- return;
+ return -1;
}
bmp = FreeImage_ConvertTo32Bits(fibitmap);
FreeImage_Unload(fibitmap);
@@ -155,16 +165,22 @@ static void first_frame(struct imv_source *src)
src->width = FreeImage_GetWidth(bmp);
src->height = FreeImage_GetHeight(bmp);
- send_bitmap(src, bmp, frametime);
private->last_frame = bmp;
+ send_bitmap(src, bmp, frametime);
+ return 0;
}
-static void next_frame(struct imv_source *src)
+static int next_frame(struct imv_source *src)
{
+ /* Don't run if this source is already active */
+ if (pthread_mutex_trylock(&src->busy)) {
+ return -1;
+ }
+
struct private *private = src->private;
if (src->num_frames == 1) {
send_bitmap(src, private->last_frame, 0);
- return;
+ return 0;
}
FITAG *tag = NULL;
@@ -250,6 +266,7 @@ static void next_frame(struct imv_source *src)
src->next_frame = (src->next_frame + 1) % src->num_frames;
send_bitmap(src, private->last_frame, frametime);
+ return 0;
}
static enum backend_result open_path(const char *path, struct imv_source **src)
@@ -268,6 +285,7 @@ static enum backend_result open_path(const char *path, struct imv_source **src)
source->width = 0;
source->height = 0;
source->num_frames = 0;
+ pthread_mutex_init(&source->busy, NULL);
source->load_first_frame = &first_frame;
source->load_next_frame = &next_frame;
source->free = &source_free;
@@ -299,6 +317,7 @@ static enum backend_result open_memory(void *data, size_t len, struct imv_source
source->width = 0;
source->height = 0;
source->num_frames = 0;
+ pthread_mutex_init(&source->busy, NULL);
source->load_first_frame = &first_frame;
source->load_next_frame = &next_frame;
source->free = &source_free;
diff --git a/src/backend_libjpeg.c b/src/backend_libjpeg.c
index 3fde6c2..e83ddc3 100644
--- a/src/backend_libjpeg.c
+++ b/src/backend_libjpeg.c
@@ -21,6 +21,7 @@ struct private {
static void source_free(struct imv_source *src)
{
+ pthread_mutex_lock(&src->busy);
free(src->name);
src->name = NULL;
@@ -37,6 +38,8 @@ static void source_free(struct imv_source *src)
free(src->private);
src->private = NULL;
+ pthread_mutex_unlock(&src->busy);
+ pthread_mutex_destroy(&src->busy);
free(src);
}
@@ -64,6 +67,7 @@ static void report_error(struct imv_source *src)
msg.bitmap = NULL;
msg.error = "Internal error";
+ pthread_mutex_unlock(&src->busy);
src->callback(&msg);
}
@@ -82,24 +86,31 @@ static void send_bitmap(struct imv_source *src, void *bitmap)
msg.frametime = 0;
msg.error = NULL;
+ pthread_mutex_unlock(&src->busy);
src->callback(&msg);
}
-static void load_image(struct imv_source *src)
+static int load_image(struct imv_source *src)
{
+ /* Don't run if this source is already active */
+ if (pthread_mutex_trylock(&src->busy)) {
+ return -1;
+ }
+
struct private *private = src->private;
void *bitmap = malloc(src->height * src->width * 4);
int rcode = tjDecompress2(private->jpeg, private->data, private->len,
bitmap, src->width, 0, src->height, TJPF_RGBA, TJFLAG_FASTDCT);
- if (!rcode) {
- send_bitmap(src, bitmap);
- } else {
+ if (rcode) {
free(bitmap);
report_error(src);
- return;
+ return -1;
}
+
+ send_bitmap(src, bitmap);
+ return 0;
}
static enum backend_result open_path(const char *path, struct imv_source **src)
@@ -148,6 +159,7 @@ static enum backend_result open_path(const char *path, struct imv_source **src)
source->height = height;
source->num_frames = 1;
source->next_frame = 1;
+ pthread_mutex_init(&source->busy, NULL);
source->load_first_frame = &load_image;
source->load_next_frame = NULL;
source->free = &source_free;
@@ -187,6 +199,7 @@ static enum backend_result open_memory(void *data, size_t len, struct imv_source
source->height = height;
source->num_frames = 1;
source->next_frame = 1;
+ pthread_mutex_init(&source->busy, NULL);
source->load_first_frame = &load_image;
source->load_next_frame = NULL;
source->free = &source_free;
diff --git a/src/backend_libpng.c b/src/backend_libpng.c
index 2c3b1d7..3713ae8 100644
--- a/src/backend_libpng.c
+++ b/src/backend_libpng.c
@@ -18,6 +18,7 @@ struct private {
static void source_free(struct imv_source *src)
{
+ pthread_mutex_lock(&src->busy);
free(src->name);
src->name = NULL;
@@ -30,6 +31,8 @@ static void source_free(struct imv_source *src)
free(src->private);
src->private = NULL;
+ pthread_mutex_unlock(&src->busy);
+ pthread_mutex_destroy(&src->busy);
free(src);
}
@@ -57,6 +60,7 @@ static void report_error(struct imv_source *src)
msg.bitmap = NULL;
msg.error = "Internal error";
+ pthread_mutex_unlock(&src->busy);
src->callback(&msg);
}
@@ -76,16 +80,22 @@ static void send_bitmap(struct imv_source *src, void *bitmap)
msg.frametime = 0;
msg.error = NULL;
+ pthread_mutex_unlock(&src->busy);
src->callback(&msg);
}
-static void load_image(struct imv_source *src)
+static int load_image(struct imv_source *src)
{
+ /* Don't run if this source is already active */
+ if (pthread_mutex_trylock(&src->busy)) {
+ return -1;
+ }
+
struct private *private = src->private;
if (setjmp(png_jmpbuf(private->png))) {
report_error(src);
- return;
+ return -1;
}
png_bytep *rows = alloca(sizeof(png_bytep) * src->height);
@@ -98,13 +108,14 @@ static void load_image(struct imv_source *src)
if (setjmp(png_jmpbuf(private->png))) {
free(rows[0]);
report_error(src);
- return;
+ return -1;
}
png_read_image(private->png, rows);
fclose(private->file);
private->file = NULL;
send_bitmap(src, rows[0]);
+ return 0;
}
static enum backend_result open_path(const char *path, struct imv_source **src)
@@ -169,6 +180,7 @@ static enum backend_result open_path(const char *path, struct imv_source **src)
source->height = png_get_image_height(private->png, private->info);
source->num_frames = 1;
source->next_frame = 1;
+ pthread_mutex_init(&source->busy, NULL);
source->load_first_frame = &load_image;
source->load_next_frame = NULL;
source->free = &source_free;
diff --git a/src/backend_librsvg.c b/src/backend_librsvg.c
index 083fb9c..c9a91ff 100644
--- a/src/backend_librsvg.c
+++ b/src/backend_librsvg.c
@@ -21,6 +21,7 @@ struct private {
static void source_free(struct imv_source *src)
{
+ pthread_mutex_lock(&src->busy);
free(src->name);
src->name = NULL;
@@ -28,6 +29,8 @@ static void source_free(struct imv_source *src)
free(private);
src->private = NULL;
+ pthread_mutex_unlock(&src->busy);
+ pthread_mutex_destroy(&src->busy);
free(src);
}
@@ -57,6 +60,7 @@ static void report_error(struct imv_source *src)
msg.bitmap = NULL;
msg.error = "Internal error";
+ pthread_mutex_unlock(&src->busy);
src->callback(&msg);
}
@@ -76,11 +80,17 @@ static void send_bitmap(struct imv_source *src, GdkPixbuf *bitmap)
msg.frametime = 0;
msg.error = NULL;
+ pthread_mutex_unlock(&src->busy);
src->callback(&msg);
}
-static void load_image(struct imv_source *src)
+static int load_image(struct imv_source *src)
{
+ /* Don't run if this source is already active */
+ if (pthread_mutex_trylock(&src->busy)) {
+ return -1;
+ }
+
RsvgHandle *handle = NULL;
GError *error = NULL;
@@ -95,7 +105,7 @@ static void load_image(struct imv_source *src)
if (!handle) {
report_error(src);
- return;
+ return -1;
}
RsvgDimensionData dim;
@@ -107,11 +117,12 @@ static void load_image(struct imv_source *src)
if (!buf) {
rsvg_handle_close(handle, &error);
report_error(src);
- return;
+ return -1;
}
rsvg_handle_close(handle, &error);
send_bitmap(src, buf);
+ return 0;
}
static enum backend_result open_path(const char *path, struct imv_source **src)
@@ -141,6 +152,7 @@ static enum backend_result open_path(const char *path, struct imv_source **src)
source->height = 1024;
source->num_frames = 1;
source->next_frame = 1;
+ pthread_mutex_init(&source->busy, NULL);
source->load_first_frame = &load_image;
source->load_next_frame = NULL;
source->free = &source_free;
@@ -173,6 +185,7 @@ static enum backend_result open_memory(void *data, size_t len, struct imv_source
source->height = 1024;
source->num_frames = 1;
source->next_frame = 1;
+ pthread_mutex_init(&source->busy, NULL);
source->load_first_frame = &load_image;
source->load_next_frame = NULL;
source->free = &source_free;
diff --git a/src/backend_libtiff.c b/src/backend_libtiff.c
index fcfdc7f..e837a46 100644
--- a/src/backend_libtiff.c
+++ b/src/backend_libtiff.c
@@ -63,6 +63,7 @@ static toff_t mem_size(thandle_t data)
static void source_free(struct imv_source *src)
{
+ pthread_mutex_lock(&src->busy);
free(src->name);
src->name = NULL;
@@ -73,6 +74,8 @@ static void source_free(struct imv_source *src)
free(src->private);
src->private = NULL;
+ pthread_mutex_unlock(&src->busy);
+ pthread_mutex_destroy(&src->busy);
free(src);
}
@@ -100,6 +103,7 @@ static void report_error(struct imv_source *src)
msg.bitmap = NULL;
msg.error = "Internal error";
+ pthread_mutex_unlock(&src->busy);
src->callback(&msg);
}
@@ -118,11 +122,17 @@ static void send_bitmap(struct imv_source *src, void *bitmap)
msg.frametime = 0;
msg.error = NULL;
+ pthread_mutex_unlock(&src->busy);
src->callback(&msg);
}
-static void load_image(struct imv_source *src)
+static int load_image(struct imv_source *src)
{
+ /* Don't run if this source is already active */
+ if (pthread_mutex_trylock(&src->busy)) {
+ return -1;
+ }
+
struct private *private = src->private;
/* libtiff suggests using their own allocation routines to support systems
@@ -135,13 +145,14 @@ static void load_image(struct imv_source *src)
bitmap, ORIENTATION_TOPLEFT, 0);
/* 1 = success, unlike the rest of *nix */
- if (rcode == 1) {
- send_bitmap(src, bitmap);
- } else {
+ if (rcode != 1) {
free(bitmap);
report_error(src);
- return;
+ return -1;
}
+
+ send_bitmap(src, bitmap);
+ return 0;
}
static enum backend_result open_path(const char *path, struct imv_source **src)
@@ -164,6 +175,7 @@ static enum backend_result open_path(const char *path, struct imv_source **src)
source->height = height;
source->num_frames = 1;
source->next_frame = 1;
+ pthread_mutex_init(&source->busy, NULL);
source->load_first_frame = &load_image;
source->load_next_frame = NULL;
source->free = &source_free;
@@ -201,6 +213,7 @@ static enum backend_result open_memory(void *data, size_t len, struct imv_source
source->height = height;
source->num_frames = 1;
source->next_frame = 1;
+ pthread_mutex_init(&source->busy, NULL);
source->load_first_frame = &load_image;
source->load_next_frame = NULL;
source->free = &source_free;
diff --git a/src/source.h b/src/source.h
index 74501ed..4f1a0dd 100644
--- a/src/source.h
+++ b/src/source.h
@@ -1,6 +1,7 @@
#ifndef IMV_SOURCE_H
#define IMV_SOURCE_H
+#include <pthread.h>
#include <stdbool.h>
#include "bitmap.h"
@@ -36,11 +37,18 @@ struct imv_source {
/* Next frame to be loaded, 0-indexed */
int next_frame;
- /* Trigger loading of the first frame. */
- void (*load_first_frame)(struct imv_source *src);
+ /* Attempted to be locked by load_first_frame or load_next_frame.
+ * If the mutex can't be locked, the call is aborted.
+ * Used to prevent the source from having multiple worker threads at once.
+ * Released by the source before calling the message callback with a result.
+ */
+ pthread_mutex_t busy;
+
+ /* Trigger loading of the first frame. Returns 0 on success. */
+ int (*load_first_frame)(struct imv_source *src);
- /* Trigger loading of next frame. */
- void (*load_next_frame)(struct imv_source *src);
+ /* Trigger loading of next frame. Returns 0 on success. */
+ int (*load_next_frame)(struct imv_source *src);
/* Safely free contents of this source. After this returns
* it is safe to dealocate/overwrite the imv_source instance.