static void *tea_thread(void *data) { int r; THREAD_WORK *tw = (THREAD_WORK *) data; /* initialize thread */ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &r); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &r); pthread_cleanup_push((void *) tea_thread_cleanup, tw); /* launch thread */ TDBG("[tea-thread] Starting thread main function"); tw->to->thread(tw); TDBG("[tea-thread] Thread main function finished."); /* wait until the correct die moment */ TDBG2("[tea-thread] Waiting for cleanup approval..."); while( pthreadex_flag_wait_timeout(&(tw->cleanup_do), 1000)) { TDBG2("[tea-thread] ..."); } /* finish him */ pthread_cleanup_pop(1); pthread_exit(NULL); return NULL; }
static void tea_thread_cleanup(THREAD_WORK *tw) { TEA_MSG_QUEUE *mq; /* do thread cleanup */ TDBG2("[tea-cleanup] Thread final cleanup started."); if(tw->to->cleanup) tw->to->cleanup(tw); if(tw->data != NULL) { free(tw->data); tw->data = NULL; } /* disassociate mqueue of tw and destroy it */ if(tw->to->listener || tw->to->sender) { pthreadex_mutex_begin(&(tw->mqueue->mutex)); TDBG2("[tea-cleanup] listener/sender cleanup"); mq = tw->mqueue; tw->mqueue = NULL; pthreadex_mutex_end(); if(mq) { TDBG2("[tea-cleanup] mqueue cleanup"); mqueue_destroy(mq); } } TDBG("[tea-cleanup] Thread finished."); pthreadex_flag_up(&(tw->cleanup_done)); }
/* * Execute elements. */ enum exec_rtn _tmpl_execute_elems(struct tmpl_ctx *ctx, struct tmpl_elem *const elems, int first_elem, int nelems) { #if TMPL_DEBUG char indent[80]; #endif enum exec_rtn rtn; int i; /* Increase nesting */ ctx->depth++; /* Check for infinite loop */ if (ctx->depth >= INFINITE_LOOP) { pr_err(ctx, 0, "too much recursion in template execution"); rtn = RTN_NORMAL; goto done; } /* Debug */ #if TMPL_DEBUG *indent = '\0'; for (i = 1; i < ctx->depth; i++) strlcat(indent, " ", sizeof(indent)); TDBG("%sExecuting %d elems starting at %d\n", indent _ nelems _ first_elem); #endif /* Execute elements in order */ for (i = first_elem; i < first_elem + nelems; i++) { struct tmpl_elem *const elem = &elems[i]; TDBG("%s%4d: %s\n", indent _ i _ _tmpl_elemstr(&elems[i] _ i)); /* Handle normal text */ if (elem->text != NULL) { /* Optionally skip initial NL + whitespace */ if (((elem->flags & TMPL_ELEM_NL_WHITE) != 0 && ctx->flags & TMPL_SKIP_NL_WHITE) != 0) continue; /* Output text */ fwrite(elem->text, 1, elem->len, ctx->output); continue; } /* Handle function call */ switch (elem->call.type) { case TY_NORMAL: { char *errmsg = NULL; char *result; if ((result = _tmpl_invoke(ctx, &errmsg, &elem->call)) == NULL) { pr_err(ctx, errno, errmsg); FREE(ctx->mtype, errmsg); break; } TDBG("%s --> \"%s\"\n", indent _ result); (void)fputs(result, ctx->output); FREE(ctx->mtype, result); break; } case TY_LOOP: { struct loop_ctx this; char *errmsg = NULL; long count; char *eptr; char *x; if (!(x = evaluate_arg(ctx, &errmsg, &elem->call.args[0]))) { pr_err(ctx, errno, errmsg); FREE(ctx->mtype, errmsg); i += elem->u.u_loop.endloop; break; } count = strtoul(x, &eptr, 10); if (*x == '\0' || *eptr != '\0' || count < 0 || count == LONG_MAX) { char buf[32]; snprintf(buf, sizeof(buf), "invalid loop count \"%s\"", x); pr_err(ctx, 0, buf); FREE(ctx->mtype, x); i += elem->u.u_loop.endloop; break; } FREE(ctx->mtype, x); this.outer = ctx->loop; ctx->loop = &this; for (this.index = 0; this.index < count; this.index++) { rtn = _tmpl_execute_elems(ctx, elems, i + 1, elem->u.u_loop.endloop - 1); if (rtn == RTN_BREAK) break; if (rtn == RTN_RETURN) { ctx->loop = this.outer; goto done; } } ctx->loop = this.outer; i += elem->u.u_loop.endloop; break; } case TY_WHILE: while (1) { char *errmsg = NULL; int truth; char *x; if (!(x = evaluate_arg(ctx, &errmsg, &elem->call.args[0]))) { pr_err(ctx, errno, errmsg); FREE(ctx->mtype, errmsg); i += elem->u.u_while.endwhile; break; } truth = _tmpl_true(x); FREE(ctx->mtype, x); if (!truth) break; rtn = _tmpl_execute_elems(ctx, elems, i + 1, elem->u.u_while.endwhile - 1); if (rtn == RTN_BREAK) break; if (rtn == RTN_RETURN) goto done; } i += elem->u.u_while.endwhile; break; case TY_IF: case TY_ELIF: { char *errmsg = NULL; int first = -1; int num = 0; int truth; char *x; if (!(x = evaluate_arg(ctx, &errmsg, &elem->call.args[0]))) { pr_err(ctx, errno, errmsg); FREE(ctx->mtype, errmsg); i += elem->u.u_if.endif; break; } truth = _tmpl_true(x); FREE(ctx->mtype, x); if (truth) { first = i + 1; num = (elem->u.u_if.elsie != -1) ? elem->u.u_if.elsie - 1 : elem->u.u_if.endif - 1; } else if (elem->u.u_if.elsie != -1) { first = i + elem->u.u_if.elsie; num = elem->u.u_if.endif - elem->u.u_if.elsie; } if (first != -1) { rtn = _tmpl_execute_elems(ctx, elems, first, num); if (rtn == RTN_BREAK || rtn == RTN_RETURN || rtn == RTN_CONTINUE) goto done; } i += elem->u.u_if.endif; break; } case TY_DEFINE: { char *errmsg = NULL; char *name; if (!(name = evaluate_arg(ctx, &errmsg, &elem->call.args[0]))) { pr_err(ctx, errno, errmsg); FREE(ctx->mtype, errmsg); i += elem->u.u_define.enddef; break; } #ifdef TMPL_DEBUG TDBG("%s%6sDefining function \"%s\" as %d elems" " starting at %d\n", indent _ "" _ name _ elem->u.u_define.enddef - 1 _ i + 1); #endif if (_tmpl_set_func(ctx, name, elems + i + 1, elem->u.u_define.enddef - 1) == -1) { pr_err(ctx, errno, NULL); FREE(ctx->mtype, name); i += elem->u.u_define.enddef; break; } FREE(ctx->mtype, name); i += elem->u.u_define.enddef; break; } case TY_ENDLOOP: case TY_ENDWHILE: case TY_ELSE: case TY_ENDIF: case TY_ENDDEF: break; case TY_BREAK: rtn = RTN_BREAK; goto done; case TY_CONTINUE: rtn = RTN_CONTINUE; goto done; case TY_RETURN: rtn = RTN_RETURN; goto done; default: assert(0); } } /* If we finished all the elements, that's a normal return */ rtn = RTN_NORMAL; done: /* Debug */ #if TMPL_DEBUG TDBG("%sDone, return is %s\n", indent _ tmpl_rtnstr(rtn)); #endif /* Decrease nesting */ ctx->depth--; /* Done */ return (rtn); }