MEDIUM: config: limit nbproc to the machine's word size

Some consistency checks cannot be performed between frontends, backends
and peers at the moment because there is no way to check for intersection
between processes bound to some processes when the number of processes is
higher than the number of bits in a word.

So first, let's limit the number of processes to the machine's word size.
This means nbproc will be limited to 32 on 32-bit machines and 64 on 64-bit
machines. This is far more than enough considering that configs rarely go
above 16 processes due to scalability and management issues, so 32 or 64
should be fine.

This way we'll ensure we can always build a mask of all the processes a
section is bound to.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index f6bda15..3ec161e 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -525,16 +525,16 @@
   On Linux 2.6 and above, it is possible to bind a process to a specific CPU
   set. This means that the process will never run on other CPUs. The "cpu-map"
   directive specifies CPU sets for process sets. The first argument is the
-  process number to bind. This process must have a number between 1 and 32,
-  and any process IDs above nbproc are ignored. It is possible to specify all
-  processes at once using "all", only odd numbers using "odd" or even numbers
-  using "even", just like with the "bind-process" directive. The second and
-  forthcoming arguments are CPU sets. Each CPU set is either a unique number
-  between 0 and 31 or a range with two such numbers delimited by a dash ('-').
-  Multiple CPU numbers or ranges may be specified, and the processes will be
-  allowed to bind to all of them. Obviously, multiple "cpu-map" directives may
-  be specified. Each "cpu-map" directive will replace the previous ones when
-  they overlap.
+  process number to bind. This process must have a number between 1 and 32 or
+  64, depending on the machine's word size, and any process IDs above nbproc
+  are ignored. It is possible to specify all processes at once using "all",
+  only odd numbers using "odd" or even numbers using "even", just like with the
+  "bind-process" directive. The second and forthcoming arguments are CPU sets.
+  Each CPU set is either a unique number between 0 and 31 or 63 or a range with
+  two such numbers delimited by a dash ('-'). Multiple CPU numbers or ranges
+  may be specified, and the processes will be allowed to bind to all of them.
+  Obviously, multiple "cpu-map" directives may be specified. Each "cpu-map"
+  directive will replace the previous ones when they overlap.
 
 crt-base <dir>
   Assigns a default directory to fetch SSL certificates from when a relative
@@ -624,14 +624,15 @@
   the "-p" command line argument. The file must be accessible to the user
   starting the process. See also "daemon".
 
-stats bind-process [ all | odd | even | <number 1-32>[-<number 1-32>] ] ...
+stats bind-process [ all | odd | even | <number 1-64>[-<number 1-64>] ] ...
   Limits the stats socket to a certain set of processes numbers. By default the
   stats socket is bound to all processes, causing a warning to be emitted when
   nbproc is greater than 1 because there is no way to select the target process
   when connecting. However, by using this setting, it becomes possible to pin
   the stats socket to a specific set of processes, typically the first one. The
   warning will automatically be disabled when this setting is used, whatever
-  the number of processes used.
+  the number of processes used. The maximum process ID depends on the machine's
+  word size (32 or 64).
 
 ssl-default-bind-ciphers <ciphers>
   This setting is only available when support for OpenSSL was built in. It sets
@@ -1830,7 +1831,7 @@
              documentation, and section 5 about bind options.
 
 
-bind-process [ all | odd | even | <number 1-32>[-<number 1-32>] ] ...
+bind-process [ all | odd | even | <number 1-64>[-<number 1-64>] ] ...
   Limit visibility of an instance to a certain set of processes numbers.
   May be used in sections :   defaults | frontend | listen | backend
                                  yes   |    yes   |   yes  |   yes
@@ -1838,19 +1839,19 @@
     all           All process will see this instance. This is the default. It
                   may be used to override a default value.
 
-    odd           This instance will be enabled on processes 1,3,5,...31. This
+    odd           This instance will be enabled on processes 1,3,5,...63. This
                   option may be combined with other numbers.
 
