static void job_error(child_process *cp, struct kvvec *kvv, const char *fmt, ...) { char msg[4096]; int len; va_list ap; int ret; va_start(ap, fmt); len = vsnprintf(msg, sizeof(msg) - 1, fmt, ap); va_end(ap); if (cp) { kvvec_addkv(kvv, "job_id", mkstr("%d", cp->id)); } kvvec_addkv_wlen(kvv, "error_msg", 9, msg, len); ret = worker_send_kvvec(master_sd, kvv); if (ret < 0 && errno == EPIPE) exit_worker(1, "Failed to send job error key/value vector to master"); kvvec_destroy(kvv, 0); }
static int finish_job(child_process *cp, int reason) { static struct kvvec resp = KVVEC_INITIALIZER; struct rusage *ru = &cp->rusage; int i, ret; /* how many key/value pairs do we need? */ if (kvvec_init(&resp, 12 + cp->request->kv_pairs) == NULL) { /* what the hell do we do now? */ exit_worker(); } gettimeofday(&cp->stop, NULL); if (running_jobs != squeue_size(sq)) { wlog("running_jobs(%d) != squeue_size(sq) (%d)\n", running_jobs, squeue_size(sq)); wlog("started: %d; running: %d; finished: %d\n", started, running_jobs, started - running_jobs); } /* * we must remove the job's timeout ticker, * or we'll end up accessing an already free()'d * pointer, or the pointer to a different child. */ squeue_remove(sq, cp->sq_event); /* get rid of still open filedescriptors */ if (cp->outstd.fd != -1) iobroker_close(iobs, cp->outstd.fd); if (cp->outerr.fd != -1) iobroker_close(iobs, cp->outerr.fd); cp->runtime = tv_delta_f(&cp->start, &cp->stop); /* * Now build the return message. * First comes the request, minus environment variables */ for (i = 0; i < cp->request->kv_pairs; i++) { struct key_value *kv = &cp->request->kv[i]; /* skip environment macros */ if (kv->key_len == 3 && !strcmp(kv->key, "env")) { continue; } kvvec_addkv_wlen(&resp, kv->key, kv->key_len, kv->value, kv->value_len); } kvvec_addkv(&resp, "wait_status", (char *)mkstr("%d", cp->ret)); kvvec_addkv_wlen(&resp, "outstd", 6, cp->outstd.buf, cp->outstd.len); kvvec_addkv_wlen(&resp, "outerr", 6, cp->outerr.buf, cp->outerr.len); kvvec_add_tv(&resp, "start", cp->start); kvvec_add_tv(&resp, "stop", cp->stop); kvvec_addkv(&resp, "runtime", (char *)mkstr("%f", cp->runtime)); if (!reason) { /* child exited nicely */ kvvec_addkv(&resp, "exited_ok", "1"); kvvec_add_tv(&resp, "ru_utime", ru->ru_utime); kvvec_add_tv(&resp, "ru_stime", ru->ru_stime); kvvec_add_long(&resp, "ru_minflt", ru->ru_minflt); kvvec_add_long(&resp, "ru_majflt", ru->ru_majflt); kvvec_add_long(&resp, "ru_nswap", ru->ru_nswap); kvvec_add_long(&resp, "ru_inblock", ru->ru_inblock); kvvec_add_long(&resp, "ru_oublock", ru->ru_oublock); kvvec_add_long(&resp, "ru_nsignals", ru->ru_nsignals); } else { /* some error happened */ kvvec_addkv(&resp, "exited_ok", "0"); kvvec_addkv(&resp, "error_code", (char *)mkstr("%d", reason)); } ret = send_kvvec(master_sd, &resp); if (ret < 0 && errno == EPIPE) exit_worker(); running_jobs--; if (cp->outstd.buf) { free(cp->outstd.buf); cp->outstd.buf = NULL; } if (cp->outerr.buf) { free(cp->outerr.buf); cp->outerr.buf = NULL; } kvvec_destroy(cp->request, KVVEC_FREE_ALL); free(cp->cmd); free(cp); return 0; }
int finish_job(child_process *cp, int reason) { static struct kvvec resp = KVVEC_INITIALIZER; struct rusage *ru = &cp->ei->rusage; int i, ret; /* get rid of still open filedescriptors */ if (cp->outstd.fd != -1) { gather_output(cp, &cp->outstd, 1); iobroker_close(iobs, cp->outstd.fd); } if (cp->outerr.fd != -1) { gather_output(cp, &cp->outerr, 1); iobroker_close(iobs, cp->outerr.fd); } /* Make sure network-supplied data doesn't contain nul bytes */ strip_nul_bytes(cp->outstd); strip_nul_bytes(cp->outerr); /* how many key/value pairs do we need? */ if (kvvec_init(&resp, 12 + cp->request->kv_pairs) == NULL) { /* what the hell do we do now? */ exit_worker(1, "Failed to init response key/value vector"); } gettimeofday(&cp->ei->stop, NULL); if (running_jobs != squeue_size(sq)) { wlog("running_jobs(%d) != squeue_size(sq) (%d)\n", running_jobs, squeue_size(sq)); wlog("started: %d; running: %d; finished: %d\n", started, running_jobs, started - running_jobs); } cp->ei->runtime = tv_delta_f(&cp->ei->start, &cp->ei->stop); /* * Now build the return message. * First comes the request, minus environment variables */ for (i = 0; i < cp->request->kv_pairs; i++) { struct key_value *kv = &cp->request->kv[i]; /* skip environment macros */ if (kv->key_len == 3 && !strcmp(kv->key, "env")) { continue; } kvvec_addkv_wlen(&resp, kv->key, kv->key_len, kv->value, kv->value_len); } kvvec_addkv(&resp, "wait_status", mkstr("%d", cp->ret)); kvvec_add_tv(&resp, "start", cp->ei->start); kvvec_add_tv(&resp, "stop", cp->ei->stop); kvvec_addkv(&resp, "runtime", mkstr("%f", cp->ei->runtime)); if (!reason) { /* child exited nicely (or with a signal, so check wait_status) */ kvvec_addkv(&resp, "exited_ok", "1"); kvvec_add_tv(&resp, "ru_utime", ru->ru_utime); kvvec_add_tv(&resp, "ru_stime", ru->ru_stime); kvvec_add_long(&resp, "ru_minflt", ru->ru_minflt); kvvec_add_long(&resp, "ru_majflt", ru->ru_majflt); kvvec_add_long(&resp, "ru_inblock", ru->ru_inblock); kvvec_add_long(&resp, "ru_oublock", ru->ru_oublock); } else { /* some error happened */ kvvec_addkv(&resp, "exited_ok", "0"); kvvec_addkv(&resp, "error_code", mkstr("%d", reason)); } kvvec_addkv_wlen(&resp, "outerr", 6, cp->outerr.buf, cp->outerr.len); kvvec_addkv_wlen(&resp, "outstd", 6, cp->outstd.buf, cp->outstd.len); ret = worker_send_kvvec(master_sd, &resp); if (ret < 0 && errno == EPIPE) exit_worker(1, "Failed to send kvvec struct to master"); return 0; }