# HG changeset patch # User Tero Marttila # Date 1214438240 -10800 # Node ID 8307d28329ae773eac10c621d028e96b1d052ea4 # Parent 31307efd7e7882708ba2c4b923c67dc9bad1edf9 render_thread works now committer: Tero Marttila diff -r 31307efd7e78 -r 8307d28329ae common.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); diff -r 31307efd7e78 -r 8307d28329ae common.h --- 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 /* diff -r 31307efd7e78 -r 8307d28329ae node_main.c --- 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); diff -r 31307efd7e78 -r 8307d28329ae render_local.c --- 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); +} + diff -r 31307efd7e78 -r 8307d28329ae render_local.h --- 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 */ diff -r 31307efd7e78 -r 8307d28329ae render_png.c --- 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; } diff -r 31307efd7e78 -r 8307d28329ae render_thread.c --- 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) { diff -r 31307efd7e78 -r 8307d28329ae render_thread.h --- 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); diff -r 31307efd7e78 -r 8307d28329ae render_thread_struct.h --- 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; }; diff -r 31307efd7e78 -r 8307d28329ae web_main.c --- 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,