-    even          This instance will be enabled on processes 2,4,6,...32. This
+    even          This instance will be enabled on processes 2,4,6,...64. This
                   option may be combined with other numbers. Do not use it
                   with less than 2 processes otherwise some instances might be
                   missing from all processes.
 
     number        The instance will be enabled on this process number or range,
-                  whose values must all be between 1 and 32. You must be
-                  careful not to reference a process number greater than the
-                  configured global.nbproc, otherwise some instances might be
-                  missing from all processes.
+                  whose values must all be between 1 and 32 or 64 depending on
+                  the machine's word size. You must be careful not to reference
+                  a process number greater than the configured global.nbproc,
+                  otherwise some instances might be missing from all processes.
 
   This keyword limits binding of certain instances to certain processes. This
   is useful in order not to have too many processes listening to the same
@@ -1858,10 +1859,10 @@
   'nbproc 2' in the global section, then distributes the listeners among 'odd'
   and 'even' instances.
 
-  At the moment, it is not possible to reference more than 32 processes using
-  this keyword, but this should be more than enough for most setups. Please
-  note that 'all' really means all processes and is not limited to the first
-  32.
+  At the moment, it is not possible to reference more than 32 or 64 processes
+  using this keyword, but this should be more than enough for most setups.
+  Please note that 'all' really means all processes regardless of the machine's
+  word size, and is not limited to the first 32 or 64.
 
   If some backends are referenced by frontends bound to other processes, the
   backend automatically inherits the frontend's processes.
diff --git a/include/common/standard.h b/include/common/standard.h
index 0beb2c9..86cafb5 100644
--- a/include/common/standard.h
+++ b/include/common/standard.h
@@ -42,6 +42,10 @@
 # define ULLONG_MAX	(LLONG_MAX * 2ULL + 1)
 #endif
 
+#ifndef LONGBITS
+#define LONGBITS  ((unsigned int)sizeof(long) * 8)
+#endif
+
 /* size used for max length of decimal representation of long long int. */
 #define NB_LLMAX_STR (sizeof("-9223372036854775807")-1)
 
@@ -527,7 +531,7 @@
 }
 
 /* Simple popcount implementation. It returns the number of ones in a word */
-static inline unsigned int popcount(unsigned int a)
+static inline unsigned int popcount(unsigned long a)
 {
 	unsigned int cnt;
 	for (cnt = 0; a; a >>= 1) {
@@ -537,6 +541,15 @@
 	return cnt;
 }
 
+/* Build a word with the <bits> lower bits set (reverse of popcount) */
+static inline unsigned long nbits(int bits)
+{
+	if (--bits < 0)
+		return 0;
+	else
+		return (2UL << bits) - 1;
+}
+
 /*
  * Parse binary string written in hexadecimal (source) and store the decoded
  * result into binstr and set binstrlen to the lengh of binstr. Memory for
diff --git a/include/types/global.h b/include/types/global.h
index cf61271..c945f53 100644
--- a/include/types/global.h
+++ b/include/types/global.h
@@ -149,7 +149,7 @@
 		} ux;
 	} unix_bind;
 #ifdef USE_CPU_AFFINITY
-	unsigned long cpu_map[32];  /* list of CPU masks for the 32 first processes */
+	unsigned long cpu_map[LONGBITS];  /* list of CPU masks for the 32/64 first processes */
 #endif
 	struct proxy *stats_fe;     /* the frontend holding the stats settings */
 };
diff --git a/include/types/proxy.h b/include/types/proxy.h
index cf277fd..1086190 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -345,7 +345,7 @@
 	struct chunk errmsg[HTTP_ERR_SIZE];	/* default or customized error messages for known errors */
 	int uuid;				/* universally unique proxy ID, used for SNMP */
 	unsigned int backlog;			/* force the frontend's listen backlog */
-	unsigned int bind_proc;			/* bitmask of processes using this proxy. 0 = all. */
+	unsigned long bind_proc;		/* bitmask of processes using this proxy */
 
 	/* warning: these structs are huge, keep them at the bottom */
 	struct sockaddr_storage dispatch_addr;	/* the default address to connect to */
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 7f11bf8..7032397 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -886,6 +886,12 @@
 			goto out;
 		}
 		global.nbproc = atol(args[1]);
