MEDIUM: listener: keep a single thread-mask and warn on "process" misuse

Now that nbproc and nbthread are exclusive, we can still provide more
detailed explanations about what we've found in the config when a bind
line appears on multiple threads and processes at the same time, then
ignore the setting.

This patch reduces the listener's thread mask to a single mask instead
of an array of masks per process. Now we have only one thread mask and
one process mask per bind-conf. This removes ~504 bytes of RAM per
bind-conf and will simplify handling of thread masks.

If a "bind" line only refers to process numbers not found by its parent
frontend or not covered by the global nbproc directive, or to a thread
not covered by the global nbthread directive, a warning is emitted saying
what will be used instead.
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 85d8dd5..16d9251 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -2304,8 +2304,7 @@
 #endif
 
 			/* detect and address thread affinity inconsistencies */
-			nbproc = my_ffsl(proc_mask(bind_conf->bind_proc)) - 1;
-			mask = thread_mask(bind_conf->bind_thread[nbproc]);
+			mask = thread_mask(bind_conf->bind_thread);
 			if (!(mask & all_threads_mask)) {
 				unsigned long new_mask = 0;
 
@@ -2314,33 +2313,28 @@
 					mask >>= global.nbthread;
 				}
 
-				for (nbproc = 0; nbproc < MAX_PROCS; nbproc++) {
-					if (!bind_conf->bind_proc || (bind_conf->bind_proc & (1UL << nbproc)))
-						bind_conf->bind_thread[nbproc] = new_mask;
-				}
+				bind_conf->bind_thread = new_mask;
 				ha_warning("Proxy '%s': the thread range specified on the 'process' directive of 'bind %s' at [%s:%d] only refers to thread numbers out of the range defined by the global 'nbthread' directive. The thread numbers were remapped to existing threads instead (mask 0x%lx).\n",
 					   curproxy->id, bind_conf->arg, bind_conf->file, bind_conf->line, new_mask);
 			}
 
 			/* detect process and nbproc affinity inconsistencies */
-			if (!bind_conf->bind_proc)
-				continue;
-
-			mask = proc_mask(curproxy->bind_proc) & all_proc_mask;
-			/* mask cannot be null here thanks to the previous checks */
-
-			nbproc = my_popcountl(bind_conf->bind_proc);
-			bind_conf->bind_proc &= mask;
+			mask = proc_mask(bind_conf->bind_proc) & proc_mask(curproxy->bind_proc);
+			if (!(mask & all_proc_mask)) {
+				mask = proc_mask(curproxy->bind_proc) & all_proc_mask;
+				nbproc = my_popcountl(bind_conf->bind_proc);
+				bind_conf->bind_proc = proc_mask(bind_conf->bind_proc) & mask;
 
-			if (!bind_conf->bind_proc && nbproc == 1) {
-				ha_warning("Proxy '%s': the process number specified on the 'process' directive of 'bind %s' at [%s:%d] refers to a process not covered by the proxy. This has been fixed by forcing it to run on the proxy's first process only.\n",
-					   curproxy->id, bind_conf->arg, bind_conf->file, bind_conf->line);
-				bind_conf->bind_proc = mask & ~(mask - 1);
-			}
-			else if (!bind_conf->bind_proc && nbproc > 1) {
-				ha_warning("Proxy '%s': the process range specified on the 'process' directive of 'bind %s' at [%s:%d] only refers to processes not covered by the proxy. The directive was ignored so that all of the proxy's processes are used.\n",
-					   curproxy->id, bind_conf->arg, bind_conf->file, bind_conf->line);
-				bind_conf->bind_proc = 0;
+				if (!bind_conf->bind_proc && nbproc == 1) {
+					ha_warning("Proxy '%s': the process number specified on the 'process' directive of 'bind %s' at [%s:%d] refers to a process not covered by the proxy. This has been fixed by forcing it to run on the proxy's first process only.\n",
+						   curproxy->id, bind_conf->arg, bind_conf->file, bind_conf->line);
+					bind_conf->bind_proc = mask & ~(mask - 1);
+				}
+				else if (!bind_conf->bind_proc && nbproc > 1) {
+					ha_warning("Proxy '%s': the process range specified on the 'process' directive of 'bind %s' at [%s:%d] only refers to processes not covered by the proxy. The directive was ignored so that all of the proxy's processes are used.\n",
+						   curproxy->id, bind_conf->arg, bind_conf->file, bind_conf->line);
+					bind_conf->bind_proc = 0;
+				}
 			}
 		}
 
diff --git a/src/listener.c b/src/listener.c
index f8745e3..117b9c4 100644
--- a/src/listener.c
+++ b/src/listener.c
@@ -954,7 +954,6 @@
 {
 	char *slash;
 	unsigned long proc = 0, thread = 0;
-	int i;
 
 	if ((slash = strchr(args[cur_arg + 1], '/')) != NULL)
 		*slash = 0;
@@ -973,11 +972,7 @@
 	}
 
 	conf->bind_proc |= proc;
-	if (thread) {
-		for (i = 0; i < MAX_PROCS; i++)
-			if (!proc || (proc & (1UL << i)))
-				conf->bind_thread[i] |= thread;
-	}
+	conf->bind_thread |= thread;
 	return 0;
 }
 
diff --git a/src/proto_sockpair.c b/src/proto_sockpair.c
index 9105dd2..713da37 100644
--- a/src/proto_sockpair.c
+++ b/src/proto_sockpair.c
@@ -153,7 +153,7 @@
 	listener->state = LI_LISTEN;
 
 	fd_insert(fd, listener, listener->proto->accept,
-	          thread_mask(listener->bind_conf->bind_thread[relative_pid-1]));
+	          thread_mask(listener->bind_conf->bind_thread));
 
 	return err;
 
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index e4b8f63..28b7750 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1076,7 +1076,7 @@
 	listener->state = LI_LISTEN;
 
 	fd_insert(fd, listener, listener->proto->accept,
-	          thread_mask(listener->bind_conf->bind_thread[relative_pid-1]));
+	          thread_mask(listener->bind_conf->bind_thread));
 
  tcp_return:
 	if (msg && errlen) {
diff --git a/src/proto_uxst.c b/src/proto_uxst.c
index 7fc145b..d454d4c 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -340,7 +340,7 @@
 	listener->state = LI_LISTEN;
 
 	fd_insert(fd, listener, listener->proto->accept,
-	          thread_mask(listener->bind_conf->bind_thread[relative_pid-1]));
+	          thread_mask(listener->bind_conf->bind_thread));
 
 	return err;