eal: fix hang in control thread creation
authorLuc Pelletier <lucp.at.work@gmail.com>
Wed, 7 Apr 2021 20:16:06 +0000 (16:16 -0400)
committerDavid Marchand <david.marchand@redhat.com>
Fri, 9 Apr 2021 14:37:55 +0000 (16:37 +0200)
The affinity of a control thread is set after it has been launched. If
setting the affinity fails, pthread_cancel is called followed by a call
to pthread_join, which can hang forever if the thread's start routine
doesn't call a pthread cancellation point.

This patch modifies the logic so that the control thread exits
gracefully if the affinity cannot be set successfully and removes the
call to pthread_cancel.

Fixes: 6383d2642b62 ("eal: set name when creating a control thread")
Cc: stable@dpdk.org
Signed-off-by: Luc Pelletier <lucp.at.work@gmail.com>
Acked-by: Olivier Matz <olivier.matz@6wind.com>
Reviewed-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>
lib/librte_eal/common/eal_common_thread.c

index 3347e91..03dbcd9 100644 (file)
@@ -187,14 +187,18 @@ static void *ctrl_thread_init(void *arg)
                eal_get_internal_configuration();
        rte_cpuset_t *cpuset = &internal_conf->ctrl_cpuset;
        struct rte_thread_ctrl_params *params = arg;
-       void *(*start_routine)(void *) = params->start_routine;
+       void *(*start_routine)(void *);
        void *routine_arg = params->arg;
 
        __rte_thread_init(rte_lcore_id(), cpuset);
 
        pthread_barrier_wait(&params->configured);
+       start_routine = params->start_routine;
        ctrl_params_free(params);
 
+       if (start_routine == NULL)
+               return NULL;
+
        return start_routine(routine_arg);
 }
 
@@ -218,14 +222,12 @@ rte_ctrl_thread_create(pthread_t *thread, const char *name,
        params->refcnt = 2;
 
        ret = pthread_barrier_init(&params->configured, NULL, 2);
-       if (ret != 0) {
-               free(params);
-               return -ret;
-       }
+       if (ret != 0)
+               goto fail_no_barrier;
 
        ret = pthread_create(thread, attr, ctrl_thread_init, (void *)params);
        if (ret != 0)
-               goto fail;
+               goto fail_with_barrier;
 
        if (name != NULL) {
                ret = rte_thread_setname(*thread, name);
@@ -236,19 +238,22 @@ rte_ctrl_thread_create(pthread_t *thread, const char *name,
 
        ret = pthread_setaffinity_np(*thread, sizeof(*cpuset), cpuset);
        if (ret != 0)
-               goto fail_cancel;
+               params->start_routine = NULL;
 
        pthread_barrier_wait(&params->configured);
        ctrl_params_free(params);
 
-       return 0;
+       if (ret != 0)
+               /* start_routine has been set to NULL above; */
+               /* ctrl thread will exit immediately */
+               pthread_join(*thread, NULL);
 
-fail_cancel:
-       pthread_cancel(*thread);
-       pthread_join(*thread, NULL);
+       return -ret;
 
-fail:
+fail_with_barrier:
        pthread_barrier_destroy(&params->configured);
+
+fail_no_barrier:
        free(params);
 
        return -ret;