extern struct poller cur_poller; /* the current poller */
extern int nbpollers;
extern struct poller pollers[MAX_POLLERS]; /* all registered pollers */
-extern struct fdtab *fdtab; /* array of all the file descriptors */
+extern THREAD_LOCAL struct fdtab *fdtab; /* array of all the file descriptors */
extern int totalconn; /* total # of terminated sessions */
extern int actconn; /* # of active sessions */
#define GTUNE_LISTENER_MQ_ANY (GTUNE_LISTENER_MQ_FAIR | GTUNE_LISTENER_MQ_OPT)
#define GTUNE_NO_KTLS (1<<29)
#define GTUNE_NO_MAX_COUNTER (1<<30)
+#define GTUNE_NO_TG_FD_SHARING (1U<<31)
/* subsystem-specific debugging options for tune.debug */
#define GDBG_CPU_AFFINITY (1U<< 0)
uint niced_tasks; /* number of niced tasks in this group's run queues */
uint committed_extra_streams; /* sum of extra front streams committed by muxes in this group */
+ struct fdtab *fdtab; /* fdtab to be used by that thread group */
/* pad to cache line (64B) */
char __pad[0]; /* unused except to check remaining room */
#include <haproxy/tools.h>
-struct fdtab *fdtab __read_mostly = NULL; /* array of all the file descriptors */
+THREAD_LOCAL struct fdtab *fdtab = NULL; /* array of all the file descriptors */
+static struct fdtab *_fdtab;
struct polled_mask *polled_mask __read_mostly = NULL; /* Array for the polled_mask of each fd */
int totalconn; /* total # of terminated sessions */
int actconn; /* # of active sessions */
{
int p;
struct poller *bp;
+ int nbfdtab;
+
+ if (global.tune.options & GTUNE_NO_TG_FD_SHARING) {
+ nbfdtab = global.nbtgroups;
+ } else
+ nbfdtab = 1;
/* always provide an aligned fdtab */
- if ((fdtab = ha_aligned_zalloc(64, array_size_or_fail(global.maxsock, sizeof(*fdtab)))) == NULL) {
+ if ((_fdtab = ha_aligned_zalloc(64, array_size_or_fail(global.maxsock, nbfdtab * sizeof(*fdtab)))) == NULL) {
ha_alert("Not enough memory to allocate %d entries for fdtab!\n", global.maxsock);
goto fail_tab;
}
- vma_set_name(fdtab, global.maxsock * sizeof(*fdtab), "fd", "fdtab");
+
+ for (p = 0; p < global.nbtgroups; p++) {
+ if (global.tune.options & GTUNE_NO_TG_FD_SHARING) {
+ ha_tgroup_ctx[p].fdtab = (void *)((char *)(void *)_fdtab + p * global.maxsock * sizeof(*fdtab));
+ } else
+ ha_tgroup_ctx[p].fdtab = _fdtab;
+ }
+ /*
+ * Immediately set the fdtab for our thread, as we'll need it soon
+ */
+ fdtab = ha_tgroup_ctx[0].fdtab;
+ vma_set_name(_fdtab, global.maxsock * sizeof(*fdtab) * nbfdtab, "fd", "fdtab");
if ((polled_mask = calloc(global.maxsock, sizeof(*polled_mask))) == NULL) {
ha_alert("Not enough memory to allocate %d entries for polled_mask!\n", global.maxsock);
__decl_thread(static pthread_cond_t init_cond = PTHREAD_COND_INITIALIZER);
ha_set_thread(data);
+ fdtab = tg_ctx->fdtab;
set_thread_cpu_affinity();
clock_set_local_source();
ha_random_seed_thread();
struct tgroup_info *tgi = (struct tgroup_info *)arg;
int i;
+#ifdef CLONE_FILES
+ if (global.tune.options & GTUNE_NO_TG_FD_SHARING)
+ if (unshare(CLONE_FILES) != 0) {
+ ha_alert("unshare(CLONE_FILES) failed while trying to use one FD table per thread group (%s)\n", strerror(errno));
+ exit(1);
+ }
+#endif
/* Create nbthread-1 thread. The first thread is the current one */
for (i = 1; i < tgi->count; i++)
pthread_create(&ha_pthread[tgi->base + i], NULL, tgi->start, &ha_thread_info[tgi->base + i]);
*/
for (i = 1; i < global.nbtgroups; i++) {
ha_tgroup_info[i].start = handler;
+ /*
+ * Copy the fdtab to the new thread group, it should contain
+ * file descriptors that are common to all thread groups
+ */
+ if (global.tune.options & GTUNE_NO_TG_FD_SHARING)
+ memcpy(ha_tgroup_ctx[i].fdtab, ha_tgroup_ctx[0].fdtab,
+ global.maxsock * sizeof(*fdtab));
pthread_create(&ha_pthread[ha_tgroup_info[i].base], NULL, &start_extra_tgroup_threads, &ha_tgroup_info[i]);
}