[master] 70c9a26 Restructure 'process' a bit and teach it a few new tricks.
Poul-Henning Kamp
phk at FreeBSD.org
Wed Jan 10 12:44:12 UTC 2018
commit 70c9a26460d64eec7ffd60ba9fe4391b873a1fbb
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Wed Jan 10 12:39:47 2018 +0000
Restructure 'process' a bit and teach it a few new tricks.
diff --git a/bin/varnishtest/tests/a00017.vtc b/bin/varnishtest/tests/a00017.vtc
index b700305..21b184c 100644
--- a/bin/varnishtest/tests/a00017.vtc
+++ b/bin/varnishtest/tests/a00017.vtc
@@ -42,7 +42,7 @@ shell -exit 1 -expect "Command failed with error code 101" {
shell "varnishadm -n ${tmpdir}/v1 param.set cli_limit 128"
shell -expect "[response was truncated]" "varnishadm -n ${tmpdir}/v1 help"
-process p1 -stop -wait
+process p1 -expect-exit 64 -stop -wait
# Test multiple -f options
diff --git a/bin/varnishtest/tests/u00000.vtc b/bin/varnishtest/tests/u00000.vtc
index 3ed2eaf..8a0ab79 100644
--- a/bin/varnishtest/tests/u00000.vtc
+++ b/bin/varnishtest/tests/u00000.vtc
@@ -2,13 +2,15 @@ varnishtest "Simple process tests"
# new & start
process p1 "cat" -start
-process p2 "cat" -start
-process p3 "cat" -start
+process p2 -log "cat" -start
+process p3 -dump "cat" -start
+process p4 -hexdump "cat" -start
# write
process p1 -writeln "foo"
process p2 -writeln "bar"
process p3 -writeln "baz"
+process p4 -writeln "b\001z"
# give enough time for the writes
delay 0.5
@@ -17,11 +19,13 @@ delay 0.5
process p1 -stop
process p2 -close
process p3 -kill KILL
+process p4 -kill TERM
# wait
process p1 -wait
process p2 -wait
process p3 -wait
+process p4 -wait
# check stdout
shell "grep -q foo ${p1_out}"
diff --git a/bin/varnishtest/vtc_process.c b/bin/varnishtest/vtc_process.c
index e6d9ad1..0388f99 100644
--- a/bin/varnishtest/vtc_process.c
+++ b/bin/varnishtest/vtc_process.c
@@ -33,13 +33,17 @@
#include <errno.h>
#include <fcntl.h>
+#include <poll.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "vtc.h"
+
+#include "vev.h"
#include "vlu.h"
+#include "vsb.h"
#include "vsub.h"
struct process {
@@ -53,10 +57,17 @@ struct process {
char *dir;
char *out;
char *err;
- int fd_to;
+ int fd_stdin;
+ int fd_stdout;
+ int fd_stderr;
+ int f_stdout;
+ int f_stderr;
+ struct vlu *vlu_stdout;
+ struct vlu *vlu_stderr;
+ const char *cur_fd;
int log;
- int fd_from;
pid_t pid;
+ int expect_exit;
pthread_mutex_t mtx;
pthread_t tp;
@@ -103,8 +114,8 @@ process_new(const char *name)
p->dir, p->dir, p->out, p->err);
AZ(system(buf));
- p->fd_to = -1;
- p->fd_from = -1;
+ p->fd_stdin = -1;
+ p->fd_stdout = -1;
VTAILQ_INSERT_TAIL(&processes, p, list);
return (p);
@@ -158,7 +169,66 @@ process_vlu_func(void *priv, const char *l)
struct process *p;
CAST_OBJ_NOTNULL(p, priv, PROCESS_MAGIC);
- vtc_dump(p->vl, 4, "output", l, -1);
+ vtc_dump(p->vl, 4, p->cur_fd, l, -1);
+ return (0);
+}
+
+static int v_matchproto_(vev_cb_f)
+process_stdin(const struct vev *ev, int what)
+{
+ struct process *p;
+ CAST_OBJ_NOTNULL(p, ev->priv, PROCESS_MAGIC);
+ vtc_log(p->vl, 4, "stdin event 0x%x", what);
+ return (1);
+}
+
+static int v_matchproto_(vev_cb_f)
+process_stdout(const struct vev *ev, int what)
+{
+ struct process *p;
+ char buf[BUFSIZ];
+ int i;
+
+ CAST_OBJ_NOTNULL(p, ev->priv, PROCESS_MAGIC);
+ (void)what;
+ p->cur_fd = "stdout";
+ i = read(p->fd_stdout, buf, sizeof buf);
+ if (i <= 0) {
+ vtc_log(p->vl, 4, "stdout read %d", i);
+ return (1);
+ }
+ if (p->log == 1)
+ (void)VLU_Feed(p->vlu_stdout, buf, i);
+ else if (p->log == 2)
+ vtc_dump(p->vl, 4, "stdout", buf, i);
+ else if (p->log == 3)
+ vtc_hexdump(p->vl, 4, "stdout", buf, i);
+ (void)write(p->f_stdout, buf, i);
+ return (0);
+}
+
+static int v_matchproto_(vev_cb_f)
+process_stderr(const struct vev *ev, int what)
+{
+ struct process *p;
+ char buf[BUFSIZ];
+ int i;
+
+ CAST_OBJ_NOTNULL(p, ev->priv, PROCESS_MAGIC);
+ (void)what;
+ p->cur_fd = "stderr";
+ i = read(p->fd_stderr, buf, sizeof buf);
+ if (i <= 0) {
+ vtc_log(p->vl, 4, "stderr read %d", i);
+ return (1);
+ }
+ if (p->log == 1)
+ (void)VLU_Feed(p->vlu_stderr, buf, i);
+ else if (p->log == 2)
+ vtc_dump(p->vl, 4, "stderr", buf, i);
+ else if (p->log == 3)
+ vtc_hexdump(p->vl, 4, "stderr", buf, i);
+ (void)write(p->f_stderr, buf, i);
return (0);
}
@@ -167,17 +237,65 @@ process_thread(void *priv)
{
struct process *p;
struct rusage ru;
+ struct vev_root *evb;
+ struct vev *ev;
int r;
CAST_OBJ_NOTNULL(p, priv, PROCESS_MAGIC);
- if (p->fd_from > 0)
- (void)VLU_File(p->fd_from, process_vlu_func, p, 1024);
+
+ p->f_stdout = open(p->out, O_WRONLY|O_APPEND);
+ assert(p->f_stdout >= 0);
+ p->f_stderr = open(p->err, O_WRONLY|O_APPEND);
+ assert(p->f_stderr >= 0);
+
+ evb = VEV_New();
+ AN(evb);
+
+ ev = VEV_Alloc();
+ AN(ev);
+ ev->fd = p->fd_stdin;
+ ev->fd_flags = VEV__HUP | VEV__ERR;
+ ev->priv = p;
+ ev->callback = process_stdin;
+ AZ(VEV_Start(evb, ev));
+
+ ev = VEV_Alloc();
+ AN(ev);
+ ev->fd = p->fd_stdout;
+ ev->fd_flags = VEV__RD | VEV__HUP | VEV__ERR;
+ ev->callback = process_stdout;
+ ev->priv = p;
+ AZ(VEV_Start(evb, ev));
+
+ ev = VEV_Alloc();
+ AN(ev);
+ ev->fd = p->fd_stderr;
+ ev->fd_flags = VEV__RD | VEV__HUP | VEV__ERR;
+ ev->callback = process_stderr;
+ ev->priv = p;
+ AZ(VEV_Start(evb, ev));
+
+ if (p->log == 1) {
+ p->vlu_stdout = VLU_New(process_vlu_func, p, 1024);
+ AN(p->vlu_stdout);
+ p->vlu_stderr = VLU_New(process_vlu_func, p, 1024);
+ AN(p->vlu_stderr);
+ }
+
+ do {
+ r = VEV_Once(evb);
+ } while (r == 1);
+
+ if (r < 0)
+ vtc_fatal(p->vl, "VEV_Once() = %d, error %s", r,
+ strerror(errno));
+
r = wait4(p->pid, &p->status, 0, &ru);
- AZ(pthread_mutex_lock(&p->mtx));
+ closefd(&p->f_stdout);
+ closefd(&p->f_stderr);
- if (p->fd_to >= 0)
- closefd(&p->fd_to);
+ AZ(pthread_mutex_lock(&p->mtx));
/* NB: We keep the other macros around */
macro_undef(p->vl, p->name, "pid");
@@ -191,17 +309,23 @@ process_thread(void *priv)
AZ(pthread_mutex_unlock(&p->mtx));
- if (WIFEXITED(p->status) && WEXITSTATUS(p->status) == 0)
- return (NULL);
#ifdef WCOREDUMP
- vtc_log(p->vl, 2, "Bad exit code: %04x sig %d exit %d core %d",
+ vtc_log(p->vl, 2, "Exit code: %04x sig %d exit %d core %d",
p->status, WTERMSIG(p->status), WEXITSTATUS(p->status),
WCOREDUMP(p->status));
#else
- vtc_log(p->vl, 2, "Bad exit code: %04x sig %d exit %d",
+ vtc_log(p->vl, 2, "Exit code: %04x sig %d exit %d",
p->status, WTERMSIG(p->status), WEXITSTATUS(p->status));
#endif
-
+ if (WEXITSTATUS(p->status) != p->expect_exit)
+ vtc_fatal(p->vl, "Expected exit %d got %d",
+ p->expect_exit, WEXITSTATUS(p->status));
+
+ VEV_Destroy(&evb);
+ if (p->log == 1) {
+ VLU_Destroy(&p->vlu_stdout);
+ VLU_Destroy(&p->vlu_stderr);
+ }
return (NULL);
}
@@ -209,9 +333,7 @@ static void
process_start(struct process *p)
{
struct vsb *cl;
- int out_fd, err_fd;
- int fds[2];
- int fdt[2] = { -1, -1 };
+ int fd0[2], fd1[2], fd2[2];
CHECK_OBJ_NOTNULL(p, PROCESS_MAGIC);
if (p->hasthread)
@@ -221,44 +343,35 @@ process_start(struct process *p)
cl = macro_expand(p->vl, p->spec);
AN(cl);
- AZ(pipe(fds));
- if (p->log) {
- AZ(pipe(fdt));
- out_fd = fdt[1];
- err_fd = fdt[1];
- } else {
- out_fd = open(p->out, O_WRONLY|O_APPEND);
- assert(out_fd >= 0);
- err_fd = open(p->err, O_WRONLY|O_APPEND);
- assert(err_fd >= 0);
- }
+
+ AZ(pipe(fd0));
+ AZ(pipe(fd1));
+ AZ(pipe(fd2));
+
p->pid = fork();
assert(p->pid >= 0);
if (p->pid == 0) {
- assert(dup2(fds[0], 0) == 0);
- assert(dup2(out_fd, 1) == 1);
- assert(dup2(err_fd, 2) == 2);
+ assert(dup2(fd0[0], STDIN_FILENO) == STDIN_FILENO);
+ assert(dup2(fd1[1], STDOUT_FILENO) == STDOUT_FILENO);
+ assert(dup2(fd2[1], STDERR_FILENO) == STDERR_FILENO);
VSUB_closefrom(STDERR_FILENO + 1);
AZ(setpgid(0, 0));
- AZ(execl("/bin/sh", "/bin/sh", "-c", VSB_data(cl),
- (char *)NULL));
+ AZ(execl("/bin/sh", "/bin/sh", "-c", VSB_data(cl), NULL));
exit(1);
}
vtc_log(p->vl, 3, "PID: %ld", (long)p->pid);
+ VSB_destroy(&cl);
+
+ closefd(&fd0[0]);
+ closefd(&fd1[1]);
+ closefd(&fd2[1]);
+ p->fd_stdin = fd0[1];
+ p->fd_stdout = fd1[0];
+ p->fd_stderr = fd2[0];
macro_def(p->vl, p->name, "pid", "%ld", (long)p->pid);
macro_def(p->vl, p->name, "dir", "%s", p->dir);
macro_def(p->vl, p->name, "out", "%s", p->out);
macro_def(p->vl, p->name, "err", "%s", p->err);
- closefd(&fds[0]);
- p->fd_to = fds[1];
- if (p->log) {
- closefd(&fdt[1]);
- p->fd_from = fdt[0];
- } else {
- closefd(&out_fd);
- closefd(&err_fd);
- }
- VSB_destroy(&cl);
p->hasthread = 1;
AZ(pthread_create(&p->tp, NULL, process_thread, p));
}
@@ -330,7 +443,7 @@ process_write(const struct process *p, const char *text)
len = strlen(text);
vtc_log(p->vl, 4, "Writing %d bytes", len);
- r = write(p->fd_to, text, len);
+ r = write(p->fd_stdin, text, len);
if (r < 0)
vtc_fatal(p->vl, "Failed to write: %s (%d)",
strerror(errno), errno);
@@ -344,8 +457,8 @@ process_close(struct process *p)
vtc_fatal(p->vl, "Cannot close a non-running process");
AZ(pthread_mutex_lock(&p->mtx));
- if (p->fd_to >= 0)
- closefd(&p->fd_to);
+ if (p->fd_stdin >= 0)
+ closefd(&p->fd_stdin);
AZ(pthread_mutex_unlock(&p->mtx));
}
@@ -354,8 +467,10 @@ process_close(struct process *p)
* Run a process in the background with stdout and stderr redirected to
* ${pNAME_out} and ${pNAME_err}, both located in ${pNAME_dir}::
*
- * process pNAME SPEC [-log] [-start] [-wait] [-run] [-kill STRING] \
- * [-stop] [-write STRING] [-writeln STRING] [-close]
+ * process pNAME SPEC [-log] [-dump] [-hexdump] [-expect-exit N]
+ * [-start] [-run]
+ * [-write STRING] [-writeln STRING]
+ * [-kill STRING] [-stop] [-wait] [-close]
*
* pNAME
* Name of the process. It must start with 'p'.
@@ -363,12 +478,21 @@ process_close(struct process *p)
* SPEC
* The command(s) to run in this process.
*
- * \-log
+ * \-hexdump
+ * Log stdout/stderr with vtc_hexdump(). Must be before -start/-run.
+ *
+ * \-dump
* Log stdout/stderr with vtc_dump(). Must be before -start/-run.
*
+ * \-log
+ * Log stdout/stderr with VLU/vtc_log(). Must be before -start/-run.
+ *
* \-start
* Start the process.
*
+ * \-expect-exit N
+ * Expect exit status N
+ *
* \-wait
* Wait for the process to finish.
*
@@ -461,6 +585,20 @@ cmd_process(CMD_ARGS)
process_start(p);
continue;
}
+ if (!strcmp(*av, "-hexdump")) {
+ if (p->hasthread)
+ vtc_fatal(p->vl,
+ "Cannot dump a running process");
+ p->log = 3;
+ continue;
+ }
+ if (!strcmp(*av, "-dump")) {
+ if (p->hasthread)
+ vtc_fatal(p->vl,
+ "Cannot dump a running process");
+ p->log = 2;
+ continue;
+ }
if (!strcmp(*av, "-log")) {
if (p->hasthread)
vtc_fatal(p->vl,
@@ -468,6 +606,11 @@ cmd_process(CMD_ARGS)
p->log = 1;
continue;
}
+ if (!strcmp(*av, "-expect-exit")) {
+ p->expect_exit = strtoul(av[1], NULL, 0);
+ av++;
+ continue;
+ }
if (!strcmp(*av, "-wait")) {
process_wait(p);
continue;
More information about the varnish-commit
mailing list