+		if (global.nbproc < 1 || global.nbproc > LONGBITS) {
+			Alert("parsing [%s:%d] : '%s' must be between 1 and %d (was %d).\n",
+			      file, linenum, args[0], LONGBITS, global.nbproc);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
 	}
 	else if (!strcmp(args[0], "maxconn")) {
 		if (global.maxconn != 0) {
@@ -1369,24 +1375,24 @@
 	else if (strcmp(args[0], "cpu-map") == 0) {  /* map a process list to a CPU set */
 #ifdef USE_CPU_AFFINITY
 		int cur_arg, i;
-		unsigned int proc = 0;
+		unsigned long proc = 0;
 		unsigned long cpus = 0;
 
 		if (strcmp(args[1], "all") == 0)
-			proc = 0xFFFFFFFF;
+			proc = ~0UL;
 		else if (strcmp(args[1], "odd") == 0)
-			proc = 0x55555555;
+			proc = ~0UL/3UL; /* 0x555....555 */
 		else if (strcmp(args[1], "even") == 0)
-			proc = 0xAAAAAAAA;
+			proc = (~0UL/3UL) << 1; /* 0xAAA...AAA */
 		else {
-			proc = atoi(args[1]);
-			if (proc >= 1 && proc <= 32)
-				proc = 1 << (proc - 1);
+			proc = atol(args[1]);
+			if (proc >= 1 && proc <= LONGBITS)
+				proc = 1UL << (proc - 1);
 		}
 
 		if (!proc || !*args[2]) {
-			Alert("parsing [%s:%d]: %s expects a process number including 'all', 'odd', 'even', or a number from 1 to 32, followed by a list of CPU ranges with numbers from 0 to 31.\n",
-			      file, linenum, args[0]);
+			Alert("parsing [%s:%d]: %s expects a process number including 'all', 'odd', 'even', or a number from 1 to %d, followed by a list of CPU ranges with numbers from 0 to %d.\n",
+			      file, linenum, args[0], LONGBITS, LONGBITS - 1);
 			err_code |= ERR_ALERT | ERR_FATAL;
 			goto out;
 		}
@@ -1408,9 +1414,9 @@
 					high = swap;
 				}
 
-				if (high >= sizeof(long) * 8) {
+				if (high >= LONGBITS) {
 					Alert("parsing [%s:%d]: %s supports CPU numbers from 0 to %d.\n",
-					      file, linenum, args[0], (int)(sizeof(long) * 8 - 1));
+					      file, linenum, args[0], LONGBITS - 1);
 					err_code |= ERR_ALERT | ERR_FATAL;
 					goto out;
 				}
@@ -1426,8 +1432,8 @@
 			}
 			cur_arg++;
 		}
-		for (i = 0; i < 32; i++)
-			if (proc & (1 << i))
+		for (i = 0; i < LONGBITS; i++)
+			if (proc & (1UL << i))
 				global.cpu_map[i] = cpus;
 #else
 		Alert("parsing [%s:%d] : '%s' is not enabled, please check build options for USE_CPU_AFFINITY.\n", file, linenum, args[0]);
