MEDIUM: listeners: support the definition of thread groups on bind lines

This extends the "thread" statement of bind lines to support an optional
thread group number. When unspecified (0) it's an absolute thread range,
and when specified it's one relative to the thread group. Masks are still
used so no more than 64 threads may be specified at once, and a single
group is possible. The directive is not used for now.
diff --git a/src/listener.c b/src/listener.c
index a1e9edc..b89aa98 100644
--- a/src/listener.c
+++ b/src/listener.c
@@ -1593,24 +1593,38 @@
 /* parse the "thread" bind keyword */
 static int bind_parse_thread(char **args, int cur_arg, struct proxy *px, struct bind_conf *conf, char **err)
 {
-	char *slash;
-	unsigned long thread = 0;
+	char *sep = NULL;
+	ulong thread = 0;
+	long tgroup = 0;
 
-	if ((slash = strchr(args[cur_arg + 1], '/')) != NULL)
-		*slash = 0;
+	tgroup = strtol(args[cur_arg + 1], &sep, 10);
+	if (*sep == '/') {
+		/* a thread group was present */
+		if (tgroup < 1 || tgroup > MAX_TGROUPS) {
+			memprintf(err, "'%s' thread-group number must be between 1 and %d (was %ld)", args[cur_arg + 1], MAX_TGROUPS, tgroup);
+			return ERR_ALERT | ERR_FATAL;
+		}
+		sep++;
+	}
+	else {
+		/* no thread group */
+		tgroup = 0;
+		sep = args[cur_arg + 1];
+	}
 
-	if (slash) {
-		*slash = '/';
-		memprintf(err, "'%s': thread groups not supported", args[cur_arg+1]);
+	if ((conf->settings.bind_tgroup || conf->settings.bind_thread) &&
+	    conf->settings.bind_tgroup != tgroup) {
+		memprintf(err, "'%s' multiple thread-groups are not supported", args[cur_arg + 1]);
 		return ERR_ALERT | ERR_FATAL;
 	}
-
-	if (parse_process_number(args[cur_arg+1], &thread, MAX_THREADS, NULL, err)) {
-		memprintf(err, "'%s' : %s", args[cur_arg+1], *err);
+	
+	if (parse_process_number(sep, &thread, MAX_THREADS, NULL, err)) {
+		memprintf(err, "'%s' : %s", sep, *err);
 		return ERR_ALERT | ERR_FATAL;
 	}
 
 	conf->settings.bind_thread |= thread;
+	conf->settings.bind_tgroup  = tgroup;
 	return 0;
 }