render_thread works now
authorTero Marttila <terom@fixme.fi>
Thu, 26 Jun 2008 02:57:20 +0300
changeset 24 8307d28329ae
parent 23 31307efd7e78
child 25 a1e271de54c2
render_thread works now

committer: Tero Marttila <terom@fixme.fi>
common.c
common.h
node_main.c
render_local.c
render_local.h
render_png.c
render_thread.c
render_thread.h
render_thread_struct.h
web_main.c
--- a/common.c	Thu Jun 26 01:32:56 2008 +0300
+++ b/common.c	Thu Jun 26 02:57:20 2008 +0300
@@ -8,7 +8,7 @@
 #include "common.h"
 
 static void _generic_err_vargs (int use_stderr, const char *func, int perr, const char *fmt, va_list va) {
-    FILE *stream = use_stderr ? stderr : stdin;
+    FILE *stream = use_stderr ? stderr : stdout;
 
     if (func)
         fprintf(stream, "%s: ", func);
--- a/common.h	Thu Jun 26 01:32:56 2008 +0300
+++ b/common.h	Thu Jun 26 02:57:20 2008 +0300
@@ -44,7 +44,7 @@
 #ifdef DEBUG_ENABLED
 #define DEBUG(...) err_func(__func__, __VA_ARGS__)
 #else
-#define DEBUG(...) if (0) { }
+#define DEBUG(...) (void) (0)
 #endif
 
 // default is to enable INFO
@@ -55,7 +55,7 @@
 #if INFO_ENABLED
 #define INFO(...) info(__VA_ARGS__)
 #else
-#define INFO(...) if (0) { }
+#define INFO(...) (void) (0)
 #endif
 
 /*
--- a/node_main.c	Thu Jun 26 01:32:56 2008 +0300
+++ b/node_main.c	Thu Jun 26 02:57:20 2008 +0300
@@ -31,6 +31,10 @@
         perr_exit("sigaction");
 }
 
+void log_null (int severity, const char *msg) {
+    // ignore
+}
+
 /*
  * State needed to handle a client
  */
@@ -76,9 +80,13 @@
     free(ctx);
 }
 
-static void handle_render_done (struct render_thread *thread_info, void *arg) {
+static void handle_render_done (struct render_thread *thread_info, int err, void *arg) {
     struct client_info *ctx = arg;
 
+#if INFO_ENABLED
+    INFO("client [%p]: %s", ctx, err ? "failed" : "done");
+#endif    
+
     // just free it, it takes care of closing it as well
     client_free(ctx);
 }
@@ -151,7 +159,7 @@
         return;
     }
     
-    PWARNING("eventbuffer: %s %s",
+    PWARNING("client [%p]: eventbuffer error: %s %s", ctx,
         (what & EVBUFFER_READ) ? "read" : ((what & EVBUFFER_WRITE) ? "write" : "???"),
         (what & EVBUFFER_EOF) ? "eof" : ((what & EVBUFFER_ERROR) ? "error" : ((what & EVBUFFER_TIMEOUT) ? "timeout" : "???"))
     );
@@ -175,6 +183,13 @@
     if ((socket = accept(fd, (struct sockaddr *) &addr, &addr_len)) == -1)
         PERROR("accept");
     
+    // alloc a new client_info
+    if (!(ctx = calloc(1, sizeof(*ctx))))
+        ERROR("calloc");
+    
+    // store the socket
+    ctx->socket = socket;
+
 #if INFO_ENABLED
     assert(INET_ADDRSTRLEN < INET6_ADDRSTRLEN);
 
@@ -201,17 +216,9 @@
         addr_str = addr_buf;
     }
 
-    INFO("ACCEPT: %s:%hu\n", addr_str, ntohs(nport));
-
+    INFO("client [%p]: accept from %s:%hu", ctx, addr_str, ntohs(nport));
 #endif
 
-    // alloc a new client_info
-    if (!(ctx = calloc(1, sizeof(*ctx))))
-        ERROR("calloc");
-    
-    // store the socket
-    ctx->socket = socket;
-
     // then a bufferevent so that we can read in the command
     if (!(ctx->bufev = bufferevent_new(ctx->socket, &handle_read, NULL, &handle_error, ctx)))
         ERROR("bufferevent_new");
@@ -224,6 +231,7 @@
     bufferevent_setwatermark(ctx->bufev, EV_READ, sizeof(struct render_cmd), 0);
     
     // now we just wait for the cmd...
