diff --git a/doc/configuration.txt b/doc/configuration.txt index f6bda15d0..3ec161e3f 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -525,16 +525,16 @@ cpu-map <"all"|"odd"|"even"|process_num> ... 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 Assigns a default directory to fetch SSL certificates from when a relative @@ -624,14 +624,15 @@ pidfile 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 | [-] ] ... +stats bind-process [ all | odd | even | [-] ] ... 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 This setting is only available when support for OpenSSL was built in. It sets @@ -1830,7 +1831,7 @@ bind / [, ...] [param*] documentation, and section 5 about bind options. -bind-process [ all | odd | even | [-] ] ... +bind-process [ all | odd | even | [-] ] ... 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 @@ bind-process [ all | odd | even | [-] ] ... 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 @@ bind-process [ all | odd | even | [-] ] ... '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 0beb2c9e3..86cafb5d6 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 @@ static inline unsigned int div64_32(unsigned long long o1, unsigned int o2) } /* 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 @@ static inline unsigned int popcount(unsigned int a) return cnt; } +/* Build a word with the 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 cf612713f..c945f53cc 100644 --- a/include/types/global.h +++ b/include/types/global.h @@ -149,7 +149,7 @@ struct global { } 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 cf277fdd7..1086190a2 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -345,7 +345,7 @@ struct proxy { 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 7f11bf884..703239739 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -886,6 +886,12 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) 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 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) 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 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) 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 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) } 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 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) } 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 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) 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 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm) 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 @@ out_uri_auth_compat: 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 5222534cf..e0c21b6b9 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -372,7 +372,7 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx } 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 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx 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 @@ static int stats_parse_global(char **args, int section_type, struct proxy *curpx 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 81eaeba8b..77871b055 100644 --- a/src/haproxy.c +++ b/src/haproxy.c @@ -1596,7 +1596,7 @@ int main(int argc, char **argv) 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;