summaryrefslogtreecommitdiffstats
path: root/libdimension/canvas.c
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 /libdimension/canvas.c
parent97d9b60f0fff735bace4653f3b321592ba4ed1cc (diff)
downloaddimension-968e1d8710004517639966bd4c6f83f37edccd21.tar.xz
Add read-write mutexes to canvas pixels. New error infrastructure.
Diffstat (limited to 'libdimension/canvas.c')
-rw-r--r--libdimension/canvas.c106
1 files changed, 100 insertions, 6 deletions
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.");
+ }
+}