+    return;
 
 error:
     if (ctx)
@@ -240,6 +248,7 @@
     // parse arguments
     int opt;
     const char *port_name = NULL;
+    int enable_debug = 0;
     unsigned short port;
 
     while ((opt = getopt(argc, argv, "l:")) != -1) {
@@ -251,11 +260,20 @@
                 port_name = optarg;
                 break;
 
+            case 'd':
+                // enable libevent debugging
+                enable_debug = 1;
+                break;
+
             default:
-                err_exit("Usage: %s [-l port]", argv[0]);
+                err_exit("Usage: %s [-l port] [-d]", argv[0]);
         }
     }
     
+    // init libevent
+    if (!(ev_base = event_init()))
+        FATAL("event_init");
+
     // post-process arguments
     if (!port_name)
         port_name = RENDER_PORT_NAME;
@@ -263,9 +281,9 @@
     if (!(port = atoi(port_name)))
         ERROR("invalid port: %s", port_name);
     
-    // init libevent
-    if (!(ev_base = event_init()))
-        FATAL("event_init");
+    // per default it is enabled
+    if (!enable_debug)
+        event_set_log_callback(&log_null);
 
     // create the socket
     if ((ssock = socket(PF_INET, SOCK_STREAM, 0)) == -1)
@@ -284,7 +302,7 @@
     // create the listen event
     struct event listen_ev;
 
-    event_set(&listen_ev, ssock, EV_READ, &handle_accept, NULL);
+    event_set(&listen_ev, ssock, EV_READ | EV_PERSIST, &handle_accept, NULL);
 
     if (event_add(&listen_ev, NULL))
         PERROR("event_add");
@@ -293,12 +311,12 @@
     sigpipe_ignore();
     
     // run the libevent mainloop
