#include <unistd.h>
#include <stdio.h>
+#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <assert.h>
#include <errno.h>
#include <poll.h>
-#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "mgt.h"
#include "cli_priv.h"
#include "mgt_cli.h"
+#include "mgt_event.h"
pid_t mgt_pid;
pid_t child_pid = -1;
static int child_fds[2];
static unsigned child_should_run;
-static pthread_t child_listen_thread;
-static pthread_t child_poker_thread;
-static pthread_mutex_t child_mtx;
-static pthread_cond_t child_cv;
static unsigned child_ticker;
-static unsigned gotint;
static unsigned dstarts;
+struct evbase *mgt_evb;
+
/*--------------------------------------------------------------------*/
-static void *
-child_listener(void *arg)
+static int
+child_listener(struct ev *e, int what)
{
int i;
char buf[BUFSIZ];
- (void)arg;
-
- while (1) {
- i = read(child_fds[0], buf, sizeof buf - 1);
- if (i <= 0)
- break;
- buf[i] = '\0';
- printf("Child said: %s", buf);
- }
- return (NULL);
+ (void)e;
+ if ((what & ~EV_RD))
+ return (1);
+ i = read(child_fds[0], buf, sizeof buf - 1);
+ if (i <= 0)
+ return (1);
+ buf[i] = '\0';
+ printf("Child said: <<%s>>\n", buf);
+ return (0);
}
/*--------------------------------------------------------------------*/
-static void *
-child_poker(void *arg)
+static int
+child_poker(struct ev *e, int what)
{
- (void)arg;
- while (1) {
- sleep (1);
- if (!mgt_cli_askchild(NULL, NULL, "ping\n"))
- child_ticker = 0;
- }
+ (void)e;
+ (void)what;
+ if (!child_should_run)
+ return (1);
+ if (child_pid > 0 && mgt_cli_askchild(NULL, NULL, "ping\n"))
+ kill(child_pid, SIGKILL);
+ return (0);
}
/*--------------------------------------------------------------------*/
{
int i;
char *p;
+ struct ev *e;
+
+ if (child_pid >= 0)
+ return;
+
+ child_should_run = 1;
AZ(pipe(&heritage.fds[0]));
AZ(pipe(&heritage.fds[2]));
AZ(close(heritage.fds[3]));
setproctitle("Varnish-Chld");
+
+ signal(SIGINT, SIG_DFL);
child_main();
exit (1);
AZ(close(child_fds[1]));
child_fds[1] = -1;
+ e = ev_new();
+ assert(e != NULL);
+ e->fd = child_fds[0];
+ e->fd_flags = EV_RD;
+ e->name = "Child listener";
+ e->callback = child_listener;
+ AZ(ev_add(mgt_evb, e));
+
+ e = ev_new();
+ assert(e != NULL);
+ e->timeout = 3.0;
+ e->callback = child_poker;
+ e->name = "child poker";
+ AZ(ev_add(mgt_evb, e));
+
+
mgt_cli_start_child(heritage.fds[0], heritage.fds[3]);
AZ(close(heritage.fds[1]));
heritage.fds[1] = -1;
AZ(close(heritage.fds[2]));
heritage.fds[2] = -1;
child_pid = i;
- AZ(pthread_create(&child_listen_thread, NULL, child_listener, NULL));
- AZ(pthread_detach(child_listen_thread));
- AZ(pthread_create(&child_poker_thread, NULL, child_poker, NULL));
- AZ(pthread_detach(child_poker_thread));
if (mgt_push_vcls_and_start(&i, &p)) {
fprintf(stderr, "Pushing vcls failed:\n%s\n", p);
free(p);
static void
stop_child(void)
{
- int i;
- assert(child_pid != -1);
+ if (child_pid < 0)
+ return;
+
+ child_should_run = 0;
- printf("Stop child\n");
- AZ(pthread_cancel(child_poker_thread));
+ printf("Clean child\n");
mgt_cli_stop_child();
/* We tell the child to die gracefully by closing the CLI */
AZ(close(heritage.fds[3]));
heritage.fds[3] = -1;
- /*
- * Give it one second to die, then wack it hard
- * then another second and then we get real angry
- */
- for (i = 0; i < 30; i++) {
- printf("Waiting %d %d\n",i, child_pid);
- if (child_pid == -2)
- break;
- if (i == 10) {
- printf("Giving cacher SIGINT\n");
- kill(child_pid, SIGINT);
- }
- if (i == 20) {
- printf("Giving cacher SIGKILL\n");
- kill(child_pid, SIGKILL);
- }
- usleep(100000);
- }
-
- assert(child_pid == -2);
-
- AZ(close(child_fds[0]));
- child_fds[0] = -1;
- child_pid = -1;
printf("Child stopped\n");
}
/*--------------------------------------------------------------------*/
-static void
-mgt_sigchld(int arg)
+static int
+mgt_sigchld(struct ev *e, int what)
{
int status;
pid_t r;
- (void)arg;
+ (void)e;
+ (void)what;
r = wait4(-1, &status, WNOHANG, NULL);
- if (r == child_pid) {
- printf("Cache child died pid=%d status=0x%x\n",
- r, status);
- child_pid = -2;
- } else {
+ if (r != child_pid) {
printf("Unknown child died pid=%d status=0x%x\n",
r, status);
+ return (0);
}
+ printf("Cache child died pid=%d status=0x%x\n", r, status);
+ child_pid = -1;
+
+ if (child_should_run) {
+ printf("Clean child\n");
+ mgt_cli_stop_child();
+
+ /* We tell the child to die gracefully by closing the CLI */
+ AZ(close(heritage.fds[0]));
+ heritage.fds[0] = -1;
+ AZ(close(heritage.fds[3]));
+ heritage.fds[3] = -1;
+ }
+
+ AZ(close(child_fds[0]));
+ child_fds[0] = -1;
+ printf("Child cleaned\n");
+
+ if (child_should_run)
+ start_child();
+ return (0);
}
/*--------------------------------------------------------------------*/
-static void
-mgt_sigint(int arg)
+static int
+mgt_sigint(struct ev *e, int what)
{
- (void)arg;
- if (getpid() != mgt_pid) {
- printf("Got SIGINT\n");
- exit (2);
- }
+ (void)e;
+ (void)what;
printf("Manager got SIGINT\n");
- gotint = 1;
- child_should_run = 0;
+ fflush(stdout);
+ if (child_pid >= 0)
+ stop_child();
+ exit (2);
}
/*--------------------------------------------------------------------
void
mgt_run(int dflag)
{
- struct timespec to;
struct sigaction sac;
- int i;
+ struct ev *ev_sigchld, *ev_sigint;
mgt_pid = getpid();
+ mgt_evb = ev_new_base();
+ assert(mgt_evb != NULL);
+
if (dflag)
mgt_cli_setup(0, 1, 1);
- sac.sa_handler = mgt_sigchld;
- sac.sa_flags = SA_RESTART | SA_NOCLDSTOP;
- AZ(sigaction(SIGCHLD, &sac, NULL));
+ ev_sigint = ev_new();
+ assert(ev_sigint != NULL);
+ ev_sigint->sig = SIGINT;
+ ev_sigint->callback = mgt_sigint;
+ ev_sigint->name = "mgt_sigint";
+ AZ(ev_add(mgt_evb, ev_sigint));
- sac.sa_handler = mgt_sigint;
- sac.sa_flags = SA_RESTART;
- AZ(sigaction(SIGINT, &sac, NULL));
- AZ(sigaction(SIGTERM, &sac, NULL));
+ ev_sigchld = ev_new();
+ ev_sigchld->sig = SIGCHLD;
+ ev_sigchld->sig_flags = SA_NOCLDSTOP;
+ ev_sigchld->callback = mgt_sigchld;
+ ev_sigchld->name = "mgt_sigchild";
+ AZ(ev_add(mgt_evb, ev_sigchld));
setproctitle("Varnish-Mgr");
AZ(sigaction(SIGPIPE, &sac, NULL));
AZ(sigaction(SIGHUP, &sac, NULL));
- child_should_run = !dflag;
-
- AZ(pthread_cond_init(&child_cv, NULL));
- AZ(pthread_mutex_init(&child_mtx, NULL));
-
- while (1) {
- if (child_should_run && child_pid == -2)
- stop_child();
- if (!child_should_run && child_pid != -1)
- stop_child();
- if (gotint) {
- printf("Manager died due to sigint\n");
- exit(2);
- }
- if (child_should_run && child_pid == -1) {
- if (dflag && dstarts) {
- printf(
- "Manager not autostarting in debug mode\n");
- exit(2);
- }
- start_child();
- dstarts = 1;
- }
-
- /* XXX POSIXBRAINDAMAGE */
- AZ(clock_gettime(CLOCK_REALTIME, &to));
- to.tv_sec += 1;
-
- AZ(pthread_mutex_lock(&child_mtx));
- i = pthread_cond_timedwait(&child_cv, &child_mtx, &to);
- AZ(pthread_mutex_unlock(&child_mtx));
- if (i == ETIMEDOUT && ++child_ticker > 5 && child_pid != -1) {
- stop_child();
- if (dflag)
- exit (2);
- }
- }
+ printf("rolling...\n");
+ if (!dflag)
+ start_child();
+
+ ev_schedule(mgt_evb);
+
+ printf("manager dies\n");
+ exit(2);
}
/*--------------------------------------------------------------------*/
(void)cli;
(void)av;
if (priv != NULL) {
- child_should_run = 0;
- AZ(pthread_cond_signal(&child_cv));
+ stop_child();
return;
}
dstarts = 0;
- child_should_run = 1;
- AZ(pthread_cond_signal(&child_cv));
+ start_child();
}
#include <string.h>
#include <unistd.h>
#include <stdarg.h>
-#include <pthread.h>
#include <sys/types.h>
#include "libvarnish.h"
#include "common_cli.h"
#include "mgt.h"
#include "mgt_cli.h"
+#include "mgt_event.h"
#include "shmlog.h"
static int cli_i = -1, cli_o = -1;
-static pthread_mutex_t cli_mtx;
/*--------------------------------------------------------------------*/
(void)priv;
- AZ(pthread_mutex_lock(&cli_mtx));
-
/* Request */
if (cli_o <= 0) {
- AZ(pthread_mutex_unlock(&cli_mtx));
cli_result(cli, CLIS_CANT);
cli_out(cli, "Cache process not running");
return;
cli_out(cli, "%s", p);
free(p);
- AZ(pthread_mutex_unlock(&cli_mtx));
}
/*--------------------------------------------------------------------*/
unsigned u, v;
- AZ(pthread_mutex_init(&cli_mtx, NULL));
/*
* Build the joint cli_proto by combining the manager process
* entries with with the cache process entries. The latter
va_end(ap);
if (i < 0)
return (i);
- AZ(pthread_mutex_lock(&cli_mtx));
assert(p[i - 1] == '\n');
i = write(cli_o, p, strlen(p));
assert(i == strlen(p));
free(p);
i = cli_readres(cli_i, &j, resp);
- AZ(pthread_mutex_unlock(&cli_mtx));
if (status != NULL)
*status = j;
return (j == CLIS_OK ? 0 : j);
/*--------------------------------------------------------------------*/
struct cli_port {
+ unsigned magic;
+#define CLI_PORT_MAGIC 0x5791079f
+ struct ev *ev;
int fdi;
int fdo;
int verbose;
unsigned nbuf;
unsigned lbuf;
struct cli cli[1];
+ char name[30];
};
-static void *
-mgt_cli_main(void *arg)
+static int
+mgt_cli_callback(struct ev *e, unsigned what)
{
struct cli_port *cp;
char *p;
int i;
- assert(arg != NULL);
- cp = arg;
+ CAST_OBJ_NOTNULL(cp, e->priv, CLI_PORT_MAGIC);
- cp->lbuf = 4096;
- cp->buf = malloc(cp->lbuf);
- assert(cp->buf != NULL);
- cp->cli->sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
- assert(cp->cli->sb != NULL);
- while (1) {
+ while (!(what & (EV_ERR | EV_HUP))) {
if (cp->nbuf == cp->lbuf) {
cp->lbuf += cp->lbuf;
cp->buf = realloc(cp->buf, cp->lbuf);
cp->nbuf += i;
p = strchr(cp->buf, '\n');
if (p == NULL)
- continue;
+ return (0);
*p = '\0';
sbuf_clear(cp->cli->sb);
cli_dispatch(cp->cli, cli_proto, cp->buf);
if (i < cp->nbuf)
memcpy(cp->buf, p, cp->nbuf - i);
cp->nbuf -= i;
+ return (0);
}
sbuf_delete(cp->cli->sb);
free(cp->buf);
close(cp->fdi);
close(cp->fdo);
free(cp);
- return (NULL);
+ return (1);
}
void
mgt_cli_setup(int fdi, int fdo, int verbose)
{
struct cli_port *cp;
- pthread_t tp;
cp = calloc(sizeof *cp, 1);
assert(cp != NULL);
+ sprintf(cp->name, "cli %d->%d", fdi, fdo);
+ cp->magic = CLI_PORT_MAGIC;
+
cp->fdi = fdi;
cp->fdo = fdo;
cp->verbose = verbose;
- AZ(pthread_create(&tp, NULL, mgt_cli_main, cp));
- AZ(pthread_detach(tp));
-}
-
-#if 0
-
-/*--------------------------------------------------------------------
- * Generic passthrough for CLI functions
- */
-
-static void
-cli_passthrough_cb(unsigned u, const char *r, void *priv)
-{
- struct cli *cli = priv;
-
- cli_out(cli, "%s\n", r);
- cli_result(cli, u);
- cli_resume(cli);
-}
-
-static void
-m_cli_func_passthrough(struct cli *cli, char **av, void *priv)
-{
-
- (void)av;
- (void)priv;
-
- cli_suspend(cli);
- mgt_child_request(cli_passthrough_cb, cli, &av[2], av[1]);
-}
-
-static void
-m_cli_func_config_inline(struct cli *cli, char **av, void *priv)
-{
- char *vf;
- struct sbuf *sb;
-
- (void)priv;
-
- sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
- assert(sb != NULL);
- vf = VCC_Compile(sb, av[3], NULL);
- sbuf_finish(sb);
- if (sbuf_len(sb) > 0) {
- cli_out(cli, "%s", sbuf_data(sb));
- sbuf_delete(sb);
- return;
- }
- sbuf_delete(sb);
- cli_suspend(cli);
- mgt_child_request(cli_passthrough_cb, cli, NULL,
- "config.load %s %s", av[2], vf);
-}
-
-/* XXX: m prefix to avoid name clash */
-static void
-m_cli_func_config_load(struct cli *cli, char **av, void *priv)
-{
- char *vf;
- struct sbuf *sb;
- (void)priv;
-
- sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
- assert(sb != NULL);
- vf = VCC_CompileFile(sb, av[3]);
- sbuf_finish(sb);
- if (sbuf_len(sb) > 0) {
- cli_out(cli, "%s", sbuf_data(sb));
- sbuf_delete(sb);
- return;
- }
- sbuf_delete(sb);
- cli_suspend(cli);
- mgt_child_request(cli_passthrough_cb, cli, NULL,
- "config.load %s %s", av[2], vf);
-}
-
-static char *
-vcl_file(const char *fflag)
-{
- char *vf;
- struct sbuf *sb;
-
- sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
- assert(sb != NULL);
- vf = VCC_CompileFile(sb, fflag);
- sbuf_finish(sb);
- if (sbuf_len(sb) > 0) {
- fprintf(stderr, "%s", sbuf_data(sb));
- sbuf_delete(sb);
- return (NULL);
- }
- sbuf_delete(sb);
- return (vf);
-}
-
-
-/*--------------------------------------------------------------------*/
-
-static void
-m_cli_func_server_start(struct cli *cli, char **av, void *priv)
-{
-
- (void)cli;
- (void)av;
- (void)priv;
-
- mgt_child_start();
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-m_cli_func_server_stop(struct cli *cli, char **av, void *priv)
-{
-
- (void)cli;
- (void)av;
- (void)priv;
-
- mgt_child_stop();
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-m_cli_func_exit(struct cli *cli, char **av, void *priv)
-{
-
- (void)cli;
- (void)av;
- (void)priv;
- mgt_child_kill();
- exit (0);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-m_cli_func_verbose(struct cli *cli, char **av, void *priv)
-{
-
- (void)av;
- (void)priv;
-
- cli->verbose = !cli->verbose;
-}
-
-
-static void
-m_cli_func_ping(struct cli *cli, char **av, void *priv)
-{
- time_t t;
-
- (void)priv;
-
- if (av[2] != NULL) {
- cli_out(cli, "Got your %s\n", av[2]);
- }
- t = time(NULL);
- cli_out(cli, "PONG %ld\n", t);
-}
-
-/*--------------------------------------------------------------------*/
-
-static void
-m_cli_func_stats(struct cli *cli, char **av, void *priv)
-{
-
- (void)av;
- (void)priv;
-
- assert (VSL_stats != NULL);
-#define MAC_STAT(n,t,f,d) \
- cli_out(cli, "%12ju " d "\n", (VSL_stats->n));
-#include "stat_field.h"
-#undef MAC_STAT
-}
-
-/*--------------------------------------------------------------------*/
-
-
-/*--------------------------------------------------------------------*/
-
-/* for development purposes */
-#include <printf.h>
-
-int
-main(int argc, char *argv[])
-{
- int o;
- const char *portnumber = "8080";
- unsigned dflag = 0;
- const char *bflag = NULL;
- const char *fflag = NULL;
- const char *sflag = "file";
- const char *hflag = "classic";
-
- (void)register_printf_render_std((const unsigned char *)"HVQ");
-
- setbuf(stdout, NULL);
- setbuf(stderr, NULL);
-
- VCC_InitCompile(default_vcl);
-
- heritage.default_ttl = 120;
- heritage.wthread_min = 1;
- heritage.wthread_max = UINT_MAX;
- heritage.wthread_timeout = 10;
- heritage.mem_workspace = 4096;
-
- while ((o = getopt(argc, argv, "b:df:h:p:s:t:w:")) != -1)
- switch (o) {
- case 'b':
- bflag = optarg;
- break;
- case 'd':
- dflag++;
- break;
- case 'f':
- fflag = optarg;
- break;
- case 'h':
- hflag = optarg;
- break;
- case 'p':
- portnumber = optarg;
- break;
- case 's':
- sflag = optarg;
- break;
- case 't':
- heritage.default_ttl = strtoul(optarg, NULL, 0);
- break;
- case 'w':
- tackle_warg(optarg);
- break;
- default:
- usage();
- }
-
- argc -= optind;
- argv += optind;
-
- if (argc != 0) {
- fprintf(stderr, "Too many arguments\n");
- usage();
- }
-
- if (bflag != NULL && fflag != NULL) {
- fprintf(stderr, "Only one of -b or -f can be specified\n");
- usage();
- }
- if (bflag == NULL && fflag == NULL) {
- fprintf(stderr, "One of -b or -f must be specified\n");
- usage();
- }
-
- if (bflag != NULL)
- heritage.vcl_file = vcl_default(bflag);
- else
- heritage.vcl_file = vcl_file(fflag);
- if (heritage.vcl_file == NULL)
- exit (1);
-
- setup_storage(sflag);
- setup_hash(hflag);
-
- /*
- * XXX: Lacking the suspend/resume facility (due to the socket API
- * missing an unlisten(2) facility) we may want to push this into
- * the child to limit the amount of time where the socket(s) exists
- * but do not answer. That, on the other hand, would eliminate the
- * possibility of doing a "no-glitch" restart of the child process.
- */
- open_tcp(portnumber);
-
- VSL_MgtInit(SHMLOG_FILENAME, 8*1024*1024);
-
- if (dflag)
- DebugStunt();
- daemon(dflag, dflag);
- if (dflag)
- printf("%d\n%d\n%d\n", getpid(), getsid(0), getpgrp());
-
- {
- struct event e_sigchld;
- struct cli *cli;
- int i;
-
- mgt_eb = event_init();
- assert(mgt_eb != NULL);
-
- if (dflag)
- cli = cli_setup(mgt_eb, 0, 1, 1, cli_proto);
-
- signal_set(&e_sigchld, SIGCHLD, mgt_sigchld, NULL);
- AZ(event_base_set(mgt_eb, &e_sigchld));
- AZ(signal_add(&e_sigchld, NULL));
-
- mgt_child_start();
-
- i = event_base_loop(mgt_eb, 0);
- if (i != 0)
- printf("event_dispatch() = %d\n", i);
+ cp->lbuf = 4096;
+ cp->buf = malloc(cp->lbuf);
+ assert(cp->buf != NULL);
- }
+ cp->cli->sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
+ assert(cp->cli->sb != NULL);
- exit(0);
+ cp->ev = calloc(sizeof *cp->ev, 1);
+ cp->ev->name = cp->name;
+ cp->ev->fd = fdi;
+ cp->ev->fd_flags = EV_RD;
+ cp->ev->callback = mgt_cli_callback;
+ cp->ev->priv = cp;
+ ev_add(mgt_evb, cp->ev);
}
-#endif
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
-#include <pthread.h>
#include <sys/types.h>
#include "sbuf.h"
static TAILQ_HEAD(, vcls) vclhead = TAILQ_HEAD_INITIALIZER(vclhead);
-static pthread_mutex_t vcc_mtx;
-
/*--------------------------------------------------------------------*/
static const char *default_vcl =
assert(vp != NULL);
vp->name = strdup(name);
vp->fname = file;
- AZ(pthread_mutex_lock(&vcc_mtx));
TAILQ_INSERT_TAIL(&vclhead, vp, list);
- AZ(pthread_mutex_unlock(&vcc_mtx));
return (vp);
}
{
struct vcls *vp;
- AZ(pthread_mutex_lock(&vcc_mtx));
TAILQ_FOREACH(vp, &vclhead, list) {
if (mgt_cli_askchild(status, p,
"config.load %s %s\n", vp->name, vp->fname))
"config.use %s\n", vp->name, vp->fname))
return (1);
}
- AZ(pthread_mutex_unlock(&vcc_mtx));
if (mgt_cli_askchild(status, p, "start\n"))
return (1);
return (0);
if (getpid() != mgt_pid)
return;
- AZ(pthread_mutex_lock(&vcc_mtx));
while (1) {
vp = TAILQ_FIRST(&vclhead);
if (vp == NULL)
break;
mgt_vcc_del(vp);
}
- AZ(pthread_mutex_unlock(&vcc_mtx));
}
void
mgt_vcc_init(void)
{
- AZ(pthread_mutex_init(&vcc_mtx, NULL));
VCC_InitCompile(default_vcl);
AZ(atexit(mgt_vcc_atexit));
}
struct vcls *vp;
(void)priv;
- AZ(pthread_mutex_lock(&vcc_mtx));
vp = mcf_find_vcl(cli, av[2]);
if (vp != NULL && vp->active == 0) {
if (mgt_cli_askchild(&status, &p, "config.use %s\n", av[2])) {
}
}
}
- AZ(pthread_mutex_unlock(&vcc_mtx));
}
void
struct vcls *vp;
(void)priv;
- AZ(pthread_mutex_lock(&vcc_mtx));
vp = mcf_find_vcl(cli, av[2]);
if (vp != NULL && vp->active) {
cli_result(cli, CLIS_PARAM);
AZ(mgt_vcc_delbyname(av[2]));
}
}
- AZ(pthread_mutex_unlock(&vcc_mtx));
}
void
cli_out(cli, "%s", p);
free(p);
} else {
- AZ(pthread_mutex_lock(&vcc_mtx));
TAILQ_FOREACH(vp, &vclhead, list) {
cli_out(cli, "%s %6s %s\n",
vp->active ? "*" : " ",
"N/A", vp->name);
}
- AZ(pthread_mutex_unlock(&vcc_mtx));
}
}