#ifndef _PROTO_FD_H
#define _PROTO_FD_H
+#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
*/
int init_pollers();
+/*
+ * Some pollers may lose their connection after a fork(). It may be necessary
+ * to create initialize part of them again. Returns 0 in case of failure,
+ * otherwise 1. The fork() function may be NULL if unused. In case of error,
+ * the the current poller is destroyed and the caller is responsible for trying
+ * another one by calling init_pollers() again.
+ */
+int fork_poller();
+
+/*
+ * Lists the known pollers on <out>.
+ * Should be performed only before initialization.
+ */
+int list_pollers(FILE *out);
+
/*
* Runs the polling loop
*/
REGPRM2 void (*poll)(struct poller *p, int wait_time); /* the poller itself */
REGPRM1 int (*init)(struct poller *p); /* poller initialization */
REGPRM1 void (*term)(struct poller *p); /* termination of this poller */
+ REGPRM1 int (*test)(struct poller *p); /* pre-init check of the poller */
+ REGPRM1 int (*fork)(struct poller *p); /* post-fork re-opening */
const char *name; /* poller name */
int pref; /* try pollers with higher preference first */
};
p->pref = 0;
}
+/*
+ * Check that the poller works.
+ * Returns 1 if OK, otherwise 0.
+ */
+REGPRM1 static int epoll_test(struct poller *p)
+{
+ int fd;
+
+ fd = epoll_create(global.maxsock + 1);
+ if (fd < 0)
+ return 0;
+ close(fd);
+ return 1;
+}
+
/*
* The only exported function. Returns 1.
*/
p->pref = 300;
p->private = NULL;
+ p->test = epoll_test;
p->init = epoll_init;
p->term = epoll_term;
p->poll = epoll_poll;
p->pref = 0;
}
+/*
+ * Check that the poller works.
+ * Returns 1 if OK, otherwise 0.
+ */
+REGPRM1 static int kqueue_test(struct poller *p)
+{
+ int fd;
+
+ fd = kqueue();
+ if (fd < 0)
+ return 0;
+ close(fd);
+ return 1;
+}
+
+/*
+ * Recreate the kqueue file descriptor after a fork(). Returns 1 if OK,
+ * otherwise 0. Note that some pollers need to be reopened after a fork()
+ * (such as kqueue), and some others may fail to do so in a chroot.
+ */
+REGPRM1 static int kqueue_fork(struct poller *p)
+{
+ close(kqueue_fd);
+ kqueue_fd = kqueue();
+ if (kqueue_fd < 0)
+ return 0;
+ return 1;
+}
+
/*
* The only exported function. Returns 1.
*/
-//int kqueue_native_register(struct poller *p)
int kqueue_register(struct poller *p)
{
p->name = "kqueue";
p->pref = 300;
p->private = NULL;
+ p->test = kqueue_test;
p->init = kqueue_init;
p->term = kqueue_term;
p->poll = kqueue_poll;
+ p->fork = kqueue_fork;
p->is_set = __fd_is_set;
p->cond_s = p->set = __fd_set;
p->pref = 0;
}
+/*
+ * Check that the poller works.
+ * Returns 1 if OK, otherwise 0.
+ */
+REGPRM1 static int poll_test(struct poller *p)
+{
+ return 1;
+}
+
/*
* The only exported function. Returns 1.
*/
p->pref = 200;
p->private = NULL;
+ p->test = poll_test;
p->init = poll_init;
p->term = poll_term;
p->poll = poll_poll;
p->pref = 0;
}
+/*
+ * Check that the poller works.
+ * Returns 1 if OK, otherwise 0.
+ */
+REGPRM1 static int select_test(struct poller *p)
+{
+ return 1;
+}
+
/*
* The only exported function. Returns 1.
*/
p->pref = 150;
p->private = NULL;
+ p->test = select_test;
p->init = select_init;
p->term = select_term;
p->poll = select_poll;
*
*/
+#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
return 0;
}
+/*
+ * Lists the known pollers on <out>.
+ * Should be performed only before initialization.
+ */
+int list_pollers(FILE *out)
+{
+ int p;
+ int last, next;
+ int usable;
+ struct poller *bp;
+
+ fprintf(out, "Available polling systems :\n");
+
+ usable = 0;
+ bp = NULL;
+ last = next = -1;
+ while (1) {
+ for (p = 0; p < nbpollers; p++) {
+ if (!bp || (pollers[p].pref > bp->pref))
+ bp = &pollers[p];
+ if ((next < 0 || pollers[p].pref > next)
+ && (last < 0 || pollers[p].pref < last))
+ next = pollers[p].pref;
+ }
+
+ if (next == -1)
+ break;
+
+ for (p = 0; p < nbpollers; p++) {
+ if (pollers[p].pref == next) {
+ fprintf(out, " %10s : ", pollers[p].name);
+ if (pollers[p].pref == 0)
+ fprintf(out, "disabled, ");
+ else
+ fprintf(out, "pref=%3d, ", pollers[p].pref);
+ if (pollers[p].test(&pollers[p])) {
+ fprintf(out, " test result OK");
+ if (next > 0)
+ usable++;
+ } else
+ fprintf(out, " test result FAILED");
+ fprintf(out, "\n");
+ }
+ }
+ last = next;
+ next = -1;
+ };
+ fprintf(out, "Total: %d (%d usable), will use %s.\n", nbpollers, usable, bp ? bp->name : "none");
+ return 0;
+}
+
+/*
+ * Some pollers may lose their connection after a fork(). It may be necessary
+ * to create initialize part of them again. Returns 0 in case of failure,
+ * otherwise 1. The fork() function may be NULL if unused. In case of error,
+ * the the current poller is destroyed and the caller is responsible for trying
+ * another one by calling init_pollers() again.
+ */
+int fork_poller()
+{
+ if (cur_poller.fork) {
+ if (cur_poller.fork(&cur_poller))
+ return 1;
+ cur_poller.term(&cur_poller);
+ return 0;
+ }
+ return 1;
+}
+
/*
* Local variables:
* c-indent-level: 8
/* Note: we could disable any poller by name here */
+ if (global.mode & (MODE_VERBOSE|MODE_DEBUG))
+ list_pollers(stderr);
+
if (!init_pollers()) {
- Alert("No polling mechanism available\n");
+ Alert("No polling mechanism available.\n");
exit(1);
}
- if (global.mode & MODE_DEBUG) {
- printf("Note: using %s() as the polling mechanism.\n", cur_poller.name);
+ if (global.mode & (MODE_VERBOSE|MODE_DEBUG)) {
+ printf("Using %s() as the polling mechanism.\n", cur_poller.name);
}
}
}
pid = getpid(); /* update child's pid */
setsid();
+ fork_poller();
}
/*
/*
- * this function starts all the proxies. Its return value is composed from
- * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
- * if <verbose> is not zero.
+ * This function creates all proxy sockets. It should be done very early,
+ * typically before privileges are dropped. The sockets will be registered
+ * but not added to any fd_set, in order not to loose them across the fork().
+ * The proxies also start in IDLE state, meaning that it will be
+ * maintain_proxies that will finally complete their loading.
+ *
+ * Its return value is composed from ERR_NONE, ERR_RETRYABLE and ERR_FATAL.
+ * Retryable errors will only be printed if <verbose> is not zero.
*/
int start_proxies(int verbose)
{
fdtab[fd].cb[DIR_RD].b = fdtab[fd].cb[DIR_WR].b = NULL;
fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
fdtab[fd].state = FD_STLISTEN;
- EV_FD_SET(fd, DIR_RD);
fd_insert(fd);
listeners++;
}
if (!pxerr) {
- curproxy->state = PR_STRUN;
+ curproxy->state = PR_STIDLE;
send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
}
}