summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dimension/dimension.in10
-rw-r--r--libdimension-python/dimension.pxd22
-rw-r--r--libdimension-python/dimension.pyx53
-rw-r--r--libdimension/Makefile.am6
-rw-r--r--libdimension/bench/prtree.c2
-rw-r--r--libdimension/dimension-internal.h2
-rw-r--r--libdimension/dimension.h2
-rw-r--r--libdimension/dimension/future.h (renamed from libdimension/dimension/progress.h)30
-rw-r--r--libdimension/dimension/png.h10
-rw-r--r--libdimension/dimension/raytrace.h4
-rw-r--r--libdimension/future-impl.h (renamed from libdimension/progress-impl.h)29
-rw-r--r--libdimension/future.c164
-rw-r--r--libdimension/png.c60
-rw-r--r--libdimension/progress.c165
-rw-r--r--libdimension/raytrace.c26
-rw-r--r--libdimension/tests/prtree.c2
-rw-r--r--libdimension/tests/render.c6
-rw-r--r--libdimension/threads.c13
-rw-r--r--libdimension/threads.h4
19 files changed, 303 insertions, 307 deletions
diff --git a/dimension/dimension.in b/dimension/dimension.in
index dc2430c..0ea41e4 100644
--- a/dimension/dimension.in
+++ b/dimension/dimension.in
@@ -119,7 +119,7 @@ if args.output is None:
args.output = noext + ".png"
# Display a progress bar
-def progress_bar(str, progress):
+def progress_bar(str, future):
try:
if not args.quiet:
print(str, end = " ")
@@ -128,21 +128,21 @@ def progress_bar(str, progress):
term_width = terminal_width()
width = term_width - (len(str) + 1)%term_width
for i in range(width):
- progress.wait((i + 1)/width)
+ future.wait((i + 1)/width)
print(".", end = "")
sys.stdout.flush()
print()
sys.stdout.flush()
- progress.finish()
+ future.join()
except KeyboardInterrupt:
print()
sys.stdout.flush()
- progress.cancel()
+ future.cancel()
try:
- progress.finish()
+ future.join()
except RuntimeError:
# Swallow the failure exception
pass
diff --git a/libdimension-python/dimension.pxd b/libdimension-python/dimension.pxd
index b70508c..403b327 100644
--- a/libdimension-python/dimension.pxd
+++ b/libdimension-python/dimension.pxd
@@ -64,16 +64,16 @@ cdef extern from "../libdimension/dimension.h":
void dmnsn_array_remove(dmnsn_array *array, size_t i)
void dmnsn_array_apply(dmnsn_array *array, dmnsn_callback_fn *callback)
- ############
- # Progress #
- ############
+ ###########
+ # Futures #
+ ###########
- ctypedef struct dmnsn_progress
+ ctypedef struct dmnsn_future
- int dmnsn_finish_progress(dmnsn_progress *progress)
- void dmnsn_cancel_progress(dmnsn_progress *progress)
- double dmnsn_get_progress(dmnsn_progress *progress)
- void dmnsn_wait_progress(dmnsn_progress *progress, double prog)
+ int dmnsn_future_join(dmnsn_future *future)
+ void dmnsn_future_cancel(dmnsn_future *future)
+ double dmnsn_future_progress(dmnsn_future *future)
+ void dmnsn_future_wait(dmnsn_future *future, double progress)
##########
# Timers #
@@ -194,9 +194,9 @@ cdef extern from "../libdimension/dimension.h":
int dmnsn_png_optimize_canvas(dmnsn_canvas *canvas)
int dmnsn_png_write_canvas(dmnsn_canvas *canvas, FILE *file)
- dmnsn_progress *dmnsn_png_write_canvas_async(dmnsn_canvas *canvas, FILE *file)
+ dmnsn_future *dmnsn_png_write_canvas_async(dmnsn_canvas *canvas, FILE *file)
dmnsn_canvas *dmnsn_png_read_canvas(FILE *file)
- dmnsn_progress *dmnsn_png_read_canvas_async(dmnsn_canvas **canvas, FILE *file)
+ dmnsn_future *dmnsn_png_read_canvas_async(dmnsn_canvas **canvas, FILE *file)
int dmnsn_gl_optimize_canvas(dmnsn_canvas *canvas)
int dmnsn_gl_write_canvas(dmnsn_canvas *canvas)
@@ -391,7 +391,7 @@ cdef extern from "../libdimension/dimension.h":
void dmnsn_delete_scene(dmnsn_scene *scene)
void dmnsn_raytrace_scene(dmnsn_scene *scene)
- dmnsn_progress *dmnsn_raytrace_scene_async(dmnsn_scene *scene)
+ dmnsn_future *dmnsn_raytrace_scene_async(dmnsn_scene *scene)
cdef extern from "platform.h":
unsigned int dmnsn_terminal_width()
diff --git a/libdimension-python/dimension.pyx b/libdimension-python/dimension.pyx
index 3fff622..7f9fda0 100644
--- a/libdimension-python/dimension.pyx
+++ b/libdimension-python/dimension.pyx
@@ -46,55 +46,55 @@ def terminal_width():
"""Return the width of the terminal, if present."""
return dmnsn_terminal_width()
-############
-# Progress #
-############
+###########
+# Futures #
+###########
-cdef class Progress:
- cdef dmnsn_progress *_progress
+cdef class Future:
+ cdef dmnsn_future *_future
cdef _finalizer
def __cinit__(self):
- self._progress = NULL
+ self._future = NULL
self._finalizer = None
def __init__(self):
- raise RuntimeError("attempt to create a Progress object.")
+ raise RuntimeError("attempt to create a Future object.")
def __dealloc__(self):
- if self._progress != NULL:
- self.finish()
+ if self._future != NULL:
+ self.join()
- def finish(self):
+ def join(self):
self._assert_unfinished()
try:
- if dmnsn_finish_progress(self._progress) != 0:
+ if dmnsn_future_join(self._future) != 0:
raise RuntimeError("background task failed.")
if self._finalizer is not None:
self._finalizer()
finally:
- self._progress = NULL
+ self._future = NULL
def cancel(self):
self._assert_unfinished()
- dmnsn_cancel_progress(self._progress)
+ dmnsn_future_cancel(self._future)
def progress(self):
self._assert_unfinished()
- return dmnsn_get_progress(self._progress)
+ return dmnsn_future_progress(self._future)
def wait(self, progress):
self._assert_unfinished()
- dmnsn_wait_progress(self._progress, progress)
+ dmnsn_future_wait(self._future, progress)
def _assert_unfinished(self):
- if self._progress == NULL:
+ if self._future == NULL:
raise RuntimeError("background task finished.")
-cdef Progress _Progress(dmnsn_progress *progress):
- """Wrap a Progress object around an existing dmnsn_progress *."""
- cdef Progress self = Progress.__new__(Progress)
- self._progress = progress
+cdef Future _Future(dmnsn_future *future):
+ """Wrap a Future object around an existing dmnsn_future *."""
+ cdef Future self = Future.__new__(Future)
+ self._future = future
return self
##########
@@ -562,7 +562,7 @@ cdef class Canvas:
def write_PNG(self, path):
"""Export the canvas as a PNG file."""
- self.write_PNG_async(path).finish()
+ self.write_PNG_async(path).join()
def write_PNG_async(self, path):
"""Export the canvas as a PNG file, in the background."""
bpath = path.encode("UTF-8")
@@ -575,14 +575,13 @@ cdef class Canvas:
if fclose(file) != 0:
_raise_OSError()
- cdef dmnsn_progress *progress = dmnsn_png_write_canvas_async(self._canvas,
- file)
+ cdef dmnsn_future *future = dmnsn_png_write_canvas_async(self._canvas, file)
try:
- if progress == NULL:
+ if future == NULL:
_raise_OSError()
- ret = _Progress(progress)
+ ret = _Future(future)
ret._finalizer = finalize
return ret
except:
@@ -1501,7 +1500,7 @@ cdef class Scene:
def raytrace(self):
"""Render the scene."""
- self.raytrace_async().finish()
+ self.raytrace_async().join()
def raytrace_async(self):
"""Render the scene, in the background."""
# Account for image dimensions in the camera
@@ -1519,7 +1518,7 @@ cdef class Scene:
# Ensure the default texture is complete
cdef Texture default = Texture(pigment = Black)
dmnsn_texture_cascade(default._texture, &self._scene.default_texture)
- return _Progress(dmnsn_raytrace_scene_async(self._scene))
+ return _Future(dmnsn_raytrace_scene_async(self._scene))
def __dealloc__(self):
dmnsn_delete_scene(self._scene)
diff --git a/libdimension/Makefile.am b/libdimension/Makefile.am
index 2a62a91..84f880c 100644
--- a/libdimension/Makefile.am
+++ b/libdimension/Makefile.am
@@ -37,6 +37,7 @@ nobase_include_HEADERS = dimension.h \
dimension/error.h \
dimension/finish.h \
dimension/finishes.h \
+ dimension/future.h \
dimension/geometry.h \
dimension/gl.h \
dimension/inline.h \
@@ -53,7 +54,6 @@ nobase_include_HEADERS = dimension.h \
dimension/pigments.h \
dimension/png.h \
dimension/polynomial.h \
- dimension/progress.h \
dimension/raytrace.h \
dimension/refcount.h \
dimension/scene.h \
@@ -77,6 +77,8 @@ libdimension_la_SOURCES = $(nobase_include_HEADERS) \
dimension-internal.h \
error.c \
finish.c \
+ future.c \
+ future-impl.h \
geometry.c \
gradient.c \
inline.c \
@@ -98,8 +100,6 @@ libdimension_la_SOURCES = $(nobase_include_HEADERS) \
profile.h \
point_light.c \
polynomial.c \
- progress.c \
- progress-impl.h \
prtree.c \
prtree.h \
raytrace.c \
diff --git a/libdimension/bench/prtree.c b/libdimension/bench/prtree.c
index 7c38990..7db2bbc 100644
--- a/libdimension/bench/prtree.c
+++ b/libdimension/bench/prtree.c
@@ -19,7 +19,7 @@
#include "../prtree.c"
#include "../threads.c"
-#include "../progress.c"
+#include "../future.c"
#include <sandglass.h>
#include <stdlib.h>
diff --git a/libdimension/dimension-internal.h b/libdimension/dimension-internal.h
index 21e2f42..4370f6b 100644
--- a/libdimension/dimension-internal.h
+++ b/libdimension/dimension-internal.h
@@ -32,7 +32,7 @@
#include "compiler.h"
#include "profile.h"
#include "platform.h"
-#include "progress-impl.h"
+#include "future-impl.h"
#include "threads.h"
#include "prtree.h"
diff --git a/libdimension/dimension.h b/libdimension/dimension.h
index 309eaa2..59b73bd 100644
--- a/libdimension/dimension.h
+++ b/libdimension/dimension.h
@@ -80,7 +80,7 @@ typedef void dmnsn_free_fn(void *ptr);
#include <dimension/refcount.h>
#include <dimension/array.h>
#include <dimension/dictionary.h>
-#include <dimension/progress.h>
+#include <dimension/future.h>
#include <dimension/timer.h>
#include <dimension/geometry.h>
#include <dimension/polynomial.h>
diff --git a/libdimension/dimension/progress.h b/libdimension/dimension/future.h
index 3464a9b..f0693b9 100644
--- a/libdimension/dimension/progress.h
+++ b/libdimension/dimension/future.h
@@ -21,39 +21,39 @@
/**
* @file
* An interface for asynchronous tasks. *_async() versions of functions
- * return a dmnsn_progress* object which can indicate the progress of the
+ * return a dmnsn_future* object which can indicate the progress of the
* background task, and wait for task completion. The task's return value
* is returned as an int from dmnsn_finish_progress().
*/
-/** A progress object. */
-typedef struct dmnsn_progress dmnsn_progress;
+/** A future object. */
+typedef struct dmnsn_future dmnsn_future;
/**
- * Join the worker thread and return it's integer return value in addition to
- * deleting \p progress.
- * @param[in,out] progress The background task to finish.
+ * Join the worker thread and return its integer return value in addition to
+ * deleting \p future.
+ * @param[in,out] future The background task to join.
* @return The return value of the background task.
*/
-int dmnsn_finish_progress(dmnsn_progress *progress);
+int dmnsn_future_join(dmnsn_future *future);
/**
* Interrupt the execution of a background thread.
- * @param[in,out] progress The background task to cancel.
+ * @param[in,out] future The background task to cancel.
*/
-void dmnsn_cancel_progress(dmnsn_progress *progress);
+void dmnsn_future_cancel(dmnsn_future *future);
/**
* Get the progress of the background task.
- * @param[in] progress The background task to examine.
- * @return The progress of the background task, out of 1.0.
+ * @param[in] future The background task to examine.
+ * @return The progress of the background task, in [0.0, 1.0].
*/
-double dmnsn_get_progress(const dmnsn_progress *progress);
+double dmnsn_future_progress(const dmnsn_future *future);
/**
* Wait for a certain amount of progress. Always use this rather than
* spinlocking.
- * @param[in] progress The background task to monitor.
- * @param[in] prog The progress value to wait for.
+ * @param[in] future The background task to monitor.
+ * @param[in] progress The progress value to wait for.
*/
-void dmnsn_wait_progress(const dmnsn_progress *progress, double prog);
+void dmnsn_future_wait(const dmnsn_future *future, double progress);
diff --git a/libdimension/dimension/png.h b/libdimension/dimension/png.h
index e3519a0..244c481 100644
--- a/libdimension/dimension/png.h
+++ b/libdimension/dimension/png.h
@@ -44,10 +44,10 @@ int dmnsn_png_write_canvas(const dmnsn_canvas *canvas, FILE *file);
* Write a canvas to a PNG file in the background.
* @param[in] canvas The canvas to write.
* @param[in,out] file The file to write to.
- * @return A \ref dmnsn_progress object, or NULL on failure.
+ * @return A \ref dmnsn_future object, or NULL on failure.
*/
-dmnsn_progress *dmnsn_png_write_canvas_async(const dmnsn_canvas *canvas,
- FILE *file);
+dmnsn_future *dmnsn_png_write_canvas_async(const dmnsn_canvas *canvas,
+ FILE *file);
/**
* Read a canvas from a PNG file.
@@ -63,6 +63,6 @@ dmnsn_canvas *dmnsn_png_read_canvas(FILE *file);
* contents of \p file. Do not read from this object
* until the background task has finished.
* @param[in,out] file The PNG file to read.
- * @return A \ref dmnsn_progress object, or NULL on failure.
+ * @return A \ref dmnsn_future object, or NULL on failure.
*/
-dmnsn_progress *dmnsn_png_read_canvas_async(dmnsn_canvas **canvas, FILE *file);
+dmnsn_future *dmnsn_png_read_canvas_async(dmnsn_canvas **canvas, FILE *file);
diff --git a/libdimension/dimension/raytrace.h b/libdimension/dimension/raytrace.h
index eed8a75..79c148d 100644
--- a/libdimension/dimension/raytrace.h
+++ b/libdimension/dimension/raytrace.h
@@ -32,6 +32,6 @@ void dmnsn_raytrace_scene(dmnsn_scene *scene);
/**
* Render a scene in the background.
* @param[in,out] scene The scene to render.
- * @return A \p dmnsn_progress object.
+ * @return A \p dmnsn_future object.
*/
-dmnsn_progress *dmnsn_raytrace_scene_async(dmnsn_scene *scene);
+dmnsn_future *dmnsn_raytrace_scene_async(dmnsn_scene *scene);
diff --git a/libdimension/progress-impl.h b/libdimension/future-impl.h
index 6c10ff8..c25a7c2 100644
--- a/libdimension/progress-impl.h
+++ b/libdimension/future-impl.h
@@ -20,36 +20,35 @@
/**
* @file
- * Progress object implementation.
+ * Future object implementation.
*/
#include <pthread.h>
-/** Allocate a new progress object. */
-DMNSN_INTERNAL dmnsn_progress *dmnsn_new_progress(void);
+/** Allocate a new future object. */
+DMNSN_INTERNAL dmnsn_future *dmnsn_new_future(void);
/** Set the total number of loop iterations. */
-DMNSN_INTERNAL void dmnsn_set_progress_total(dmnsn_progress *progress,
- size_t total);
-/** Increment the progress counter. */
-DMNSN_INTERNAL void dmnsn_increment_progress(dmnsn_progress *progress);
-/** Instantly complete the progress. */
-DMNSN_INTERNAL void dmnsn_done_progress(dmnsn_progress *progress);
-
-struct dmnsn_progress {
+DMNSN_INTERNAL void dmnsn_future_set_total(dmnsn_future *future, size_t total);
+/** Increment the progress of a background task. */
+DMNSN_INTERNAL void dmnsn_future_increment(dmnsn_future *future);
+/** Instantly complete the background teask. */
+DMNSN_INTERNAL void dmnsn_future_done(dmnsn_future *future);
+
+struct dmnsn_future {
size_t progress; /**< Completed loop iterations. */
size_t total; /**< Total expected loop iterations. */
- /* The worker thread */
+ /** The worker thread. */
pthread_t thread;
- /* Read-write synchronization */
+ /** Read-write synchronization. */
pthread_rwlock_t *rwlock;
- /* Condition variable for waiting for a particular amount of progress */
+ /** Condition variable for waiting for a particular amount of progress. */
pthread_cond_t *cond;
pthread_mutex_t *mutex;
- /* Minimum waited-on value */
+ /** Minimum waited-on value. */
double *min_wait;
};
diff --git a/libdimension/future.c b/libdimension/future.c
new file mode 100644
index 0000000..c328815
--- /dev/null
+++ b/libdimension/future.c
@@ -0,0 +1,164 @@
+/*************************************************************************
+ * Copyright (C) 2009-2011 Tavian Barnes <tavianator@tavianator.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/>. *
+ *************************************************************************/
+
+/**
+ * @file
+ * Future objects.
+ */
+
+#include "dimension-internal.h"
+#include <pthread.h>
+
+/* Allocate a new dmnsn_future* */
+dmnsn_future *
+dmnsn_new_future(void)
+{
+ dmnsn_future *future = dmnsn_malloc(sizeof(dmnsn_future));
+ future->progress = 0;
+ future->total = 1;
+
+ /* Initialize the rwlock, condition variable, and mutex */
+
+ future->rwlock = dmnsn_malloc(sizeof(pthread_rwlock_t));
+ dmnsn_initialize_rwlock(future->rwlock);
+
+ future->cond = dmnsn_malloc(sizeof(pthread_cond_t));
+ dmnsn_initialize_cond(future->cond);
+
+ future->mutex = dmnsn_malloc(sizeof(pthread_mutex_t));
+ dmnsn_initialize_mutex(future->mutex);
+
+ future->min_wait = dmnsn_malloc(sizeof(double));
+ *future->min_wait = 1.0;
+
+ return future;
+}
+
+/* Join the worker thread and delete `future'. */
+int
+dmnsn_future_join(dmnsn_future *future)
+{
+ void *ptr;
+ int retval = -1;
+
+ if (future) {
+ /* Get the thread's return value */
+ dmnsn_join_thread(future->thread, &ptr);
+ if (ptr && ptr != PTHREAD_CANCELED) {
+ retval = *(int *)ptr;
+ dmnsn_free(ptr);
+ }
+
+ /* Free the future object */
+
+ dmnsn_free(future->min_wait);
+
+ dmnsn_destroy_mutex(future->mutex);
+ dmnsn_free(future->mutex);
+
+ dmnsn_destroy_cond(future->cond);
+ dmnsn_free(future->cond);
+
+ dmnsn_destroy_rwlock(future->rwlock);
+ dmnsn_free(future->rwlock);
+
+ dmnsn_free(future);
+ }
+
+ return retval;
+}
+
+/* Cancel a background thread */
+void
+dmnsn_future_cancel(dmnsn_future *future)
+{
+ pthread_cancel(future->thread);
+}
+
+/* Get the current progress of the worker thread, in [0.0, 1.0] */
+double
+dmnsn_future_progress(const dmnsn_future *future)
+{
+ double progress;
+
+ dmnsn_read_lock(future->rwlock);
+ progress = (double)future->progress/future->total;
+ dmnsn_unlock_rwlock(future->rwlock);
+
+ return progress;
+}
+
+/* Wait until dmnsn_future_progress(future) >= progress */
+void
+dmnsn_future_wait(const dmnsn_future *future, double progress)
+{
+ dmnsn_lock_mutex(future->mutex);
+ while (dmnsn_future_progress(future) < progress) {
+ /* Set the minimum waited-on value */
+ if (progress < *future->min_wait)
+ *future->min_wait = progress;
+
+ dmnsn_cond_wait(future->cond, future->mutex);
+ }
+ dmnsn_unlock_mutex(future->mutex);
+}
+
+/* Set the total number of loop iterations */
+void
+dmnsn_future_set_total(dmnsn_future *future, size_t total)
+{
+ dmnsn_write_lock(future->rwlock);
+ future->total = total;
+ dmnsn_unlock_rwlock(future->rwlock);
+}
+
+/* Increment the number of completed loop iterations */
+void
+dmnsn_future_increment(dmnsn_future *future)
+{
+ /* Allow a thread to be canceled whenever it increments a future object --
+ this is close to PTHREAD_CANCEL_ASYNCHRONOUS but allows consistent state
+ on cancellation */
+ pthread_testcancel();
+
+ dmnsn_write_lock(future->rwlock);
+ ++future->progress;
+ dmnsn_unlock_rwlock(future->rwlock);
+
+ dmnsn_lock_mutex(future->mutex);
+ if (dmnsn_future_progress(future) >= *future->min_wait) {
+ *future->min_wait = 1.0;
+ dmnsn_cond_broadcast(future->cond);
+ }
+ dmnsn_unlock_mutex(future->mutex);
+}
+
+/* Immediately set to 100% completion */
+void
+dmnsn_future_done(dmnsn_future *future)
+{
+ dmnsn_write_lock(future->rwlock);
+ future->progress = future->total;
+ dmnsn_unlock_rwlock(future->rwlock);
+
+ dmnsn_lock_mutex(future->mutex);
+ dmnsn_cond_broadcast(future->cond);
+ dmnsn_unlock_mutex(future->mutex);
+}
diff --git a/libdimension/png.c b/libdimension/png.c
index 21ad764..d633abb 100644
--- a/libdimension/png.c
+++ b/libdimension/png.c
@@ -77,14 +77,14 @@ dmnsn_png_optimizer_fn(const dmnsn_canvas *canvas,
/** Payload type for PNG write thread callback. */
typedef struct {
- dmnsn_progress *progress;
+ dmnsn_future *future;
const dmnsn_canvas *canvas;
FILE *file;
} dmnsn_png_write_payload;
/** Payload type for PNG read thread callback. */
typedef struct {
- dmnsn_progress *progress;
+ dmnsn_future *future;
dmnsn_canvas **canvas;
FILE *file;
} dmnsn_png_read_payload;
@@ -99,26 +99,26 @@ static int dmnsn_png_read_canvas_thread(void *ptr);
int
dmnsn_png_write_canvas(const dmnsn_canvas *canvas, FILE *file)
{
- dmnsn_progress *progress = dmnsn_png_write_canvas_async(canvas, file);
- return dmnsn_finish_progress(progress);
+ dmnsn_future *future = dmnsn_png_write_canvas_async(canvas, file);
+ return dmnsn_future_join(future);
}
/* Write a canvas to a png file in the background */
-dmnsn_progress *
+dmnsn_future *
dmnsn_png_write_canvas_async(const dmnsn_canvas *canvas, FILE *file)
{
- dmnsn_progress *progress = dmnsn_new_progress();
+ dmnsn_future *future = dmnsn_new_future();
dmnsn_png_write_payload *payload
= dmnsn_malloc(sizeof(dmnsn_png_write_payload));
- payload->progress = progress;
- payload->canvas = canvas;
- payload->file = file;
+ payload->future = future;
+ payload->canvas = canvas;
+ payload->file = file;
/* Create the worker thread */
- dmnsn_new_thread(progress, dmnsn_png_write_canvas_thread, payload);
+ dmnsn_new_thread(future, dmnsn_png_write_canvas_thread, payload);
- return progress;
+ return future;
}
/* Read a canvas from the PNG file `file'. Return NULL on error. */
@@ -126,28 +126,28 @@ dmnsn_canvas *
dmnsn_png_read_canvas(FILE *file)
{
dmnsn_canvas *canvas;
- dmnsn_progress *progress = dmnsn_png_read_canvas_async(&canvas, file);
- dmnsn_finish_progress(progress);
+ dmnsn_future *future = dmnsn_png_read_canvas_async(&canvas, file);
+ dmnsn_future_join(future);
return canvas;
}
/* Read a canvas from a png file in the background */
-dmnsn_progress *
+dmnsn_future *
dmnsn_png_read_canvas_async(dmnsn_canvas **canvas, FILE *file)
{
- dmnsn_progress *progress = dmnsn_new_progress();
+ dmnsn_future *future = dmnsn_new_future();
dmnsn_png_read_payload *payload
= dmnsn_malloc(sizeof(dmnsn_png_write_payload));
- payload->progress = progress;
- payload->canvas = canvas;
- *payload->canvas = NULL;
- payload->file = file;
+ payload->future = future;
+ payload->canvas = canvas;
+ *payload->canvas = NULL;
+ payload->file = file;
/* Create the worker thread */
- dmnsn_new_thread(progress, dmnsn_png_read_canvas_thread, payload);
+ dmnsn_new_thread(future, dmnsn_png_read_canvas_thread, payload);
- return progress;
+ return future;
}
/*
@@ -163,7 +163,7 @@ dmnsn_png_write_canvas_thread(void *ptr)
png_uint_32 width = payload->canvas->width;
png_uint_32 height = payload->canvas->height;
- dmnsn_set_progress_total(payload->progress, height);
+ dmnsn_future_set_total(payload->future, height);
png_structp png_ptr
= png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
@@ -220,7 +220,7 @@ dmnsn_png_write_canvas_thread(void *ptr)
/* 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(payload->progress);
+ dmnsn_future_increment(payload->future);
}
/* Finish the PNG file */
@@ -251,7 +251,7 @@ dmnsn_png_write_canvas_thread(void *ptr)
/* Write the row */
png_write_row(png_ptr, (png_bytep)row);
- dmnsn_increment_progress(payload->progress);
+ dmnsn_future_increment(payload->future);
}
/* Finish the PNG file */
@@ -263,15 +263,15 @@ dmnsn_png_write_canvas_thread(void *ptr)
return 0;
}
-/** Thread-specific pointer to the appropriate dmnsn_progress* for
+/** Thread-specific pointer to the appropriate dmnsn_future* for
dmnsn_png_read_row_callback. */
-static __thread dmnsn_progress *dmnsn_tl_png_read_progress;
+static __thread dmnsn_future *dmnsn_tl_png_read_future;
/** 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)
{
- dmnsn_increment_progress(dmnsn_tl_png_read_progress);
+ dmnsn_future_increment(dmnsn_tl_png_read_future);
}
/* Read a PNG file */
@@ -279,7 +279,7 @@ static int
dmnsn_png_read_canvas_thread(void *ptr)
{
dmnsn_png_read_payload *payload = ptr;
- dmnsn_tl_png_read_progress = payload->progress;
+ dmnsn_tl_png_read_future = payload->future;
png_byte header[8];
if (fread(header, 1, 8, payload->file) != 8) {
@@ -336,7 +336,7 @@ dmnsn_png_read_canvas_thread(void *ptr)
&interlace_type, &compression_type, &filter_method);
int number_of_passes = png_set_interlace_handling(png_ptr);
- dmnsn_set_progress_total(payload->progress, (number_of_passes + 1)*height);
+ dmnsn_future_set_total(payload->future, (number_of_passes + 1)*height);
png_set_read_status_fn(png_ptr, dmnsn_png_read_row_callback);
/*
@@ -423,7 +423,7 @@ dmnsn_png_read_canvas_thread(void *ptr)
dmnsn_set_pixel(*payload->canvas, x, height - y - 1, color);
}
- dmnsn_increment_progress(payload->progress);
+ dmnsn_future_increment(payload->future);
}
dmnsn_free(row_pointers);
diff --git a/libdimension/progress.c b/libdimension/progress.c
deleted file mode 100644
index f2ff25f..0000000
--- a/libdimension/progress.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*************************************************************************
- * Copyright (C) 2009-2011 Tavian Barnes <tavianator@tavianator.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/>. *
- *************************************************************************/
-
-/**
- * @file
- * Progress objects.
- */
-
-#include "dimension-internal.h"
-#include <pthread.h>
-
-/* Allocate a new dmnsn_progress* */
-dmnsn_progress *
-dmnsn_new_progress(void)
-{
- dmnsn_progress *progress = dmnsn_malloc(sizeof(dmnsn_progress));
- progress->progress = 0;
- progress->total = 1;
-
- /* Initialize the rwlock, condition variable, and mutex */
-
- progress->rwlock = dmnsn_malloc(sizeof(pthread_rwlock_t));
- dmnsn_initialize_rwlock(progress->rwlock);
-
- progress->cond = dmnsn_malloc(sizeof(pthread_cond_t));
- dmnsn_initialize_cond(progress->cond);
-
- progress->mutex = dmnsn_malloc(sizeof(pthread_mutex_t));
- dmnsn_initialize_mutex(progress->mutex);
-
- progress->min_wait = dmnsn_malloc(sizeof(double));
- *progress->min_wait = 1.0;
-
- return progress;
-}
-
-/* Join the worker thread and delete `progress'. */
-int
-dmnsn_finish_progress(dmnsn_progress *progress)
-{
- void *ptr;
- int retval = -1;
-
- if (progress) {
- /* Get the thread's return value */
- dmnsn_join_thread(progress->thread, &ptr);
- if (ptr && ptr != PTHREAD_CANCELED) {
- retval = *(int *)ptr;
- dmnsn_free(ptr);
- }
-
- /* Free the progress object */
-
- dmnsn_free(progress->min_wait);
-
- dmnsn_destroy_mutex(progress->mutex);
- dmnsn_free(progress->mutex);
-
- dmnsn_destroy_cond(progress->cond);
- dmnsn_free(progress->cond);
-
- dmnsn_destroy_rwlock(progress->rwlock);
- dmnsn_free(progress->rwlock);
-
- dmnsn_free(progress);
- }
-
- return retval;
-}
-
-/* Cancel a background thread */
-void
-dmnsn_cancel_progress(dmnsn_progress *progress)
-{
- pthread_cancel(progress->thread);
-}
-
-/* Get the current progress of the worker thread, in [0.0, 1.0] */
-double
-dmnsn_get_progress(const dmnsn_progress *progress)
-{
- double prog;
-
- dmnsn_read_lock(progress->rwlock);
- prog = (double)progress->progress/progress->total;
- dmnsn_unlock_rwlock(progress->rwlock);
-
- return prog;
-}
-
-/* Wait until dmnsn_get_progress(progress) >= prog */
-void
-dmnsn_wait_progress(const dmnsn_progress *progress, double prog)
-{
- dmnsn_lock_mutex(progress->mutex);
- while (dmnsn_get_progress(progress) < prog) {
- /* Set the minimum waited-on value */
- if (prog < *progress->min_wait)
- *progress->min_wait = prog;
-
- dmnsn_cond_wait(progress->cond, progress->mutex);
- }
- dmnsn_unlock_mutex(progress->mutex);
-}
-
-/* Set the total number of loop iterations */
-void
-dmnsn_set_progress_total(dmnsn_progress *progress, size_t total)
-{
- dmnsn_write_lock(progress->rwlock);
- progress->total = total;
- dmnsn_unlock_rwlock(progress->rwlock);
-}
-
-/* Increment the number of completed loop iterations */
-void
-dmnsn_increment_progress(dmnsn_progress *progress)
-{
- /* Allow a thread to be canceled whenever it increments a progress object --
- this is close to PTHREAD_CANCEL_ASYNCHRONOUS but allows consistent state
- on cancellation */
- pthread_testcancel();
-
- dmnsn_write_lock(progress->rwlock);
- ++progress->progress;
- dmnsn_unlock_rwlock(progress->rwlock);
-
- dmnsn_lock_mutex(progress->mutex);
- if (dmnsn_get_progress(progress) >= *progress->min_wait) {
- *progress->min_wait = 1.0;
-
- dmnsn_cond_broadcast(progress->cond);
- }
- dmnsn_unlock_mutex(progress->mutex);
-}
-
-/* Immediately set to 100% completion */
-void
-dmnsn_done_progress(dmnsn_progress *progress)
-{
- dmnsn_write_lock(progress->rwlock);
- progress->progress = progress->total;
- dmnsn_unlock_rwlock(progress->rwlock);
-
- dmnsn_lock_mutex(progress->mutex);
- dmnsn_cond_broadcast(progress->cond);
- dmnsn_unlock_mutex(progress->mutex);
-}
diff --git a/libdimension/raytrace.c b/libdimension/raytrace.c
index 4ee451a..e5d2a15 100644
--- a/libdimension/raytrace.c
+++ b/libdimension/raytrace.c
@@ -32,7 +32,7 @@
/** Payload type for passing arguments to worker threads. */
typedef struct {
- dmnsn_progress *progress;
+ dmnsn_future *future;
dmnsn_scene *scene;
dmnsn_prtree *prtree;
} dmnsn_raytrace_payload;
@@ -41,8 +41,8 @@ typedef struct {
void
dmnsn_raytrace_scene(dmnsn_scene *scene)
{
- dmnsn_progress *progress = dmnsn_raytrace_scene_async(scene);
- if (dmnsn_finish_progress(progress) != 0) {
+ dmnsn_future *future = dmnsn_raytrace_scene_async(scene);
+ if (dmnsn_future_join(future) != 0) {
dmnsn_error("Error occured while raytracing.");
}
}
@@ -51,19 +51,19 @@ dmnsn_raytrace_scene(dmnsn_scene *scene)
static int dmnsn_raytrace_scene_thread(void *ptr);
/* Raytrace a scene in the background */
-dmnsn_progress *
+dmnsn_future *
dmnsn_raytrace_scene_async(dmnsn_scene *scene)
{
- dmnsn_progress *progress = dmnsn_new_progress();
+ dmnsn_future *future = dmnsn_new_future();
dmnsn_raytrace_payload *payload =
dmnsn_malloc(sizeof(dmnsn_raytrace_payload));
- payload->progress = progress;
- payload->scene = scene;
+ payload->future = future;
+ payload->scene = scene;
- dmnsn_new_thread(progress, dmnsn_raytrace_scene_thread, payload);
+ dmnsn_new_thread(future, dmnsn_raytrace_scene_thread, payload);
- return progress;
+ return future;
}
/** Worker thread callback. */
@@ -84,8 +84,8 @@ dmnsn_raytrace_scene_thread(void *ptr)
payload->prtree = dmnsn_new_prtree(payload->scene->objects);
dmnsn_stop_timer(&payload->scene->bounding_timer);
- /* Set up the progress object */
- dmnsn_set_progress_total(payload->progress, payload->scene->canvas->height);
+ /* Set up the future object */
+ dmnsn_future_set_total(payload->future, payload->scene->canvas->height);
/* Time the render itself */
dmnsn_start_timer(&payload->scene->render_timer);
@@ -168,7 +168,7 @@ dmnsn_raytrace_scene_concurrent(void *ptr, unsigned int thread,
unsigned int nthreads)
{
const dmnsn_raytrace_payload *payload = ptr;
- dmnsn_progress *progress = payload->progress;
+ dmnsn_future *future = payload->future;
dmnsn_scene *scene = payload->scene;
dmnsn_prtree *prtree = payload->prtree;
@@ -197,7 +197,7 @@ dmnsn_raytrace_scene_concurrent(void *ptr, unsigned int thread,
dmnsn_set_pixel(scene->canvas, x, y, color);
}
- dmnsn_increment_progress(progress);
+ dmnsn_future_increment(future);
}
return 0;
diff --git a/libdimension/tests/prtree.c b/libdimension/tests/prtree.c
index 2e33368..d89a18d 100644
--- a/libdimension/tests/prtree.c
+++ b/libdimension/tests/prtree.c
@@ -23,7 +23,7 @@
#include "../prtree.c"
#include "../threads.c"
-#include "../progress.c"
+#include "../future.c"
#include <stdio.h>
#include <stdlib.h>
diff --git a/libdimension/tests/render.c b/libdimension/tests/render.c
index ee63d06..af22691 100644
--- a/libdimension/tests/render.c
+++ b/libdimension/tests/render.c
@@ -353,11 +353,11 @@ main(void)
/* Render the scene */
printf("Rendering scene\n");
- dmnsn_progress *progress = dmnsn_raytrace_scene_async(scene);
+ dmnsn_future *future = dmnsn_raytrace_scene_async(scene);
/* Display the scene as it's rendered */
if (display) {
- while (dmnsn_get_progress(progress) < 1.0) {
+ while (dmnsn_future_progress(future) < 1.0) {
if (dmnsn_gl_write_canvas(scene->canvas) != 0) {
dmnsn_delete_display(display);
dmnsn_delete_scene(scene);
@@ -368,7 +368,7 @@ main(void)
}
}
- if (dmnsn_finish_progress(progress) != 0) {
+ if (dmnsn_future_join(future) != 0) {
dmnsn_delete_display(display);
dmnsn_delete_scene(scene);
fprintf(stderr, "--- Raytracing failed! ---\n");
diff --git a/libdimension/threads.c b/libdimension/threads.c
index 2200671..0aed16d 100644
--- a/libdimension/threads.c
+++ b/libdimension/threads.c
@@ -30,7 +30,7 @@
typedef struct dmnsn_thread_payload {
dmnsn_thread_fn *thread_fn;
void *arg;
- dmnsn_progress *progress;
+ dmnsn_future *future;
} dmnsn_thread_payload;
/** Clean up after a thread. */
@@ -38,10 +38,10 @@ static void
dmnsn_thread_cleanup(void *arg)
{
dmnsn_thread_payload *payload = arg;
- dmnsn_progress *progress = payload->progress;
+ dmnsn_future *future = payload->future;
dmnsn_free(payload);
- dmnsn_done_progress(progress);
+ dmnsn_future_done(future);
}
/** pthread callback -- call the real thread callback. */
@@ -59,15 +59,14 @@ dmnsn_thread(void *arg)
}
void
-dmnsn_new_thread(dmnsn_progress *progress, dmnsn_thread_fn *thread_fn,
- void *arg)
+dmnsn_new_thread(dmnsn_future *future, 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;
+ payload->future = future;
- if (pthread_create(&progress->thread, NULL, dmnsn_thread, payload) != 0) {
+ if (pthread_create(&future->thread, NULL, dmnsn_thread, payload) != 0) {
dmnsn_error("Couldn't start thread.");
}
}
diff --git a/libdimension/threads.h b/libdimension/threads.h
index 7a599de..ea9fb2a 100644
--- a/libdimension/threads.h
+++ b/libdimension/threads.h
@@ -34,11 +34,11 @@ typedef int dmnsn_thread_fn(void *ptr);
/**
* Create a thread that cleans up after itself on errors.
- * @param[in,out] progress The progress object to associate with the thread.
+ * @param[in,out] future The future object to associate with the thread.
* @param[in] thread_fn The thread callback.
* @param[in,out] arg The pointer to pass to the thread callback.
*/
-DMNSN_INTERNAL void dmnsn_new_thread(dmnsn_progress *progress,
+DMNSN_INTERNAL void dmnsn_new_thread(dmnsn_future *future,
dmnsn_thread_fn *thread_fn, void *arg);
/**