-    printf("RUN: %s:%hu\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
+    INFO("run: %s:%hu", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
  
     if (event_base_dispatch(ev_base))
         WARNING("event_dispatch");
 
-    printf("SHUTDOWN\n");
+    INFO("SHUTDOWN");
     
     event_base_free(ev_base);
 
--- a/render_local.c	Thu Jun 26 01:32:56 2008 +0300
+++ b/render_local.c	Thu Jun 26 02:57:20 2008 +0300
@@ -5,54 +5,61 @@
 #include "common.h"
 #include "render_struct.h"
 #include "render_local.h"
-#include "render_png_struct.h"
 #include "render_png.h"
-#include "render_raw_struct.h"
 #include "render_raw.h"
 #include "render_mandelbrot.h"
 
 int render_local (struct render *render, double *duration) {
-    unsigned char *rowbuf = NULL;
-    struct render_png png_ctx;
-    struct render_raw raw_ctx;
-    int must_deinit = 0;
-    clock_t t1, t2;
+    struct render_local ctx;
     
-    if (duration)
-        *duration = -1;
+    if (render_local_init(&ctx, render))
+        return -1;
+        
+    int err = render_local_run(&ctx, duration);
+
+    render_local_deinit(&ctx);
+
+    return err;
+}
+
+int render_local_init (struct render_local *ctx, struct render *render) {
+    // zero
+    memset(ctx, 0, sizeof(*ctx));
+
+    ctx->render_info = render;
 
     // alloc the memory buffer
-    if (!(rowbuf = malloc(render->img_w)))
+    if (!(ctx->rowbuf = malloc(render->img_w)))
         ERROR("malloc");
  
     // what mode?
     switch (render->mode) {
         case RENDER_PNG :
             // the render_png stuff
-            memset(&png_ctx, 0, sizeof(png_ctx));
+            memset(&ctx->png_ctx, 0, sizeof(ctx->png_ctx));
 
-            if (render_png_init(&png_ctx, render))
+            if (render_png_init(&ctx->png_ctx, render))
                 ERROR("render_png_init");
             
-            must_deinit = RENDER_PNG;
+            ctx->must_deinit = RENDER_PNG;
 
             //  set render_* to use the render_png
-            if (render_local_mem(render, &rowbuf, (int(*)(void *arg, unsigned char *)) &render_png_row, &png_ctx))
+            if (render_local_mem(render, &ctx->rowbuf, (int(*)(void *arg, unsigned char *)) &render_png_row, &ctx->png_ctx))
                 ERROR("render_local_mem");
 
             break;
 
         case RENDER_RAW :
             // the render_raw stuff
-            memset(&raw_ctx, 0, sizeof(raw_ctx));
+            memset(&ctx->raw_ctx, 0, sizeof(ctx->raw_ctx));
 
-            if (render_raw_init(&raw_ctx, render))
+            if (render_raw_init(&ctx->raw_ctx, render))
                 ERROR("render_raw_init");
             
-            must_deinit = RENDER_RAW;
+            ctx->must_deinit = RENDER_RAW;
 
             //  set render_* to use the render_raw
-            if (render_local_mem(render, &rowbuf, (int(*)(void *arg, unsigned char *)) &render_raw_row, &raw_ctx))
+            if (render_local_mem(render, &ctx->rowbuf, (int(*)(void *arg, unsigned char *)) &render_raw_row, &ctx->raw_ctx))
                 ERROR("render_local_mem");
 
             break;
@@ -60,14 +67,33 @@
         default :
             assert(0);
     }
-  
+    
+    // success
+    return 0;
+
+error:
+    render_local_deinit(ctx);
+
+    return -1;
+}
+
+int render_local_run (struct render_local *ctx, double *duration) {
+    clock_t t1, t2;
+    
+    if (duration)
+        *duration = -1;
+
     // then we can actually render
     t1 = clock();
 
-    if (render_mandelbrot(render))
-        ERROR("render_mandelbrot");
+    if (render_mandelbrot(ctx->render_info))
+        goto error;
 
     t2 = clock();
+
+    // flush the PNG
+    if (render_png_done(&ctx->png_ctx))
+        goto error;
     
     // calculate the time taken
     if (duration)
@@ -77,14 +103,18 @@
     return 0;
 
 error:
-    free(rowbuf);
-    
-    if (must_deinit == RENDER_PNG)
-        render_png_deinit(&png_ctx);
-
-    else if (must_deinit == RENDER_RAW)
-        render_raw_deinit(&raw_ctx);
-
+    // caller must deinit
+    //
     return -1;
 }
 
+void render_local_deinit (struct render_local *ctx) {
+    free(ctx->rowbuf);
+    
+    if (ctx->must_deinit == RENDER_PNG)
+        render_png_deinit(&ctx->png_ctx);
+
+    else if (ctx->must_deinit == RENDER_RAW)
+        render_raw_deinit(&ctx->raw_ctx);
+}
+
--- a/render_local.h	Thu Jun 26 01:32:56 2008 +0300
+++ b/render_local.h	Thu Jun 26 02:57:20 2008 +0300
@@ -2,6 +2,16 @@
 #define RENDER_LOCAL_H
 
 #include "render.h"
+#include "render_png_struct.h"
+#include "render_raw_struct.h"
+
+struct render_local {
+    struct render *render_info;
+    unsigned char *rowbuf;
+    struct render_png png_ctx;
+    struct render_raw raw_ctx;
+    int must_deinit;
+};
 
 /*
  * Renders the given struct render locally in one operation.
@@ -9,7 +19,12 @@
  * How this operates depends on the render mode:
  *  RENDER_PNG      - see render_png_init
  *  RENDER_RAW      - see render_raw_init
+ *
+ *  Note that the given render MUST remain valid across calls to init/run/deinit
  */
 int render_local (struct render *render, double *duration);
+int render_local_init (struct render_local *ctx, struct render *render);
+int render_local_run (struct render_local *ctx, double *duration);
+void render_local_deinit (struct render_local *ctx);
 
 #endif /* RENDER_LOCAL_H */
--- a/render_png.c	Thu Jun 26 01:32:56 2008 +0300
+++ b/render_png.c	Thu Jun 26 02:57:20 2008 +0300
@@ -154,18 +154,10 @@
 }
 
 int render_png_abort (struct render_png *ctx) {
-    // libpng error handling
-    if (setjmp(png_jmpbuf(ctx->png_ptr)))
-        ERROR("libpng");
-    
     // just free it
     _render_png_free(ctx);
 
     // success
     return 0;
-
-error:
-    free(ctx);
-    return -1;
 }
 
--- a/render_thread.c	Thu Jun 26 01:32:56 2008 +0300
+++ b/render_thread.c	Thu Jun 26 02:57:20 2008 +0300
@@ -18,18 +18,30 @@
     // measure how long it takes
     double duration;
     
-    // render it...
-    if (render_local(&ctx->render_info, &duration))
-        goto error;
+    struct render_local local_ctx;
+    
+    // initialize it...
+    if (!(ctx->err = render_local_init(&local_ctx, &ctx->render_info))) {
+        // setup the cancel exit handlers
+        pthread_cleanup_push( (void (*)(void *)) render_local_deinit, &local_ctx);
 
-#ifdef DEBUG_INFO
-    u_int32_t img_w, img_h;
+        // render it...
+        ctx->err = render_local_run(&local_ctx, &duration);
+        
+        if (!ctx->err) {
+#if INFO_ENABLED
+            u_int32_t img_w, img_h;
 
-    render_get_size(&ctx->render_info, &img_w, &img_h);
+            render_get_size(&ctx->render_info, &img_w, &img_h);
 
-    // report the duration
-    INFO("rendered [%ux%u] in %f seconds", img_w, img_h, duration);
+            // report the duration
+            INFO("rendered [%ux%u] in %f seconds", img_w, img_h, duration);
 #endif
+        }
+        
+        // cleanup
+        pthread_cleanup_pop(1);
+    }
 
     // notify completion, writeall()
     ssize_t ret;
@@ -52,6 +64,7 @@
     return NULL;
 
 error:
+    // if notifying of completion failed...
     return ctx;
 }
 
