libc/semaphore: Use the while loop to handle the inerrupt correctly

If atomic_try_cmpxchg_xxxx runs on LL/SC architectures (e.g.ARMv7,
ARMv8, RISC-V), the weak CAS expands to a single LDREX/STREX pair.

If the CPU takes an IRQ/FIQ/SVC between the two instructions,
hardware performs an implicit CLREX and the following STREX returns
1, therefore atomic_try_cmpxchg_xxxx return failure even though
*addr* still holds the expected value.

So let's retry atomic_try_cmpxchg_xxxx in this case.

Signed-off-by: Xiang Xiao <xiaoxiang@xiaomi.com>
This commit is contained in:
Xiang Xiao
2025-06-22 03:03:59 +08:00
committed by Alan C. Assis
parent d8f241b29d
commit fb14b54b83
3 changed files with 35 additions and 45 deletions
+9 -10
View File
@@ -151,24 +151,26 @@ int nxsem_post(FAR sem_t *sem)
} }
# endif # endif
if (fastpath) while (fastpath)
{ {
int32_t old;
int32_t new;
FAR atomic_t *val = mutex ? NXSEM_MHOLDER(sem) : NXSEM_COUNT(sem); FAR atomic_t *val = mutex ? NXSEM_MHOLDER(sem) : NXSEM_COUNT(sem);
int32_t old = atomic_read(val);
int32_t new;
if (mutex) if (mutex)
{ {
old = _SCHED_GETTID(); if (NXSEM_MBLOCKING(old))
{
break;
}
new = NXSEM_NO_MHOLDER; new = NXSEM_NO_MHOLDER;
} }
else else
{ {
old = atomic_read(val);
if (old < 0) if (old < 0)
{ {
goto out; break;
} }
new = old + 1; new = old + 1;
@@ -179,9 +181,6 @@ int nxsem_post(FAR sem_t *sem)
return OK; return OK;
} }
} }
out:
#else #else
UNUSED(mutex); UNUSED(mutex);
UNUSED(fastpath); UNUSED(fastpath);
+13 -21
View File
@@ -146,43 +146,35 @@ int nxsem_trywait(FAR sem_t *sem)
} }
# endif # endif
if (fastpath) while (fastpath)
{ {
bool ret = false;
int32_t old;
int32_t new;
FAR atomic_t *val = mutex ? NXSEM_MHOLDER(sem) : NXSEM_COUNT(sem); FAR atomic_t *val = mutex ? NXSEM_MHOLDER(sem) : NXSEM_COUNT(sem);
int32_t old = atomic_read(val);
int32_t new;
if (mutex) if (mutex)
{ {
old = NXSEM_NO_MHOLDER; if (old != NXSEM_NO_MHOLDER)
{
return -EAGAIN;
}
new = _SCHED_GETTID();
} }
else else
{
old = atomic_read(val);
}
do
{
if (!mutex)
{ {
if (old < 1) if (old < 1)
{ {
break; return -EAGAIN;
} }
new = old - 1; new = old - 1;
} }
else
if (atomic_try_cmpxchg_acquire(val, &old, new))
{ {
new = _SCHED_GETTID(); return OK;
} }
ret = atomic_try_cmpxchg_acquire(NXSEM_MHOLDER(sem), &old, new);
}
while (!mutex && !ret);
return ret ? OK : -EAGAIN;
} }
#else #else
+9 -10
View File
@@ -174,24 +174,26 @@ int nxsem_wait(FAR sem_t *sem)
} }
# endif # endif
if (fastpath) while (fastpath)
{ {
int32_t old;
int32_t new;
FAR atomic_t *val = mutex ? NXSEM_MHOLDER(sem) : NXSEM_COUNT(sem); FAR atomic_t *val = mutex ? NXSEM_MHOLDER(sem) : NXSEM_COUNT(sem);
int32_t old = atomic_read(val);
int32_t new;
if (mutex) if (mutex)
{ {
old = NXSEM_NO_MHOLDER; if (old != NXSEM_NO_MHOLDER)
{
break;
}
new = _SCHED_GETTID(); new = _SCHED_GETTID();
} }
else else
{ {
old = atomic_read(val);
if (old < 1) if (old < 1)
{ {
goto out; break;
} }
new = old - 1; new = old - 1;
@@ -202,9 +204,6 @@ int nxsem_wait(FAR sem_t *sem)
return OK; return OK;
} }
} }
out:
#else #else
UNUSED(mutex); UNUSED(mutex);
UNUSED(fastpath); UNUSED(fastpath);