MINOR: threads: move "nbthread" parsing to hathreads.c

The purpose is to make sure that all variables which directly depend
on this nbthread argument are set at the right moment. For now only
all_threads_mask needs to be set. It used to be set while calling
thread_sync_init() which is called too late for certain checks. The
same function handles threads and non-threads, which removes the need
for some thread-specific knowledge from cfgparse.c.
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 9841e2d..803a918 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -1190,18 +1190,10 @@
 			err_code |= ERR_ALERT | ERR_FATAL;
 			goto out;
 		}
-		global.nbthread = atol(args[1]);
-#ifndef USE_THREAD
-		if (global.nbthread > 1) {
-			ha_alert("HAProxy is not compiled with threads support, please check build options for USE_THREAD.\n");
-			global.nbthread = 1;
-			err_code |= ERR_ALERT | ERR_FATAL;
-			goto out;
-		}
-#endif
-		if (global.nbthread < 1 || global.nbthread > MAX_THREADS) {
-			ha_alert("parsing [%s:%d] : '%s' must be between 1 and %d (was %d).\n",
-				 file, linenum, args[0], MAX_THREADS, global.nbthread);
+		global.nbthread = parse_nbthread(args[1], &errmsg);
+		if (!global.nbthread) {
+			ha_alert("parsing [%s:%d] : '%s' %s.\n",
+				 file, linenum, args[0], errmsg);
 			err_code |= ERR_ALERT | ERR_FATAL;
 			goto out;
 		}
diff --git a/src/haproxy.c b/src/haproxy.c
index 8525593..810d598 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -3030,7 +3030,7 @@
 		int          i;
 		sigset_t     blocked_sig, old_sig;
 
-		THREAD_SYNC_INIT(global.nbthread);
+		THREAD_SYNC_INIT();
 
 		/* Init tids array */
 		for (i = 0; i < global.nbthread; i++)
diff --git a/src/hathreads.c b/src/hathreads.c
index c0c5956..bfd055a 100644
--- a/src/hathreads.c
+++ b/src/hathreads.c
@@ -11,6 +11,7 @@
  */
 
 #include <unistd.h>
+#include <stdlib.h>
 #include <fcntl.h>
 
 #include <common/cfgparse.h>
@@ -31,7 +32,7 @@
 static HA_SPINLOCK_T sync_lock;
 static int           threads_sync_pipe[2];
 static unsigned long threads_want_sync = 0;
-volatile unsigned long all_threads_mask  = 0;
+volatile unsigned long all_threads_mask  = 1; // nbthread 1 assumed by default
 
 #if defined(DEBUG_THREAD) || defined(DEBUG_FULL)
 struct lock_stat lock_stats[LOCK_LABELS];
@@ -41,7 +42,7 @@
  * others when a sync is requested. It also initializes the mask of all created
  * threads. It returns 0 on success and -1 if an error occurred.
  */
-int thread_sync_init(int nbthread)
+int thread_sync_init()
 {
 	int rfd;
 
@@ -51,10 +52,6 @@
 	rfd = threads_sync_pipe[0];
 	fcntl(rfd, F_SETFL, O_NONBLOCK);
 	fd_insert(rfd, thread_sync_io_handler, thread_sync_io_handler, MAX_THREADS_MASK);
-
-	/* we proceed like this to be sure never to overflow the left shift */
-	all_threads_mask = 1UL << (nbthread - 1);
-	all_threads_mask |= all_threads_mask - 1;
 	return 0;
 }
 
@@ -173,4 +170,38 @@
 	hap_register_build_opts("Built with multi-threading support.", 0);
 }
 
+#endif // USE_THREAD
+
+
+/* Parse the number of threads in argument <arg>, returns it and adjusts a few
+ * internal variables accordingly, or fails and returns zero with an error
+ * reason in <errmsg>. May be called multiple times while parsing.
+ */
+int parse_nbthread(const char *arg, char **err)
+{
+	long nbthread;
+	char *errptr;
+
+	nbthread = strtol(arg, &errptr, 10);
+	if (!*arg || *errptr) {
+		memprintf(err, "passed a missing or unparsable integer value in '%s'", arg);
+		return 0;
+	}
+
+#ifndef USE_THREAD
+	if (nbthread != 1) {
+		memprintf(err, "specified with a value other than 1 while HAProxy is not compiled with threads support. Please check build options for USE_THREAD");
+		return 0;
+	}
+#else
+	if (nbthread < 1 || nbthread > MAX_THREADS) {
+		memprintf(err, "value must be between 1 and %d (was %ld)", MAX_THREADS, nbthread);
+		return 0;
+	}
+
+	/* we proceed like this to be sure never to overflow the left shift */
+	all_threads_mask = 1UL << (nbthread - 1);
+	all_threads_mask |= all_threads_mask - 1;
 #endif
+	return nbthread;
+}