MEDIUM: global: add support for CPU binding on Linux ("cpu-map")

The new "cpu-map" directive allows one to assign the CPU sets that
a process is allowed to bind to. This is useful in combination with
the "nbproc" and "bind-process" directives.

The support is implicit on Linux 2.6.28 and above.
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 13363db..569fcd3 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1160,6 +1160,75 @@
 			err_code |= ERR_ALERT | ERR_FATAL;
 		}
 	}
+	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 cpus = 0;
+
+		if (strcmp(args[1], "all") == 0)
+			proc = 0xFFFFFFFF;
+		else if (strcmp(args[1], "odd") == 0)
+			proc = 0x55555555;
+		else if (strcmp(args[1], "even") == 0)
+			proc = 0xAAAAAAAA;
+		else {
+			proc = atoi(args[1]);
+			if (proc >= 1 && proc <= 32)
+				proc = 1 << (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]);
+			err_code |= ERR_ALERT | ERR_FATAL;
+			goto out;
+		}
+
+		cur_arg = 2;
+		while (*args[cur_arg]) {
+			unsigned int low, high;
+
+			if (isdigit(*args[cur_arg])) {
+				char *dash = strchr(args[cur_arg], '-');
+
+				low = high = str2uic(args[cur_arg]);
+				if (dash)
+					high = str2uic(dash + 1);
+
+				if (high < low) {
+					unsigned int swap = low;
+					low = high;
+					high = swap;
+				}
+
+				if (low < 0 || high >= sizeof(long) * 8) {
+					Alert("parsing [%s:%d]: %s supports CPU numbers from 0 to %d.\n",
+					      file, linenum, args[0], (int)(sizeof(long) * 8 - 1));
+					err_code |= ERR_ALERT | ERR_FATAL;
+					goto out;
+				}
+
+				while (low <= high)
+					cpus |= 1UL << low++;
+			}
+			else {
+				Alert("parsing [%s:%d]: %s : '%s' is not a CPU range.\n",
+				      file, linenum, args[0], args[cur_arg]);
+				err_code |= ERR_ALERT | ERR_FATAL;
+				goto out;
+			}
+			cur_arg++;
+		}
+		for (i = 0; i < 32; i++)
+			if (proc & (1 << 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]);
+		err_code |= ERR_ALERT | ERR_FATAL;
+		goto out;
+#endif
+	}
 	else {
 		struct cfg_kw_list *kwl;
 		int index;