]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MAJOR: threads: Start threads to experiment multithreading
authorChristopher Faulet <cfaulet@haproxy.com>
Tue, 29 Aug 2017 13:38:48 +0000 (15:38 +0200)
committerWilly Tarreau <w@1wt.eu>
Tue, 31 Oct 2017 12:58:29 +0000 (13:58 +0100)
[WARNING] For now, HAProxy is not thread-safe, so from this commit, it will be
          broken for a while, when compiled with threads.

When nbthread parameter is greater than 1, HAProxy will create the corresponding
number of threads. If nbthread is set to 1, nothing should be done. So if there
are concurrency issues (and be sure there will be, unfortunatly), an obvious
workaround is to disable the multithreading...

Each created threads will run a polling loop. So, in a certain way, it is pretty
similar to the nbproc mode ("outside" the bugs and the lock
contention). Nevertheless, there are an init and a deinit steps for each thread
to deal with per-thread allocation.

Each thread has a tid (thread-id), numbered from 0 to (nbtread-1). It is used in
many place to do bitwise operations or to improve debugging information.

src/haproxy.c

index bd8dfd629dfbfadc5636c53d5a910aebd4f90ed6..c145639508de9797ae229e3a5d8683160504ab17 100644 (file)
@@ -2237,6 +2237,32 @@ static void run_poll_loop()
        }
 }
 
+#ifdef USE_THREAD
+static void *run_thread_poll_loop(void *data)
+{
+       struct per_thread_init_fct   *ptif;
+       struct per_thread_deinit_fct *ptdf;
+
+       tid     = *((unsigned int *)data);
+       tid_bit = (1UL << tid);
+       tv_update_date(-1,-1);
+
+       list_for_each_entry(ptif, &per_thread_init_list, list) {
+               if (!ptif->fct()) {
+                       Alert("failed to initialize thread %u.\n", tid);
+                       exit(1);
+               }
+       }
+
+       run_poll_loop();
+
+       list_for_each_entry(ptdf, &per_thread_deinit_list, list)
+               ptdf->fct();
+
+       pthread_exit(NULL);
+}
+#endif
+
 /* This is the global management task for listeners. It enables listeners waiting
  * for global resources when there are enough free resource, or at least once in
  * a while. It is designed to be called as a task.
@@ -2755,11 +2781,32 @@ int main(int argc, char **argv)
        /*
         * That's it : the central polling loop. Run until we stop.
         */
-       run_poll_loop();
+       if (global.nbthread > 1) {
+#ifdef USE_THREAD
+               unsigned int *tids    = calloc(global.nbthread, sizeof(unsigned int));
+               pthread_t    *threads = calloc(global.nbthread, sizeof(pthread_t));
+               int          i;
+
+               for (i = 0; i < global.nbthread; i++) {
+                       tids[i] = i;
+                       pthread_create(&threads[i], NULL, &run_thread_poll_loop, &tids[i]);
+               }
+               for (i = 0; i < global.nbthread; i++)
+                       pthread_join(threads[i], NULL);
+
+               free(tids);
+               free(threads);
 
-       /* Do some cleanup */ 
+#endif /* USE_THREAD */
+       }
+       else {
+               tid = 0;
+               run_poll_loop();
+       }
+
+       /* Do some cleanup */
        deinit();
-    
+
        exit(0);
 }