summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2010-05-09 21:41:43 -0600
committerTavian Barnes <tavianator@gmail.com>2010-05-09 21:49:41 -0600
commitc280e280ba7528cc5fb88ae0be341d81f3b45e0a (patch)
treed8d5264536374ad464ba89d1a04ffc604edc643e
parent477eb270b9c338f7d9743595f8980fa81cdb083d (diff)
downloaddimension-c280e280ba7528cc5fb88ae0be341d81f3b45e0a.tar.xz
New dmnsn_new_thread() function.
Two advantages: first, waiters are guaranteed to wake if a dmnsn_error() cancels a thread. Second, the thread library is fully abstracted over by threads.{c,h} and progress.{c,h} now, though raytrace.c is still using pthread_create() directly.
-rw-r--r--libdimension/Makefile.am15
-rw-r--r--libdimension/dimension_impl.h1
-rw-r--r--libdimension/png.c262
-rw-r--r--libdimension/raytrace.c34
-rw-r--r--libdimension/threads.c58
-rw-r--r--libdimension/threads.h32
6 files changed, 228 insertions, 174 deletions
diff --git a/libdimension/Makefile.am b/libdimension/Makefile.am
index b5b0be1..0d15ff9 100644
--- a/libdimension/Makefile.am
+++ b/libdimension/Makefile.am
@@ -49,8 +49,8 @@ lib_LTLIBRARIES = libdimension.la
libdimension_la_SOURCES = $(nobase_include_HEADERS) \
ambient.c \
- prtree.c \
- prtree.h \
+ prtree.c \
+ prtree.h \
camera.c \
canvas.c \
canvas_pigment.c \
@@ -78,9 +78,12 @@ libdimension_la_SOURCES = $(nobase_include_HEADERS) \
scene.c \
solid_pigment.c \
sphere.c \
- texture.c
+ texture.c \
+ threads.c \
+ threads.h
+libdimension_la_CFLAGS = $(AM_CFLAGS) -pthread
libdimension_la_LDFLAGS = -version-info 0:0:0 $(AM_LDFLAGS)
-libdimension_la_LIBADD = -lm -lpthread
+libdimension_la_LIBADD = -lm
if PNG
libdimension_la_SOURCES += png.c
@@ -101,9 +104,9 @@ if PGO
noinst_LTLIBRARIES = libdimension-pgo.la
libdimension_pgo_la_SOURCES = $(libdimension_la_SOURCES)
libdimension_pgo_la_LIBADD = $(libdimension_la_LIBADD) -lgcov
-libdimension_pgo_la_CFLAGS = -fprofile-generate=$$(readlink -f $(builddir))/pgo
+libdimension_pgo_la_CFLAGS = $(libdimension_la_CFLAGS) -fprofile-generate=$$(readlink -f $(builddir))/pgo
-libdimension_la_CFLAGS = -fprofile-correction -fprofile-use=./pgo
+libdimension_la_CFLAGS += -fprofile-correction -fprofile-use=./pgo
all-local: libdimension.la
@for Plo in .deps/libdimension_la*.Plo; do \
diff --git a/libdimension/dimension_impl.h b/libdimension/dimension_impl.h
index 3c3283c..912a127 100644
--- a/libdimension/dimension_impl.h
+++ b/libdimension/dimension_impl.h
@@ -22,6 +22,7 @@
#define DIMENSION_IMPL_H
#include "dimension.h"
+#include "threads.h"
#include "prtree.h"
#endif /* DIMENSION_IMPL_H */
diff --git a/libdimension/png.c b/libdimension/png.c
index 0a06e4a..595c496 100644
--- a/libdimension/png.c
+++ b/libdimension/png.c
@@ -18,7 +18,7 @@
* <http://www.gnu.org/licenses/>. *
*************************************************************************/
-#include "dimension.h"
+#include "dimension_impl.h"
#include <pthread.h>
#include <png.h>
#include <arpa/inet.h>
@@ -116,8 +116,8 @@ typedef struct {
} dmnsn_png_read_payload;
/* Thread callbacks */
-static void *dmnsn_png_write_canvas_thread(void *ptr);
-static void *dmnsn_png_read_canvas_thread(void *ptr);
+static int dmnsn_png_write_canvas_thread(void *ptr);
+static int dmnsn_png_read_canvas_thread(void *ptr);
/* Write a canvas to a png file, using libpng. Return 0 on success, nonzero on
failure. */
@@ -141,12 +141,10 @@ dmnsn_png_write_canvas_async(const dmnsn_canvas *canvas, FILE *file)
payload->file = file;
/* Create the worker thread */
- if (pthread_create(&progress->thread, NULL, &dmnsn_png_write_canvas_thread,
- payload) != 0)
+ if (dmnsn_new_thread(progress, NULL, &dmnsn_png_write_canvas_thread, payload)
+ != 0)
{
- free(payload);
- dmnsn_delete_progress(progress);
- return NULL;
+ dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't start worker thread.");
}
return progress;
@@ -175,8 +173,8 @@ dmnsn_png_read_canvas_async(dmnsn_canvas **canvas, FILE *file)
payload->file = file;
/* Create the worker thread */
- if (pthread_create(&progress->thread, NULL, &dmnsn_png_read_canvas_thread,
- payload) != 0)
+ if (dmnsn_new_thread(progress, NULL, &dmnsn_png_read_canvas_thread, payload)
+ != 0)
{
dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't start worker thread.");
}
@@ -184,87 +182,56 @@ dmnsn_png_read_canvas_async(dmnsn_canvas **canvas, FILE *file)
return progress;
}
-/* Actual implementations */
-static int dmnsn_png_write_canvas_impl(dmnsn_progress *progress,
- const dmnsn_canvas *canvas, FILE *file);
-static dmnsn_canvas *dmnsn_png_read_canvas_impl(dmnsn_progress *progress,
- FILE *file);
+/*
+ * Thread callbacks
+ */
-/* Thread callbacks */
-
-static void *
+/* Write a PNG file */
+static int
dmnsn_png_write_canvas_thread(void *ptr)
{
dmnsn_png_write_payload *payload = ptr;
- int *retval = dmnsn_malloc(sizeof(int));
- *retval = dmnsn_png_write_canvas_impl(payload->progress,
- payload->canvas, payload->file);
- dmnsn_done_progress(payload->progress);
- free(payload);
- return retval;
-}
-static void *
-dmnsn_png_read_canvas_thread(void *ptr)
-{
- dmnsn_png_read_payload *payload = ptr;
- *payload->canvas = dmnsn_png_read_canvas_impl(payload->progress,
- payload->file);
-
- int *retval = dmnsn_malloc(sizeof(int));
- *retval = *payload->canvas ? 0 : -1; /* Fail if it returned NULL */
-
- dmnsn_done_progress(payload->progress);
- free(payload);
- return retval;
-}
-
-/* Actually write the PNG file */
-static int
-dmnsn_png_write_canvas_impl(dmnsn_progress *progress,
- const dmnsn_canvas *canvas, FILE *file)
-{
- png_structp png_ptr;
- png_infop info_ptr;
- png_uint_32 width, height;
- uint16_t *row = NULL;
- dmnsn_color color;
- dmnsn_sRGB sRGB;
-
- if (!file) {
+ if (!payload->file) {
/* file was NULL */
errno = EINVAL;
+ free(payload);
return -1;
}
- width = canvas->x;
- height = canvas->y;
+ png_uint_32 width = payload->canvas->x;
+ png_uint_32 height = payload->canvas->y;
- dmnsn_new_progress_element(progress, height);
+ dmnsn_new_progress_element(payload->progress, height);
- png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ png_structp png_ptr
+ = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
/* Couldn't create libpng write struct */
+ free(payload);
return -1;
}
- info_ptr = png_create_info_struct(png_ptr);
+ png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
/* Couldn't create libpng info struct */
png_destroy_write_struct(&png_ptr, NULL);
+ free(payload);
return -1;
}
/* libpng will longjmp here if it encounters an error from here on */
+ uint16_t *row = NULL;
if (setjmp(png_jmpbuf(png_ptr))) {
/* libpng error */
free(row);
png_destroy_write_struct(&png_ptr, &info_ptr);
+ free(payload);
return -1;
}
/* Associate file with the libpng write struct */
- png_init_io(png_ptr, file);
+ png_init_io(png_ptr, payload->file);
/* Set header correctly for 16-bit sRGB image */
png_set_IHDR(png_ptr, info_ptr, width, height, 16,
@@ -284,18 +251,21 @@ dmnsn_png_write_canvas_impl(dmnsn_progress *progress,
}
/* Check if we can optimize this */
- DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer *, i, canvas->optimizers) {
+ DMNSN_ARRAY_FOREACH (dmnsn_canvas_optimizer *, i,
+ payload->canvas->optimizers)
+ {
if (i->optimizer_fn == &dmnsn_png_optimizer_fn) {
for (size_t y = 0; y < height; ++y) {
/* Invert the rows. PNG coordinates are fourth quadrant. */
uint16_t *row = (uint16_t *)i->ptr + 4*(height - y - 1)*width;
png_write_row(png_ptr, (png_bytep)row);
- dmnsn_increment_progress(progress);
+ dmnsn_increment_progress(payload->progress);
}
/* Finish the PNG file */
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
+ free(payload);
return 0;
}
}
@@ -307,8 +277,8 @@ dmnsn_png_write_canvas_impl(dmnsn_progress *progress,
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
/* Invert the rows. PNG coordinates are fourth quadrant. */
- color = dmnsn_get_pixel(canvas, x, height - y - 1);
- sRGB = dmnsn_sRGB_from_color(color);
+ dmnsn_color color = dmnsn_get_pixel(payload->canvas, x, height - y - 1);
+ dmnsn_sRGB sRGB = dmnsn_sRGB_from_color(color);
/* Saturate R, G, and B to [0, UINT16_MAX] */
@@ -348,7 +318,7 @@ dmnsn_png_write_canvas_impl(dmnsn_progress *progress,
/* Write the row */
png_write_row(png_ptr, (png_bytep)row);
- dmnsn_increment_progress(progress);
+ dmnsn_increment_progress(payload->progress);
}
/* Finish the PNG file */
@@ -356,6 +326,7 @@ dmnsn_png_write_canvas_impl(dmnsn_progress *progress,
free(row);
png_destroy_write_struct(&png_ptr, &info_ptr);
+ free(payload);
return 0;
}
@@ -366,25 +337,20 @@ static pthread_mutex_t progress_mutex = PTHREAD_MUTEX_INITIALIZER;
static int progress_key_init = 0;
/* Callback to increment the progress after a row has been read */
-static void dmnsn_png_read_row_callback(png_structp png_ptr, png_uint_32 row,
- int pass);
+static void
+dmnsn_png_read_row_callback(png_structp png_ptr, png_uint_32 row, int pass)
+{
+ dmnsn_progress *progress = pthread_getspecific(progress_key);
+ if (progress) {
+ dmnsn_increment_progress(progress);
+ }
+}
-/* Actually read a PNG file */
-static dmnsn_canvas *
-dmnsn_png_read_canvas_impl(dmnsn_progress *progress, FILE *file)
+/* Read a PNG file */
+static int
+dmnsn_png_read_canvas_thread(void *ptr)
{
- dmnsn_canvas *canvas;
- png_byte header[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
- png_structp png_ptr;
- png_infop info_ptr;
- png_uint_32 width, height, rowbytes;
- int bit_depth, color_type, interlace_type, compression_type, filter_method,
- number_of_passes;
- png_bytep image = NULL;
- png_bytep *row_pointers = NULL;
- dmnsn_color color;
- dmnsn_sRGB sRGB;
- png_bytep png_pixel;
+ dmnsn_png_read_payload *payload = ptr;
/* Initialize/set progress_key */
@@ -402,7 +368,7 @@ dmnsn_png_read_canvas_impl(dmnsn_progress *progress, FILE *file)
progress_key_init = 1;
}
- if (pthread_setspecific(progress_key, progress) != 0) {
+ if (pthread_setspecific(progress_key, payload->progress) != 0) {
dmnsn_error(DMNSN_SEVERITY_MEDIUM, "Couldn't set thread-specific pointer.");
}
@@ -411,55 +377,61 @@ dmnsn_png_read_canvas_impl(dmnsn_progress *progress, FILE *file)
"Couldn't unlock thread-specific pointer mutex.");
}
- if (!file) {
+ if (!payload->file) {
/* file was NULL */
errno = EINVAL;
- return NULL;
+ return -1;
}
- fread(header, 1, 8, file);
+ png_byte header[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ fread(header, 1, 8, payload->file);
if (png_sig_cmp(header, 0, 8)) {
- /* file is not a PNG file, or the read failed */
+ /* payload->file is not a PNG file, or the read failed */
errno = EINVAL;
- return NULL;
+ return -1;
}
/* Create the libpng read struct */
- png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ png_structp png_ptr
+ = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
- return NULL;
+ return -1;
}
/* Create the libpng info struct */
- info_ptr = png_create_info_struct(png_ptr);
+ png_infop info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
png_destroy_read_struct(&png_ptr, NULL, NULL);
- return NULL;
+ return -1;
}
/* libpng will longjmp here if it encounters an error from here on */
+ png_bytep image = NULL;
+ png_bytep *row_pointers = NULL;
if (setjmp(png_jmpbuf(png_ptr))) {
/* libpng error */
free(row_pointers);
free(image);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- return NULL;
+ return -1;
}
/* Associate the read struct with the file, and tell it we've already checked
8 bytes of signature */
- png_init_io(png_ptr, file);
+ png_init_io(png_ptr, payload->file);
png_set_sig_bytes(png_ptr, 8);
/* Read the PNG header into info struct */
png_read_info(png_ptr, info_ptr);
/* Get useful information from the info struct */
+ png_uint_32 width, height;
+ int bit_depth, color_type, interlace_type, compression_type, filter_method;
png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
&interlace_type, &compression_type, &filter_method);
- number_of_passes = png_set_interlace_handling(png_ptr);
+ int number_of_passes = png_set_interlace_handling(png_ptr);
- dmnsn_new_progress_element(progress, (number_of_passes + 1)*height);
+ dmnsn_new_progress_element(payload->progress, (number_of_passes + 1)*height);
png_set_read_status_fn(png_ptr, &dmnsn_png_read_row_callback);
/*
@@ -485,7 +457,7 @@ dmnsn_png_read_canvas_impl(dmnsn_progress *progress, FILE *file)
png_read_update_info(png_ptr, info_ptr);
/* Get bytes/image row */
- rowbytes = png_get_rowbytes(png_ptr, info_ptr);
+ png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr);
/* Allocate the temporary image buffer */
image = dmnsn_malloc(rowbytes*height);
@@ -502,7 +474,7 @@ dmnsn_png_read_canvas_impl(dmnsn_progress *progress, FILE *file)
png_read_image(png_ptr, row_pointers);
/* Allocate the canvas */
- canvas = dmnsn_new_canvas(width, height);
+ *payload->canvas = dmnsn_new_canvas(width, height);
/* Now we convert the image to our canvas format. This depends on the image
bit depth (which has been scaled up to at least 8 or 16), and the presence
@@ -512,38 +484,42 @@ dmnsn_png_read_canvas_impl(dmnsn_progress *progress, FILE *file)
if (color_type & PNG_COLOR_MASK_ALPHA) {
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
- png_pixel = image + 8*(y*width + x);
-
- sRGB.R = ((double)((png_pixel[0] << UINT16_C(8)) + png_pixel[1]))
- /UINT16_MAX;
- sRGB.G = ((double)((png_pixel[2] << UINT16_C(8)) + png_pixel[3]))
- /UINT16_MAX;
- sRGB.B = ((double)((png_pixel[4] << UINT16_C(8)) + png_pixel[5]))
- /UINT16_MAX;
-
- color = dmnsn_color_from_sRGB(sRGB);
+ png_bytep png_pixel = image + 8*(y*width + x);
+
+ dmnsn_sRGB sRGB = {
+ .R = ((double)((png_pixel[0] << UINT16_C(8)) + png_pixel[1]))
+ /UINT16_MAX,
+ .G = ((double)((png_pixel[2] << UINT16_C(8)) + png_pixel[3]))
+ /UINT16_MAX,
+ .B = ((double)((png_pixel[4] << UINT16_C(8)) + png_pixel[5]))
+ /UINT16_MAX
+ };
+
+ dmnsn_color color = dmnsn_color_from_sRGB(sRGB);
color.trans = ((double)((png_pixel[6] << UINT16_C(8))
+ png_pixel[7]))/UINT16_MAX;
- dmnsn_set_pixel(canvas, x, height - y - 1, color);
+ dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color);
}
- dmnsn_increment_progress(progress);
+ dmnsn_increment_progress(payload->progress);
}
} else {
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
- png_pixel = image + 6*(y*width + x);
-
- sRGB.R = ((double)((png_pixel[0] << UINT16_C(8)) + png_pixel[1]))
- /UINT16_MAX;
- sRGB.G = ((double)((png_pixel[2] << UINT16_C(8)) + png_pixel[3]))
- /UINT16_MAX;
- sRGB.B = ((double)((png_pixel[4] << UINT16_C(8)) + png_pixel[5]))
- /UINT16_MAX;
-
- color = dmnsn_color_from_sRGB(sRGB);
- dmnsn_set_pixel(canvas, x, height - y - 1, color);
+ png_bytep png_pixel = image + 6*(y*width + x);
+
+ dmnsn_sRGB sRGB = {
+ .R = ((double)((png_pixel[0] << UINT16_C(8)) + png_pixel[1]))
+ /UINT16_MAX,
+ .G = ((double)((png_pixel[2] << UINT16_C(8)) + png_pixel[3]))
+ /UINT16_MAX,
+ .B = ((double)((png_pixel[4] << UINT16_C(8)) + png_pixel[5]))
+ /UINT16_MAX
+ };
+
+ dmnsn_color color = dmnsn_color_from_sRGB(sRGB);
+ dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color);
}
- dmnsn_increment_progress(progress);
+ dmnsn_increment_progress(payload->progress);
}
}
} else {
@@ -551,31 +527,35 @@ dmnsn_png_read_canvas_impl(dmnsn_progress *progress, FILE *file)
if (color_type & PNG_COLOR_MASK_ALPHA) {
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
- png_pixel = image + 4*(y*width + x);
+ png_bytep png_pixel = image + 4*(y*width + x);
- sRGB.R = ((double)png_pixel[0])/UINT8_MAX;
- sRGB.G = ((double)png_pixel[1])/UINT8_MAX;
- sRGB.B = ((double)png_pixel[2])/UINT8_MAX;
+ dmnsn_sRGB sRGB = {
+ .R = ((double)png_pixel[0])/UINT8_MAX,
+ .G = ((double)png_pixel[1])/UINT8_MAX,
+ .B = ((double)png_pixel[2])/UINT8_MAX
+ };
- color = dmnsn_color_from_sRGB(sRGB);
+ dmnsn_color color = dmnsn_color_from_sRGB(sRGB);
color.trans = ((double)png_pixel[3])/UINT8_MAX;
- dmnsn_set_pixel(canvas, x, height - y - 1, color);
+ dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color);
}
- dmnsn_increment_progress(progress);
+ dmnsn_increment_progress(payload->progress);
}
} else {
for (size_t y = 0; y < height; ++y) {
for (size_t x = 0; x < width; ++x) {
- png_pixel = image + 3*(y*width + x);
+ png_bytep png_pixel = image + 3*(y*width + x);
- sRGB.R = ((double)png_pixel[0])/UINT8_MAX;
- sRGB.G = ((double)png_pixel[1])/UINT8_MAX;
- sRGB.B = ((double)png_pixel[2])/UINT8_MAX;
+ dmnsn_sRGB sRGB = {
+ sRGB.R = ((double)png_pixel[0])/UINT8_MAX,
+ sRGB.G = ((double)png_pixel[1])/UINT8_MAX,
+ sRGB.B = ((double)png_pixel[2])/UINT8_MAX
+ };
- color = dmnsn_color_from_sRGB(sRGB);
- dmnsn_set_pixel(canvas, x, height - y - 1, color);
+ dmnsn_color color = dmnsn_color_from_sRGB(sRGB);
+ dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color);
}
- dmnsn_increment_progress(progress);
+ dmnsn_increment_progress(payload->progress);
}
}
}
@@ -584,14 +564,6 @@ dmnsn_png_read_canvas_impl(dmnsn_progress *progress, FILE *file)
free(image);
png_read_end(png_ptr, NULL);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
- return canvas;
-}
-
-static void
-dmnsn_png_read_row_callback(png_structp png_ptr, png_uint_32 row, int pass)
-{
- dmnsn_progress *progress = pthread_getspecific(progress_key);
- if (progress) {
- dmnsn_increment_progress(progress);
- }
+ free(payload);
+ return 0;
}
diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c
index 0c3b738..2c389dc 100644
--- a/libdimension/raytrace.c
+++ b/libdimension/raytrace.c
@@ -37,7 +37,7 @@ typedef struct {
} dmnsn_raytrace_payload;
/* Thread callback */
-static void *dmnsn_raytrace_scene_thread(void *ptr);
+static int dmnsn_raytrace_scene_thread(void *ptr);
/* Raytrace a scene */
void
@@ -58,8 +58,8 @@ dmnsn_raytrace_scene_async(dmnsn_scene *scene)
payload->progress = progress;
payload->scene = scene;
- if (pthread_create(&progress->thread, NULL, &dmnsn_raytrace_scene_thread,
- payload) != 0)
+ if (dmnsn_new_thread(progress, NULL, &dmnsn_raytrace_scene_thread, payload)
+ != 0)
{
dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't start worker thread.");
}
@@ -67,32 +67,16 @@ dmnsn_raytrace_scene_async(dmnsn_scene *scene)
return progress;
}
-/* Start the multi-threaded implementation */
-static void dmnsn_raytrace_scene_multithread(dmnsn_raytrace_payload *payload);
-
/* Thread callback */
-static void *
+static void *dmnsn_raytrace_scene_multithread_thread(void *ptr);
+
+/* Thread callback -- set up the multithreaded engine */
+static int
dmnsn_raytrace_scene_thread(void *ptr)
{
dmnsn_raytrace_payload *payload = ptr;
payload->prtree = dmnsn_new_prtree(payload->scene->objects);
- dmnsn_raytrace_scene_multithread(payload);
- dmnsn_delete_prtree(payload->prtree);
- dmnsn_done_progress(payload->progress);
- free(payload);
-
- int *retval = dmnsn_malloc(sizeof(int));
- *retval = 0;
- return retval;
-}
-/* Thread callback */
-static void *dmnsn_raytrace_scene_multithread_thread(void *ptr);
-
-/* Set up the multi-threaded engine */
-static void
-dmnsn_raytrace_scene_multithread(dmnsn_raytrace_payload *payload)
-{
dmnsn_raytrace_payload *payloads;
pthread_t *threads;
@@ -135,6 +119,10 @@ dmnsn_raytrace_scene_multithread(dmnsn_raytrace_payload *payload)
free(threads);
free(payloads);
+ dmnsn_delete_prtree(payload->prtree);
+ free(payload);
+
+ return 0;
}
/* Actual raytracing implementation */
diff --git a/libdimension/threads.c b/libdimension/threads.c
new file mode 100644
index 0000000..5450ecc
--- /dev/null
+++ b/libdimension/threads.c
@@ -0,0 +1,58 @@
+/*************************************************************************
+ * Copyright (C) 2010 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * This file is part of The Dimension Library. *
+ * *
+ * The Dimension Library is free software; you can redistribute it and/ *
+ * or modify it under the terms of the GNU Lesser General Public License *
+ * as published by the Free Software Foundation; either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * The Dimension Library is distributed in the hope that it will be *
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty *
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this program. If not, see *
+ * <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#include "dimension_impl.h"
+
+typedef struct dmnsn_thread_payload {
+ dmnsn_thread_fn *thread_fn;
+ void *arg;
+ dmnsn_progress *progress;
+} dmnsn_thread_payload;
+
+static void
+dmnsn_thread_cleanup(void *arg)
+{
+ dmnsn_progress *progress = arg;
+ dmnsn_done_progress(progress);
+}
+
+static void *
+dmnsn_thread(void *arg)
+{
+ dmnsn_thread_payload *payload = arg;
+ int *ret;
+ pthread_cleanup_push(&dmnsn_thread_cleanup, payload->progress);
+ ret = dmnsn_malloc(sizeof(ret));
+ *ret = (*payload->thread_fn)(payload->arg);
+ pthread_cleanup_pop(1);
+ return ret;
+}
+
+int
+dmnsn_new_thread(dmnsn_progress *progress, const pthread_attr_t *attr,
+ dmnsn_thread_fn *thread_fn, void *arg)
+{
+ dmnsn_thread_payload *payload = dmnsn_malloc(sizeof(dmnsn_thread_payload));
+ payload->thread_fn = thread_fn;
+ payload->arg = arg;
+ payload->progress = progress;
+
+ return pthread_create(&progress->thread, attr, &dmnsn_thread, payload);
+}
diff --git a/libdimension/threads.h b/libdimension/threads.h
new file mode 100644
index 0000000..5884fae
--- /dev/null
+++ b/libdimension/threads.h
@@ -0,0 +1,32 @@
+/*************************************************************************
+ * Copyright (C) 2010 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * This file is part of The Dimension Library. *
+ * *
+ * The Dimension Library is free software; you can redistribute it and/ *
+ * or modify it under the terms of the GNU Lesser General Public License *
+ * as published by the Free Software Foundation; either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * The Dimension Library is distributed in the hope that it will be *
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty *
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Lesser General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser General Public *
+ * License along with this program. If not, see *
+ * <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+#ifndef DIMENSION_IMPL_THREADS_H
+#define DIMENSION_IMPL_THREADS_H
+
+#include <pthread.h>
+
+typedef int dmnsn_thread_fn(void *ptr);
+
+/* Creates a thread that cleans up after itself on errors */
+int dmnsn_new_thread(dmnsn_progress *progress, const pthread_attr_t *attr,
+ dmnsn_thread_fn *thread_fn, void *arg);
+
+#endif /* DIMENSION_IMPL_THREADS_H */