summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2009-04-08 22:26:16 +0000
committerTavian Barnes <tavianator@gmail.com>2009-04-08 22:26:16 +0000
commit968e1d8710004517639966bd4c6f83f37edccd21 (patch)
tree09f2bfebd6dd0da42e3f47ccd909c075969f46d2
parent97d9b60f0fff735bace4653f3b321592ba4ed1cc (diff)
downloaddimension-968e1d8710004517639966bd4c6f83f37edccd21.tar.xz
Add read-write mutexes to canvas pixels. New error infrastructure.
-rw-r--r--libdimension/Makefile.am3
-rw-r--r--libdimension/canvas.c106
-rw-r--r--libdimension/dimension.h16
-rw-r--r--libdimension/dimension/canvas.h18
-rw-r--r--libdimension/error.c74
5 files changed, 210 insertions, 7 deletions
diff --git a/libdimension/Makefile.am b/libdimension/Makefile.am
index 69bcbb3..60c9347 100644
--- a/libdimension/Makefile.am
+++ b/libdimension/Makefile.am
@@ -21,5 +21,6 @@ nobase_include_HEADERS = dimension.h dimension/geometry.h dimension/color.h dime
lib_LTLIBRARIES = libdimension.la
-libdimension_la_SOURCES = dimension.h dimension/geometry.h dimension/color.h dimension/canvas.h canvas.c color.c geometry.c
+libdimension_la_SOURCES = dimension.h dimension/geometry.h dimension/color.h dimension/canvas.h canvas.c color.c geometry.c error.c
libdimension_la_LDFLAGS = -version-info 0:0:0
+libdimension_la_LIBADD = -lm -lpthread
diff --git a/libdimension/canvas.c b/libdimension/canvas.c
index 21d6d86..e56c391 100644
--- a/libdimension/canvas.c
+++ b/libdimension/canvas.c
@@ -19,34 +19,128 @@
*************************************************************************/
#include "dimension.h"
-#include <stdlib.h> /* For malloc(), free() */
+#include <pthread.h> /* Must be first included header */
+#include <stdlib.h> /* For malloc(), free() */
dmnsn_canvas *
dmnsn_new_canvas(unsigned int x, unsigned int y)
{
+ unsigned int i, j, k, l;
dmnsn_canvas *canvas = malloc(sizeof(dmnsn_canvas));
if (canvas) {
canvas->x = x;
canvas->y = y;
canvas->pixels = malloc(sizeof(dmnsn_color)*x*y);
+ if (!canvas->pixels) {
+ free(canvas);
+ return NULL;
+ }
- if (canvas->pixels) {
- return canvas;
- } else {
+ canvas->rwlocks = malloc(sizeof(pthread_rwlock_t)*x*y);
+ if (!canvas->rwlocks) {
+ free(canvas->pixels);
free(canvas);
return NULL;
}
- } else {
- return NULL;
+
+ for (i = 0; i < x; ++i) {
+ for (j = 0; j < y; ++j) {
+ if (pthread_rwlock_init(&canvas->rwlocks[j*x + i], NULL) != 0) {
+ /* pthread_rwlock_init failed. Destroy the locks we've already made,
+ free the canvas, and return NULL. We leak memory if destruction
+ fails (i.e. someone is somehow using an rwlock already). */
+ for (l = 0; l < j; ++l) {
+ for (k = 0; k < x; ++k) {
+ if (pthread_rwlock_destroy(&canvas->rwlocks[l*x + k]) != 0) {
+ /* Low severity, because leaked memory won't actually hurt us */
+ dmnsn_error(DMNSN_SEVERITY_LOW,
+ "Leaking rwlocks in failed allocation.");
+ }
+ }
+ }
+
+ for (k = 0; k < i; ++k) {
+ if (pthread_rwlock_destroy(&canvas->rwlocks[j*x + k]) != 0) {
+ dmnsn_error(DMNSN_SEVERITY_LOW,
+ "Leaking rwlocks in failed allocation.");
+ }
+ }
+
+ free(canvas->rwlocks);
+ free(canvas->pixels);
+ free(canvas);
+ return NULL;
+ }
+ }
+ }
}
+
+ return canvas;
}
void
dmnsn_delete_canvas(dmnsn_canvas *canvas)
{
+ unsigned int i, j;
+
if (canvas) {
+ for (i = 0; i < canvas->x; ++i) {
+ for (j = 0; j < canvas->y; ++j) {
+ if (pthread_rwlock_destroy(&canvas->rwlocks[j*canvas->x + i]) != 0) {
+ dmnsn_error(DMNSN_SEVERITY_LOW,
+ "Leaking rwlocks in deallocation.");
+ }
+ }
+ }
+
+ free(canvas->rwlocks);
free(canvas->pixels);
free(canvas);
}
}
+
+dmnsn_color
+dmnsn_get_pixel(const dmnsn_canvas *canvas, unsigned int x, unsigned int y)
+{
+ dmnsn_color color;
+ dmnsn_rdlock_pixel(canvas, x, y);
+ color = canvas->pixels[y*canvas->x + x];
+ dmnsn_unlock_pixel(canvas, x, y);
+ return color;
+}
+
+void
+dmnsn_set_pixel(dmnsn_canvas *canvas, dmnsn_color color,
+ unsigned int x, unsigned int y)
+{
+ dmnsn_wrlock_pixel(canvas, x, y);
+ canvas->pixels[y*canvas->x + x] = color;
+ dmnsn_unlock_pixel(canvas, x, y);
+}
+
+void
+dmnsn_rdlock_pixel(const dmnsn_canvas *canvas, unsigned int x, unsigned int y)
+{
+ if (pthread_rwlock_rdlock(&canvas->rwlocks[y*canvas->x + x]) != 0) {
+ dmnsn_error(DMNSN_SEVERITY_MEDIUM,
+ "Couldn't acquire read-lock for pixel.");
+ }
+}
+
+void
+dmnsn_wrlock_pixel(dmnsn_canvas *canvas, unsigned int x, unsigned int y)
+{
+ if (pthread_rwlock_wrlock(&canvas->rwlocks[y*canvas->x + x]) != 0) {
+ dmnsn_error(DMNSN_SEVERITY_MEDIUM,
+ "Couldn't acquire write-lock for pixel.");
+ }
+}
+
+void
+dmnsn_unlock_pixel(const dmnsn_canvas *canvas, unsigned int x, unsigned int y)
+{
+ if (pthread_rwlock_unlock(&canvas->rwlocks[y*canvas->x + x]) != 0) {
+ dmnsn_error(DMNSN_SEVERITY_MEDIUM, "Couldn't unlock pixel.");
+ }
+}
diff --git a/libdimension/dimension.h b/libdimension/dimension.h
index 558c9ed..fa38629 100644
--- a/libdimension/dimension.h
+++ b/libdimension/dimension.h
@@ -28,6 +28,22 @@
extern "C" {
#endif
+/* Debug and error handling stuff */
+
+typedef enum {
+ DMNSN_SEVERITY_LOW, /* Only die on low resilience */
+ DMNSN_SEVERITY_MEDIUM, /* Die on low or medium resilience */
+ DMNSN_SEVERITY_HIGH /* Always die */
+} dmnsn_severity;
+
+#define dmnsn_error(severity, str) dmnsn_report_error(severity, __func__, str)
+
+void dmnsn_report_error(dmnsn_severity severity,
+ const char *func, const char *str);
+dmnsn_severity dmnsn_get_resilience();
+void dmnsn_set_resilience(dmnsn_severity resilience);
+
+/* More includes */
#include <dimension/geometry.h>
#include <dimension/color.h>
#include <dimension/canvas.h>
diff --git a/libdimension/dimension/canvas.h b/libdimension/dimension/canvas.h
index 21d56e4..d40ed1d 100644
--- a/libdimension/dimension/canvas.h
+++ b/libdimension/dimension/canvas.h
@@ -25,6 +25,8 @@
#ifndef DIMENSION_CANVAS_H
#define DIMENSION_CANVAS_H
+#include <pthread.h>
+
typedef struct {
unsigned int x, y;
@@ -33,9 +35,25 @@ typedef struct {
* at (a,b) is accessible as pixels[b*x + a].
*/
dmnsn_color *pixels;
+
+ /* Read-write locks for each pixel */
+ pthread_rwlock_t *rwlocks;
} dmnsn_canvas;
dmnsn_canvas *dmnsn_new_canvas(unsigned int x, unsigned int y);
void dmnsn_delete_canvas(dmnsn_canvas *canvas);
+/* These handle the rwlocks correctly */
+dmnsn_color dmnsn_get_pixel(const dmnsn_canvas *canvas,
+ unsigned int x, unsigned int y);
+void dmnsn_set_pixel(dmnsn_canvas *canvas, dmnsn_color color,
+ unsigned int x, unsigned int y);
+
+/* Manual locking */
+void dmnsn_rdlock_pixel(const dmnsn_canvas *canvas,
+ unsigned int x, unsigned int y);
+void dmnsn_wrlock_pixel(dmnsn_canvas *canvas, unsigned int x, unsigned int y);
+void dmnsn_unlock_pixel(const dmnsn_canvas *canvas,
+ unsigned int x, unsigned int y);
+
#endif /* DIMENSION_CANVAS_H */
diff --git a/libdimension/error.c b/libdimension/error.c
new file mode 100644
index 0000000..b91c192
--- /dev/null
+++ b/libdimension/error.c
@@ -0,0 +1,74 @@
+/*************************************************************************
+ * Copyright (C) 2008 Tavian Barnes <tavianator@gmail.com> *
+ * *
+ * This file is part of Dimension. *
+ * *
+ * Dimension 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. *
+ * *
+ * Dimension 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.h"
+#include <pthread.h>
+#include <stdio.h> /* For fprintf() */
+#include <stdlib.h> /* For exit() */
+
+static dmnsn_severity dmnsn_resilience = DMNSN_SEVERITY_MEDIUM;
+static pthread_mutex_t dmnsn_resilience_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void
+dmnsn_report_error(dmnsn_severity severity, const char *func, const char *str)
+{
+ if (severity >= dmnsn_get_resilience()) {
+ fprintf(stderr, "Dimension ERROR: %s(): %s\n", func, str);
+ exit(1);
+ } else {
+ fprintf(stderr, "Dimension WARNING: %s(): %s\n", func, str);
+ }
+}
+
+dmnsn_severity
+dmnsn_get_resilience()
+{
+ dmnsn_severity resilience;
+ if (pthread_mutex_lock(&dmnsn_resilience_mutex) != 0) {
+ fprintf(stderr, "Dimension WARNING: %s(): %s\n", __func__,
+ "Couldn't lock resilience mutex.");
+ }
+ resilience = dmnsn_resilience;
+ if (pthread_mutex_unlock(&dmnsn_resilience_mutex) != 0) {
+ fprintf(stderr, "Dimension WARNING: %s(): %s\n", __func__,
+ "Couldn't unlock resilience mutex.");
+ }
+ return resilience;
+}
+
+void
+dmnsn_set_resilience(dmnsn_severity resilience)
+{
+ if (resilience > DMNSN_SEVERITY_HIGH) {
+ fprintf(stderr, "Dimension ERROR: %s(): %s\n", __func__,
+ "Resilience has wrong value.");
+ exit(1);
+ }
+
+ if (pthread_mutex_lock(&dmnsn_resilience_mutex) != 0) {
+ fprintf(stderr, "Dimension WARNING: %s(): %s\n", __func__,
+ "Couldn't lock resilience mutex.");
+ }
+ dmnsn_resilience = resilience;
+ if (pthread_mutex_unlock(&dmnsn_resilience_mutex) != 0) {
+ fprintf(stderr, "Dimension WARNING: %s(): %s\n", __func__,
+ "Couldn't unlock resilience mutex.");
+ }
+}