@@ -2350,7 +2356,7 @@
 	}
 	else if (!strcmp(args[0], "bind-process")) {  /* enable this proxy only on some processes */
 		int cur_arg = 1;
-		unsigned int set = 0;
+		unsigned long set = 0;
 
 		while (*args[cur_arg]) {
 			unsigned int low, high;
@@ -2360,10 +2366,10 @@
 				break;
 			}
 			else if (strcmp(args[cur_arg], "odd") == 0) {
-				set |= 0x55555555;
+				set |= ~0UL/3UL; /* 0x555....555 */
 			}
 			else if (strcmp(args[cur_arg], "even") == 0) {
-				set |= 0xAAAAAAAA;
+				set |= (~0UL/3UL) << 1; /* 0xAAA...AAA */
 			}
 			else if (isdigit((int)*args[cur_arg])) {
 				char *dash = strchr(args[cur_arg], '-');
@@ -2378,24 +2384,18 @@
 					high = swap;
 				}
 
-				if (low < 1 || high > 32) {
-					Alert("parsing [%s:%d]: %s supports process numbers from 1 to 32.\n",
-					      file, linenum, args[0]);
+				if (low < 1 || high > LONGBITS) {
+					Alert("parsing [%s:%d]: %s supports process numbers from 1 to %d.\n",
+					      file, linenum, args[0], LONGBITS);
 					err_code |= ERR_ALERT | ERR_FATAL;
 					goto out;
 				}
-
-				if (high > global.nbproc) {
-					Warning("parsing [%s:%d]: %s references process number %d which is higher than global.nbproc (%d).\n",
-						file, linenum, args[0], high, global.nbproc);
-					err_code |= ERR_WARN;
-				}
 				while (low <= high)
-					set |= 1 << (low++ - 1);
+					set |= 1UL << (low++ - 1);
 			}
 			else {
-				Alert("parsing [%s:%d]: %s expects 'all', 'odd', 'even', or a list of process ranges with numbers from 1 to 32.\n",
-				      file, linenum, args[0]);
+				Alert("parsing [%s:%d]: %s expects 'all', 'odd', 'even', or a list of process ranges with numbers from 1 to %d.\n",
+				      file, linenum, args[0], LONGBITS);
 				err_code |= ERR_ALERT | ERR_FATAL;
 				goto out;
 			}
@@ -6860,7 +6860,7 @@
 			if (curproxy->bind_proc) {
 				int proc;
 				for (proc = 0; proc < global.nbproc; proc++) {
-					if (curproxy->bind_proc & (1 << proc)) {
+					if (curproxy->bind_proc & (1UL << proc)) {
 						nbproc++;
 					}
 				}
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 5222534..e0c21b6 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -372,7 +372,7 @@
 	}
 	else if (!strcmp(args[1], "bind-process")) {  /* enable the socket only on some processes */
 		int cur_arg = 2;
-		unsigned int set = 0;
+		unsigned long set = 0;
 
 		if (!global.stats_fe) {
 			if ((global.stats_fe = alloc_stats_fe("GLOBAL", file, line)) == NULL) {
@@ -389,10 +389,10 @@
 				break;
 			}
 			else if (strcmp(args[cur_arg], "odd") == 0) {
-				set |= 0x55555555;
+				set |= ~0UL/3UL; /* 0x555....555 */
 			}
 			else if (strcmp(args[cur_arg], "even") == 0) {
-				set |= 0xAAAAAAAA;
+				set |= (~0UL/3UL) << 1; /* 0xAAA...AAA */
 			}
 			else if (isdigit((int)*args[cur_arg])) {
 				char *dash = strchr(args[cur_arg], '-');
@@ -407,19 +407,18 @@
 					high = swap;
 				}
 
-				if (low < 1 || high > 32) {
-					memprintf(err, "'%s %s' supports process numbers from 1 to 32.\n",
-					          args[0], args[1]);
+				if (low < 1 || high > LONGBITS) {
+					memprintf(err, "'%s %s' supports process numbers from 1 to %d.\n",
+					          args[0], args[1], LONGBITS);
 					return -1;
 				}
-
 				while (low <= high)
-					set |= 1 << (low++ - 1);
+					set |= 1UL << (low++ - 1);
 			}
 			else {
 				memprintf(err,
-				          "'%s %s' expects 'all', 'odd', 'even', or a list of process ranges with numbers from 1 to 32.\n",
-				          args[0], args[1]);
+				          "'%s %s' expects 'all', 'odd', 'even', or a list of process ranges with numbers from 1 to %d.\n",
+				          args[0], args[1], LONGBITS);
 				return -1;
 			}
 			cur_arg++;
diff --git a/src/haproxy.c b/src/haproxy.c
index 81eaeba..77871b0 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -1596,7 +1596,7 @@
 		px = proxy;
 		while (px != NULL) {
 			if (px->bind_proc && px->state != PR_STSTOPPED) {
-				if (!(px->bind_proc & (1 << proc)))
+				if (!(px->bind_proc & (1UL << proc)))
 					stop_proxy(px);
 			}
 			px = px->next;