libs/libc/semaphore: Enable semaphore fast wait/post paths for counting semaphores

The fast path can be used also for counting semaphores when the priority
inheritance is disabled.

Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This commit is contained in:
Jukka Laitinen 2025-05-02 14:58:53 +03:00 committed by Xiang Xiao
parent 01040400cb
commit 55913d16ad
3 changed files with 161 additions and 22 deletions

View file

@ -119,6 +119,9 @@ int sem_post(FAR sem_t *sem)
int nxsem_post(FAR sem_t *sem)
{
bool mutex;
bool fastpath = true;
DEBUGASSERT(sem != NULL);
/* We don't do atomic fast path in case of LIBC_ARCH_ATOMIC because that
@ -128,20 +131,60 @@ int nxsem_post(FAR sem_t *sem)
#ifndef CONFIG_LIBC_ARCH_ATOMIC
if (NXSEM_IS_MUTEX(sem)
mutex = NXSEM_IS_MUTEX(sem);
/* Disable fast path if priority protection is enabled on the semaphore */
# ifdef CONFIG_PRIORITY_PROTECT
&& (sem->flags & SEM_PRIO_MASK) != SEM_PRIO_PROTECT
# endif
)
if ((sem->flags & SEM_PRIO_MASK) == SEM_PRIO_PROTECT)
{
int32_t old = _SCHED_GETTID();
if (atomic_try_cmpxchg_release(NXSEM_MHOLDER(sem), &old,
NXSEM_NO_MHOLDER))
fastpath = false;
}
# endif
/* Disable fast path on a counting semaphore with priority inheritance */
# ifdef CONFIG_PRIORITY_INHERITANCE
if (!mutex && (sem->flags & SEM_PRIO_MASK) != SEM_PRIO_NONE)
{
fastpath = false;
}
# endif
if (fastpath)
{
int32_t old;
int32_t new;
FAR atomic_t *val = mutex ? NXSEM_MHOLDER(sem) : NXSEM_COUNT(sem);
if (mutex)
{
old = _SCHED_GETTID();
new = NXSEM_NO_MHOLDER;
}
else
{
old = atomic_read(val);
if (old < 0)
{
goto out;
}
new = old + 1;
}
if (atomic_try_cmpxchg_release(val, &old, new))
{
return OK;
}
}
out:
#else
UNUSED(mutex);
UNUSED(fastpath);
#endif
return nxsem_post_slow(sem);

View file

@ -107,6 +107,9 @@ int sem_trywait(FAR sem_t *sem)
int nxsem_trywait(FAR sem_t *sem)
{
bool mutex;
bool fastpath = true;
DEBUGASSERT(sem != NULL);
/* This API should not be called from the idleloop or interrupt */
@ -123,18 +126,68 @@ int nxsem_trywait(FAR sem_t *sem)
#ifndef CONFIG_LIBC_ARCH_ATOMIC
if (NXSEM_IS_MUTEX(sem)
mutex = NXSEM_IS_MUTEX(sem);
/* Disable fast path if priority protection is enabled on the semaphore */
# ifdef CONFIG_PRIORITY_PROTECT
&& (sem->flags & SEM_PRIO_MASK) != SEM_PRIO_PROTECT
# endif
)
if ((sem->flags & SEM_PRIO_MASK) == SEM_PRIO_PROTECT)
{
int32_t tid = _SCHED_GETTID();
int32_t old = NXSEM_NO_MHOLDER;
return atomic_try_cmpxchg_acquire(NXSEM_MHOLDER(sem), &old, tid) ?
OK : -EAGAIN;
fastpath = false;
}
# endif
/* Disable fast path on a counting semaphore with priority inheritance */
# ifdef CONFIG_PRIORITY_INHERITANCE
if (!mutex && (sem->flags & SEM_PRIO_MASK) != SEM_PRIO_NONE)
{
fastpath = false;
}
# endif
if (fastpath)
{
bool ret = false;
int32_t old;
int32_t new;
FAR atomic_t *val = mutex ? NXSEM_MHOLDER(sem) : NXSEM_COUNT(sem);
if (mutex)
{
old = NXSEM_NO_MHOLDER;
}
else
{
old = atomic_read(val);
}
do
{
if (!mutex)
{
if (old < 1)
{
break;
}
new = old - 1;
}
else
{
new = _SCHED_GETTID();
}
ret = atomic_try_cmpxchg_acquire(NXSEM_MHOLDER(sem), &old, new);
}
while (!mutex && !ret);
return ret ? OK : -EAGAIN;
}
#else
UNUSED(mutex);
UNUSED(fastpath);
#endif
return nxsem_trywait_slow(sem);

View file

@ -135,6 +135,9 @@ errout_with_cancelpt:
int nxsem_wait(FAR sem_t *sem)
{
bool mutex;
bool fastpath = true;
DEBUGASSERT(sem != NULL);
/* This API should not be called from the idleloop or interrupt */
@ -151,20 +154,60 @@ int nxsem_wait(FAR sem_t *sem)
#ifndef CONFIG_LIBC_ARCH_ATOMIC
if (NXSEM_IS_MUTEX(sem)
mutex = NXSEM_IS_MUTEX(sem);
/* Disable fast path if priority protection is enabled on the semaphore */
# ifdef CONFIG_PRIORITY_PROTECT
&& (sem->flags & SEM_PRIO_MASK) != SEM_PRIO_PROTECT
# endif
)
if ((sem->flags & SEM_PRIO_MASK) == SEM_PRIO_PROTECT)
{
int32_t tid = _SCHED_GETTID();
int32_t old = NXSEM_NO_MHOLDER;
if (atomic_try_cmpxchg_acquire(NXSEM_MHOLDER(sem), &old, tid))
fastpath = false;
}
# endif
/* Disable fast path on a counting semaphore with priority inheritance */
# ifdef CONFIG_PRIORITY_INHERITANCE
if (!mutex && (sem->flags & SEM_PRIO_MASK) != SEM_PRIO_NONE)
{
fastpath = false;
}
# endif
if (fastpath)
{
int32_t old;
int32_t new;
FAR atomic_t *val = mutex ? NXSEM_MHOLDER(sem) : NXSEM_COUNT(sem);
if (mutex)
{
old = NXSEM_NO_MHOLDER;
new = _SCHED_GETTID();
}
else
{
old = atomic_read(val);
if (old < 1)
{
goto out;
}
new = old - 1;
}
if (atomic_try_cmpxchg_acquire(val, &old, new))
{
return OK;
}
}
out:
#else
UNUSED(mutex);
UNUSED(fastpath);
#endif
return nxsem_wait_slow(sem);