diff --git a/include/types/global.h b/include/types/global.h index b44f1c7c7..0573fb485 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -231,8 +231,6 @@ extern int stopping; /* non zero means stopping in progress */ extern int killed; /* >0 means a hard-stop is triggered, >1 means hard-stop immediately */ extern char hostname[MAX_HOSTNAME_LEN]; extern char localpeer[MAX_HOSTNAME_LEN]; -extern struct mt_list global_listener_queue; /* list of the temporarily limited listeners */ -extern struct task *global_listener_queue_task; extern unsigned int warned; /* bitfield of a few warnings to emit just once */ extern volatile unsigned long sleeping_thread_mask; extern struct list proc_list; /* list of process in mworker mode */ diff --git a/src/haproxy.c b/src/haproxy.c index c8b59654e..a628c4043 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -235,11 +235,6 @@ unsigned int rlim_fd_max_at_boot = 0; struct mworker_proc *proc_self = NULL; -/* list of the temporarily limited listeners because of lack of resource */ -struct mt_list global_listener_queue = MT_LIST_HEAD_INIT(global_listener_queue); -struct task *global_listener_queue_task; -static struct task *manage_global_listener_queue(struct task *t, void *context, unsigned short state); - static void *run_thread_poll_loop(void *data); /* bitfield of a few warnings to emit just once (WARN_*) */ @@ -1955,15 +1950,6 @@ static void init(int argc, char **argv) exit(2); } - global_listener_queue_task = task_new(MAX_THREADS_MASK); - if (!global_listener_queue_task) { - ha_alert("Out of memory when initializing global task\n"); - exit(1); - } - /* very simple initialization, users will queue the task if needed */ - global_listener_queue_task->context = NULL; /* not even a context! */ - global_listener_queue_task->process = manage_global_listener_queue; - /* now we know the buffer size, we can initialize the channels and buffers */ init_buffer(); @@ -2597,7 +2583,6 @@ void deinit(void) free(global.node); global.node = NULL; free(global.desc); global.desc = NULL; free(oldpids); oldpids = NULL; - task_destroy(global_listener_queue_task); global_listener_queue_task = NULL; task_destroy(idle_conn_task); idle_conn_task = NULL; @@ -2801,33 +2786,6 @@ static void *run_thread_poll_loop(void *data) return NULL; } -/* This is the global management task for listeners. It enables listeners waiting - * for global resources when there are enough free resource, or at least once in - * a while. It is designed to be called as a task. - */ -static struct task *manage_global_listener_queue(struct task *t, void *context, unsigned short state) -{ - /* If there are still too many concurrent connections, let's wait for - * some of them to go away. We don't need to re-arm the timer because - * each of them will scan the queue anyway. - */ - if (unlikely(actconn >= global.maxconn)) - goto out; - - /* We should periodically try to enable listeners waiting for a global - * resource here, because it is possible, though very unlikely, that - * they have been blocked by a temporary lack of global resource such - * as a file descriptor or memory and that the temporary condition has - * disappeared. - */ - dequeue_all_listeners(); - - out: - t->expire = TICK_ETERNITY; - task_queue(t); - return t; -} - /* set uid/gid depending on global settings */ static void set_identity(const char *program_name) { diff --git a/src/listener.c b/src/listener.c index 848b01eae..94200c7be 100644 --- a/src/listener.c +++ b/src/listener.c @@ -55,6 +55,12 @@ struct xfer_sock_list *xfer_sock_list = NULL; */ static struct work_list *local_listener_queue; +/* list of the temporarily limited listeners because of lack of resource */ +static struct mt_list global_listener_queue = MT_LIST_HEAD_INIT(global_listener_queue); +static struct task *global_listener_queue_task; +static struct task *manage_global_listener_queue(struct task *t, void *context, unsigned short state); + + #if defined(USE_THREAD) struct accept_queue_ring accept_queue_rings[MAX_THREADS] __attribute__((aligned(64))) = { }; @@ -1144,17 +1150,57 @@ static int listener_queue_init() ha_alert("Out of memory while initializing listener queues.\n"); return ERR_FATAL|ERR_ABORT; } + + global_listener_queue_task = task_new(MAX_THREADS_MASK); + if (!global_listener_queue_task) { + ha_alert("Out of memory when initializing global listener queue\n"); + return ERR_FATAL|ERR_ABORT; + } + /* very simple initialization, users will queue the task if needed */ + global_listener_queue_task->context = NULL; /* not even a context! */ + global_listener_queue_task->process = manage_global_listener_queue; + return 0; } static void listener_queue_deinit() { work_list_destroy(local_listener_queue, global.nbthread); + task_destroy(global_listener_queue_task); + global_listener_queue_task = NULL; } REGISTER_CONFIG_POSTPARSER("multi-threaded listener queue", listener_queue_init); REGISTER_POST_DEINIT(listener_queue_deinit); + +/* This is the global management task for listeners. It enables listeners waiting + * for global resources when there are enough free resource, or at least once in + * a while. It is designed to be called as a task. + */ +static struct task *manage_global_listener_queue(struct task *t, void *context, unsigned short state) +{ + /* If there are still too many concurrent connections, let's wait for + * some of them to go away. We don't need to re-arm the timer because + * each of them will scan the queue anyway. + */ + if (unlikely(actconn >= global.maxconn)) + goto out; + + /* We should periodically try to enable listeners waiting for a global + * resource here, because it is possible, though very unlikely, that + * they have been blocked by a temporary lack of global resource such + * as a file descriptor or memory and that the temporary condition has + * disappeared. + */ + dequeue_all_listeners(); + + out: + t->expire = TICK_ETERNITY; + task_queue(t); + return t; +} + /* * Registers the bind keyword list as a list of valid keywords for next * parsing sessions.