@@ -59,6 +72,14 @@
     struct render_thread *ctx = arg;
     void *thread_return;
 
+    // join the thread and check the return value
+    if (pthread_join(ctx->thread_id, &thread_return))
+        PWARNING("pthread_join");
+    else if (thread_return == PTHREAD_CANCELED)
+        PWARNING("PTHREAD_CANCELED");
+    else if (thread_return != NULL)
+        PWARNING("thread_return != NULL");
+
     // make a lazy effort to read the contents of the pipe
     struct render_thread *ctx2;
     char *buf = (void *) &ctx2;
@@ -82,19 +103,11 @@
     if (close(ctx->notify_fd))
         PWARNING("close(pipe-write)");
 
-    // join the thread and check the return value
-    if (pthread_join(ctx->thread_id, &thread_return))
-        PWARNING("pthread_join");
-    else if (thread_return == PTHREAD_CANCELED)
-        PWARNING("PTHREAD_CANCELED");
-    else if (thread_return != NULL)
-        PWARNING("thread_return != NULL");
-
     // mark it as done
     ctx->is_active = 0;
 
     // call our callback
-    ctx->cb_func(ctx, ctx->cb_arg);
+    ctx->cb_func(ctx, ctx->err, ctx->cb_arg);
 }
 
 int render_thread_init (struct render_thread *ctx, struct render *render_info, render_thread_done_cb cb_func, void *cb_arg) {
--- a/render_thread.h	Thu Jun 26 01:32:56 2008 +0300
+++ b/render_thread.h	Thu Jun 26 02:57:20 2008 +0300
@@ -10,7 +10,7 @@
 
 struct render_thread;
 
-typedef void (*render_thread_done_cb)(struct render_thread *ctx, void *arg);
+typedef void (*render_thread_done_cb)(struct render_thread *ctx, int err, void *arg);
 
 struct render_thread *render_thread_alloc (struct render *render, render_thread_done_cb cb_func, void *cb_arg);
 
--- a/render_thread_struct.h	Thu Jun 26 01:32:56 2008 +0300
+++ b/render_thread_struct.h	Thu Jun 26 02:57:20 2008 +0300
@@ -26,6 +26,9 @@
     // the notification event
     struct event ev;
 
+    // did the render fail?
+    int err;
+
     // already canceled/done?
     int is_active;
 };
--- a/web_main.c	Thu Jun 26 01:32:56 2008 +0300
+++ b/web_main.c	Thu Jun 26 02:57:20 2008 +0300
@@ -169,14 +169,13 @@
     // render context
     struct render render;
     
-    if (render_init(&render, RENDER_PNG))
-        ERROR("render_alloc");
-
-    if (render_set_size(&render, img_w, img_h))
-        ERROR("render_set_size");
-
-    if (render_region_full(&render))
-        ERROR("render_region_full");
+    if (
+            render_init(&render)
+         || render_set_mode(&render, RENDER_PNG)
+         || render_set_size(&render, img_w, img_h)
+         || render_region_full(&render)
+    )
+        ERROR("render_*");
 
     // initiate the remote render operation
     if ((ctx->render_info = render_remote(&render, &remote_pool,