From 7ba0f11d70235c844fd420121b9ea42815ecec05 Mon Sep 17 00:00:00 2001 From: hujun5 Date: Fri, 15 Nov 2024 10:24:20 +0800 Subject: [PATCH] pthread: remove enter_critical_section in pthread_barrier_wait reason: We decouple semcount from business logic by using an independent counting variable, which allows us to remove critical sections in many cases. Signed-off-by: hujun5 --- include/pthread.h | 2 + libs/libc/pthread/pthread_barrierinit.c | 2 + sched/pthread/pthread_barrierwait.c | 52 +++++-------------------- 3 files changed, 14 insertions(+), 42 deletions(-) diff --git a/include/pthread.h b/include/pthread.h index a7badf2746321..e0866c8462d51 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -368,6 +368,8 @@ struct pthread_barrier_s { sem_t sem; unsigned int count; + unsigned int wait_count; + mutex_t mutex; }; #ifndef __PTHREAD_BARRIER_T_DEFINED diff --git a/libs/libc/pthread/pthread_barrierinit.c b/libs/libc/pthread/pthread_barrierinit.c index 5ff90ed72ec2d..739ccc6cb1cac 100644 --- a/libs/libc/pthread/pthread_barrierinit.c +++ b/libs/libc/pthread/pthread_barrierinit.c @@ -87,6 +87,8 @@ int pthread_barrier_init(FAR pthread_barrier_t *barrier, { sem_init(&barrier->sem, 0, 0); barrier->count = count; + barrier->wait_count = 0; + nxmutex_init(&barrier->mutex); } return ret; diff --git a/sched/pthread/pthread_barrierwait.c b/sched/pthread/pthread_barrierwait.c index 2486c2d70ed2f..0cbf4901e9556 100644 --- a/sched/pthread/pthread_barrierwait.c +++ b/sched/pthread/pthread_barrierwait.c @@ -82,67 +82,35 @@ int pthread_barrier_wait(FAR pthread_barrier_t *barrier) { - irqstate_t flags; - int semcount; - int ret; - if (barrier == NULL) { return EINVAL; } - /* Disable pre-emption throughout the following */ - - flags = enter_critical_section(); - - /* Find out how many threads are already waiting at the barrier */ - - ret = nxsem_get_value(&barrier->sem, &semcount); - if (ret != OK) - { - leave_critical_section(flags); - return -ret; - } - /* If the number of waiters would be equal to the count, then we are done */ - if ((1 - semcount) >= (int)barrier->count) + nxmutex_lock(&barrier->mutex); + + if ((barrier->wait_count + 1) >= barrier->count) { /* Free all of the waiting threads */ - while (semcount < 0) + while (barrier->wait_count > 0) { + barrier->wait_count--; nxsem_post(&barrier->sem); - nxsem_get_value(&barrier->sem, &semcount); } /* Then return PTHREAD_BARRIER_SERIAL_THREAD to the final thread */ - leave_critical_section(flags); + nxmutex_unlock(&barrier->mutex); + return PTHREAD_BARRIER_SERIAL_THREAD; } - /* Otherwise, this thread must wait as well */ - - while ((ret = nxsem_wait(&barrier->sem)) != OK) - { - /* If the thread is awakened by a signal, just continue to wait */ - - if (ret != -EINTR) - { - /* If it is awakened by some other error, then there is a - * problem - */ - - break; - } - } + barrier->wait_count++; - /* We will only get here when we are one of the N-1 threads that were - * waiting for the final thread at the barrier. We just need to return - * zero. - */ + nxmutex_unlock(&barrier->mutex); - leave_critical_section(flags); - return -ret; + return -nxsem_wait_uninterruptible(&barrier->sem); }