From: Willy Tarreau Date: Sun, 15 Apr 2007 22:25:25 +0000 (+0200) Subject: [MAJOR] auto-registering of pollers at load time X-Git-Tag: v1.3.9~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ef1d1f859b3a9599c6b134ef5996c7851503739d;p=thirdparty%2Fhaproxy.git [MAJOR] auto-registering of pollers at load time Gcc provides __attribute__((constructor)) which is very convenient to execute functions at startup right before main(). All the pollers have been converted to have their register() function declared like this, so that it is not necessary anymore to call them from a centralized file. --- diff --git a/include/proto/fd.h b/include/proto/fd.h index 72b2c6be84..287c8bd80a 100644 --- a/include/proto/fd.h +++ b/include/proto/fd.h @@ -35,15 +35,13 @@ */ void fd_delete(int fd); -/* registers all known pollers */ -void register_pollers(); - /* disable the specified poller */ void disable_poller(const char *poller_name); /* * Initialize the pollers till the best one is found. * If none works, returns 0, otherwise 1. + * The pollers register themselves just before main() is called. */ int init_pollers(); diff --git a/src/ev_epoll.c b/src/ev_epoll.c index 403e71c3c6..b4844998ad 100644 --- a/src/ev_epoll.c +++ b/src/ev_epoll.c @@ -220,7 +220,7 @@ REGPRM1 static void __fd_clo(int fd) /* * epoll() poller */ -REGPRM2 static void epoll_poll(struct poller *p, int wait_time) +REGPRM2 static void _do_poll(struct poller *p, int wait_time) { int status; int fd; @@ -257,7 +257,7 @@ REGPRM2 static void epoll_poll(struct poller *p, int wait_time) * Returns 0 in case of failure, non-zero in case of success. If it fails, it * disables the poller by setting its pref to 0. */ -REGPRM1 static int epoll_init(struct poller *p) +REGPRM1 static int _do_init(struct poller *p) { __label__ fail_chg_ptr, fail_chg_list, fail_fdevt, fail_ee, fail_fd; int fd_set_bytes; @@ -306,7 +306,7 @@ REGPRM1 static int epoll_init(struct poller *p) * Termination of the epoll() poller. * Memory is released and the poller is marked as unselectable. */ -REGPRM1 static void epoll_term(struct poller *p) +REGPRM1 static void _do_term(struct poller *p) { fd_flush_changes(); @@ -335,7 +335,7 @@ REGPRM1 static void epoll_term(struct poller *p) * Check that the poller works. * Returns 1 if OK, otherwise 0. */ -REGPRM1 static int epoll_test(struct poller *p) +REGPRM1 static int _do_test(struct poller *p) { int fd; @@ -347,26 +347,33 @@ REGPRM1 static int epoll_test(struct poller *p) } /* - * The only exported function. Returns 1. + * It is a constructor, which means that it will automatically be called before + * main(). This is GCC-specific but it works at least since 2.95. + * Special care must be taken so that it does not need any uninitialized data. */ -int epoll_register(struct poller *p) +__attribute__((constructor)) +static void _do_register(void) { + struct poller *p; + + if (nbpollers >= MAX_POLLERS) + return; + p = &pollers[nbpollers++]; + p->name = "epoll"; p->pref = 300; p->private = NULL; - p->test = epoll_test; - p->init = epoll_init; - p->term = epoll_term; - p->poll = epoll_poll; + p->test = _do_test; + p->init = _do_init; + p->term = _do_term; + p->poll = _do_poll; p->is_set = __fd_is_set; p->cond_s = p->set = __fd_set; p->cond_c = p->clr = __fd_clr; p->rem = __fd_rem; p->clo = __fd_clo; - - return 1; } diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c index dd990e4706..55419f6f02 100644 --- a/src/ev_kqueue.c +++ b/src/ev_kqueue.c @@ -98,7 +98,7 @@ REGPRM1 static void __fd_clo(int fd) /* * kqueue() poller */ -REGPRM2 static void kqueue_poll(struct poller *p, int wait_time) +REGPRM2 static void _do_poll(struct poller *p, int wait_time) { int status; int count, fd; @@ -142,7 +142,7 @@ REGPRM2 static void kqueue_poll(struct poller *p, int wait_time) * Returns 0 in case of failure, non-zero in case of success. If it fails, it * disables the poller by setting its pref to 0. */ -REGPRM1 static int kqueue_init(struct poller *p) +REGPRM1 static int _do_init(struct poller *p) { __label__ fail_wevt, fail_revt, fail_fd; int fd_set_bytes; @@ -183,7 +183,7 @@ REGPRM1 static int kqueue_init(struct poller *p) * Termination of the kqueue() poller. * Memory is released and the poller is marked as unselectable. */ -REGPRM1 static void kqueue_term(struct poller *p) +REGPRM1 static void _do_term(struct poller *p) { if (fd_evts[DIR_WR]) free(fd_evts[DIR_WR]); @@ -202,7 +202,7 @@ REGPRM1 static void kqueue_term(struct poller *p) * Check that the poller works. * Returns 1 if OK, otherwise 0. */ -REGPRM1 static int kqueue_test(struct poller *p) +REGPRM1 static int _do_test(struct poller *p) { int fd; @@ -218,7 +218,7 @@ REGPRM1 static int kqueue_test(struct poller *p) * 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) +REGPRM1 static int _do_fork(struct poller *p) { close(kqueue_fd); kqueue_fd = kqueue(); @@ -228,27 +228,34 @@ REGPRM1 static int kqueue_fork(struct poller *p) } /* - * The only exported function. Returns 1. + * It is a constructor, which means that it will automatically be called before + * main(). This is GCC-specific but it works at least since 2.95. + * Special care must be taken so that it does not need any uninitialized data. */ -int kqueue_register(struct poller *p) +__attribute__((constructor)) +static void _do_register(void) { + struct poller *p; + + if (nbpollers >= MAX_POLLERS) + return; + p = &pollers[nbpollers++]; + 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->test = _do_test; + p->init = _do_init; + p->term = _do_term; + p->poll = _do_poll; + p->fork = _do_fork; p->is_set = __fd_is_set; p->cond_s = p->set = __fd_set; p->cond_c = p->clr = __fd_clr; p->rem = __fd_rem; p->clo = __fd_clo; - - return 1; } diff --git a/src/ev_poll.c b/src/ev_poll.c index 1dbf228896..c48f502151 100644 --- a/src/ev_poll.c +++ b/src/ev_poll.c @@ -81,7 +81,7 @@ REGPRM1 static void __fd_rem(const int fd) /* * Poll() poller */ -REGPRM2 static void poll_poll(struct poller *p, int wait_time) +REGPRM2 static void _do_poll(struct poller *p, int wait_time) { int status; int fd, nbfd; @@ -157,7 +157,7 @@ REGPRM2 static void poll_poll(struct poller *p, int wait_time) * Returns 0 in case of failure, non-zero in case of success. If it fails, it * disables the poller by setting its pref to 0. */ -REGPRM1 static int poll_init(struct poller *p) +REGPRM1 static int _do_init(struct poller *p) { __label__ fail_swevt, fail_srevt, fail_pe; int fd_set_bytes; @@ -192,7 +192,7 @@ REGPRM1 static int poll_init(struct poller *p) * Termination of the poll() poller. * Memory is released and the poller is marked as unselectable. */ -REGPRM1 static void poll_term(struct poller *p) +REGPRM1 static void _do_term(struct poller *p) { if (fd_evts[DIR_WR]) free(fd_evts[DIR_WR]); @@ -208,31 +208,39 @@ REGPRM1 static void poll_term(struct poller *p) * Check that the poller works. * Returns 1 if OK, otherwise 0. */ -REGPRM1 static int poll_test(struct poller *p) +REGPRM1 static int _do_test(struct poller *p) { return 1; } /* - * The only exported function. Returns 1. + * It is a constructor, which means that it will automatically be called before + * main(). This is GCC-specific but it works at least since 2.95. + * Special care must be taken so that it does not need any uninitialized data. */ -int poll_register(struct poller *p) +__attribute__((constructor)) +static void _do_register(void) { + struct poller *p; + + if (nbpollers >= MAX_POLLERS) + return; + p = &pollers[nbpollers++]; + p->name = "poll"; p->pref = 200; p->private = NULL; - p->test = poll_test; - p->init = poll_init; - p->term = poll_term; - p->poll = poll_poll; + p->test = _do_test; + p->init = _do_init; + p->term = _do_term; + p->poll = _do_poll; p->is_set = __fd_is_set; p->set = __fd_set; p->clr = __fd_clr; p->clo = p->rem = __fd_rem; p->cond_s = __fd_cond_s; p->cond_c = __fd_cond_c; - return 1; } diff --git a/src/ev_select.c b/src/ev_select.c index 6c1a13294e..ed79abf01e 100644 --- a/src/ev_select.c +++ b/src/ev_select.c @@ -78,7 +78,7 @@ REGPRM1 static void __fd_rem(int fd) /* * Select() poller */ -REGPRM2 static void select_poll(struct poller *p, int wait_time) +REGPRM2 static void _do_poll(struct poller *p, int wait_time) { int status; int fd, i; @@ -153,7 +153,7 @@ REGPRM2 static void select_poll(struct poller *p, int wait_time) * Returns 0 in case of failure, non-zero in case of success. If it fails, it * disables the poller by setting its pref to 0. */ -REGPRM1 static int select_init(struct poller *p) +REGPRM1 static int _do_init(struct poller *p) { __label__ fail_swevt, fail_srevt, fail_wevt, fail_revt; int fd_set_bytes; @@ -190,7 +190,7 @@ REGPRM1 static int select_init(struct poller *p) * Termination of the select() poller. * Memory is released and the poller is marked as unselectable. */ -REGPRM1 static void select_term(struct poller *p) +REGPRM1 static void _do_term(struct poller *p) { if (fd_evts[DIR_WR]) free(fd_evts[DIR_WR]); @@ -208,31 +208,39 @@ REGPRM1 static void select_term(struct poller *p) * Check that the poller works. * Returns 1 if OK, otherwise 0. */ -REGPRM1 static int select_test(struct poller *p) +REGPRM1 static int _do_test(struct poller *p) { return 1; } /* - * The only exported function. Returns 1. + * It is a constructor, which means that it will automatically be called before + * main(). This is GCC-specific but it works at least since 2.95. + * Special care must be taken so that it does not need any uninitialized data. */ -int select_register(struct poller *p) +__attribute__((constructor)) +static void _do_register(void) { + struct poller *p; + + if (nbpollers >= MAX_POLLERS) + return; + p = &pollers[nbpollers++]; + p->name = "select"; p->pref = 150; p->private = NULL; - p->test = select_test; - p->init = select_init; - p->term = select_term; - p->poll = select_poll; + p->test = _do_test; + p->init = _do_init; + p->term = _do_term; + p->poll = _do_poll; p->is_set = __fd_is_set; p->set = __fd_set; p->clr = __fd_clr; p->clo = p->rem = __fd_rem; p->cond_s = __fd_cond_s; p->cond_c = __fd_cond_c; - return 1; } diff --git a/src/fd.c b/src/fd.c index 5ddfebdd00..9c370faf93 100644 --- a/src/fd.c +++ b/src/fd.c @@ -35,22 +35,6 @@ struct poller cur_poller; int nbpollers = 0; -/********************* - * generic functions - *********************/ - -extern int select_register(struct poller *p); -#if defined(ENABLE_POLL) -extern int poll_register(struct poller *p); -#endif -#if defined(ENABLE_EPOLL) -extern int epoll_register(struct poller *p); -#endif -#if defined(ENABLE_KQUEUE) -extern int kqueue_register(struct poller *p); -#endif - - /* Deletes an FD from the fdsets, and recomputes the maxfd limit. * The file descriptor is also closed. */ @@ -65,27 +49,6 @@ void fd_delete(int fd) } -/* registers all known pollers */ -void register_pollers() -{ - if (select_register(&pollers[nbpollers])) - nbpollers++; -#if defined(ENABLE_POLL) - poll_register(&pollers[nbpollers]); - nbpollers++; -#endif - -#if defined(ENABLE_EPOLL) - epoll_register(&pollers[nbpollers]); - nbpollers++; -#endif - -#if defined(ENABLE_KQUEUE) - kqueue_register(&pollers[nbpollers]); - nbpollers++; -#endif -} - /* disable the specified poller */ void disable_poller(const char *poller_name) { diff --git a/src/haproxy.c b/src/haproxy.c index 785bd740f8..f1e5cc3b7e 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -523,8 +523,10 @@ void init(int argc, char **argv) fdtab[i].state = FD_STCLOSE; } - register_pollers(); - /* Note: we could register external pollers here */ + /* + * Note: we could register external pollers here. + * Built-in pollers have been registered before main(). + */ if (!(cfg_polling_mechanism & POLL_USE_KQUEUE)) disable_poller("kqueue");