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:
parent
d8f241b29d
commit
fb14b54b83
3 changed files with 35 additions and 45 deletions
|
|
@ -151,24 +151,26 @@ int nxsem_post(FAR sem_t *sem)
|
|||
}
|
||||
# endif
|
||||
|
||||
if (fastpath)
|
||||
while (fastpath)
|
||||
{
|
||||
int32_t old;
|
||||
int32_t new;
|
||||
FAR atomic_t *val = mutex ? NXSEM_MHOLDER(sem) : NXSEM_COUNT(sem);
|
||||
int32_t old = atomic_read(val);
|
||||
int32_t new;
|
||||
|
||||
if (mutex)
|
||||
{
|
||||
old = _SCHED_GETTID();
|
||||
if (NXSEM_MBLOCKING(old))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
new = NXSEM_NO_MHOLDER;
|
||||
}
|
||||
else
|
||||
{
|
||||
old = atomic_read(val);
|
||||
|
||||
if (old < 0)
|
||||
{
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
|
||||
new = old + 1;
|
||||
|
|
@ -179,9 +181,6 @@ int nxsem_post(FAR sem_t *sem)
|
|||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
#else
|
||||
UNUSED(mutex);
|
||||
UNUSED(fastpath);
|
||||
|
|
|
|||
|
|
@ -146,43 +146,35 @@ int nxsem_trywait(FAR sem_t *sem)
|
|||
}
|
||||
# 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);
|
||||
int32_t old = atomic_read(val);
|
||||
int32_t new;
|
||||
|
||||
if (mutex)
|
||||
{
|
||||
old = NXSEM_NO_MHOLDER;
|
||||
if (old != NXSEM_NO_MHOLDER)
|
||||
{
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
new = _SCHED_GETTID();
|
||||
}
|
||||
else
|
||||
{
|
||||
old = atomic_read(val);
|
||||
if (old < 1)
|
||||
{
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
new = old - 1;
|
||||
}
|
||||
|
||||
do
|
||||
if (atomic_try_cmpxchg_acquire(val, &old, new))
|
||||
{
|
||||
if (!mutex)
|
||||
{
|
||||
if (old < 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
new = old - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
new = _SCHED_GETTID();
|
||||
}
|
||||
|
||||
ret = atomic_try_cmpxchg_acquire(NXSEM_MHOLDER(sem), &old, new);
|
||||
return OK;
|
||||
}
|
||||
while (!mutex && !ret);
|
||||
|
||||
return ret ? OK : -EAGAIN;
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -174,24 +174,26 @@ int nxsem_wait(FAR sem_t *sem)
|
|||
}
|
||||
# endif
|
||||
|
||||
if (fastpath)
|
||||
while (fastpath)
|
||||
{
|
||||
int32_t old;
|
||||
int32_t new;
|
||||
FAR atomic_t *val = mutex ? NXSEM_MHOLDER(sem) : NXSEM_COUNT(sem);
|
||||
int32_t old = atomic_read(val);
|
||||
int32_t new;
|
||||
|
||||
if (mutex)
|
||||
{
|
||||
old = NXSEM_NO_MHOLDER;
|
||||
if (old != NXSEM_NO_MHOLDER)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
new = _SCHED_GETTID();
|
||||
}
|
||||
else
|
||||
{
|
||||
old = atomic_read(val);
|
||||
|
||||
if (old < 1)
|
||||
{
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
|
||||
new = old - 1;
|
||||
|
|
@ -202,9 +204,6 @@ int nxsem_wait(FAR sem_t *sem)
|
|||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
#else
|
||||
UNUSED(mutex);
|
||||
UNUSED(fastpath);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue