A mutex records its holder as a task id in the low 31 bits of a word
whose top bit means "someone is blocked on this". The id was stored
without masking, so an id with its top bit set became a holder with the
blocking bit raised.
Task ids are normally small and positive, but not always.
nxsched_gettid() reports -ESRCH for a context that no longer maps to a
running task, and there is a window where that is exactly what the
running context is: nxtask_exit() marks the next task ready to run
while the dying task is still executing on its own stack, and only then
releases the TCB. Freeing the group inside that release takes and
drops the group's mutexes, so the lock stores 0xfffffffd and the unlock
compares 0x7ffffffd, which are not equal.
With assertions enabled the unlock trips its holder check, and every
exit of a process that frees memory panics. In a kernel build that is
every exit, so no program could be run twice, and running one at all
took the shell down with it. Without assertions the failure is silent:
the accidental blocking bit sends the unlock looking for a waiter that
never existed.
Encode the id the same way everywhere it is stored or compared, so that
a lock and an unlock from one context agree whatever the id's sign.
The masked forms of -1 and -2 would alias the "no holder" and "reset"
values, but nxsched_gettid() yields only valid ids and -ESRCH.
mm_lock() already sidesteps this window with a note that gettid() may
return -ESRCH during a context switch; this gives the generic mutex the
same footing rather than a second special case.
Test case, on the EIC7700 EVB, which is a kernel build with assertions:
nsh> hello
Hello, World!!
Before, that printed and then panicked in sem_post, taking the shell
with it, every time. After, five runs in a row complete and the shell
survives. ps over telnet still completes.
Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
Curernt implementation default semaphore max allowed value to SEM_VALUE_MAX.
In some cases, user may want to change this, so provide a function to do this: sem_setmaxvalue
Signed-off-by: Chengdong Wang <wangchengdong@lixiang.com>
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>
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 enables the mutex fast path for nxsem_wait, nxsem_trywait and nxsem_post also when
the priority inheritance is enabled.
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This puts the mutex support fully inside nxsem, allowing
locking the mutex and setting the holder with single atomic
operation.
This enables fast mutex locking from userspace, avoiding taking
critical_sections, which may be heavy in SMP and cleanup
of nxmutex library in the future.
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This reverts commit 300992203a to
fix a problem with `esp32-devkitc:blewifi`, which fails to boot up
if `CONFIG_DEBUG_ASSERTIONS=y`.
Introduced by https://github.com/apache/nuttx/pull/16176 with the
following description:
> The DEBUGASSERTS in nxsem_wait and nxsem_trywait are
non-functional, they don't check anything. These were broken in
previous commits.
The above statements are not valid. Originally, there was no
problem calling `nxsem_trywait` from the interrupt and the
`DEBUGASSERT` simply checked a corner case: if ran from the
interrupt context, the current (interrupted) task may be the idle
task. This case is allowed only if called from an interrupt and
that's what the original commit checks with:
```
DEBUGASSERT(!OSINIT_IDLELOOP() || !sched_idletask() ||
up_interrupt_context());
```
The DEBUGASSERTS in nxsem_wait and nxsem_trywait were non-functional, they
didn't check anything.
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
We should not access semaphore internals directly outside sched/semaphore.
Just read it via the NXSEM_COUNT macro provided.
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
This avoids unnecessary syscalls in memory protected builds, when mutex
lock/unlock can be done with only atomic counter access
Signed-off-by: Jukka Laitinen <jukka.laitinen@tii.ae>
Add sem_wait fast operations, use atomic to ensure
atomicity of semcount operations, and do not depend
on critical section.
Test with robot:
before modify:
nxmutex_lock cost: 78 ns
nxmutex_unlock cost: 82 ns
after modify:
nxmutex_lock cost: 28 ns
nxmutex_unlock cost: 14 ns
Signed-off-by: zhangyuan29 <zhangyuan29@xiaomi.com>
Most tools used for compliance and SBOM generation use SPDX identifiers
This change brings us a step closer to an easy SBOM generation.
Signed-off-by: Alin Jerpelea <alin.jerpelea@sony.com>
pointer comparison is unsigned, when returning -errno will be converted
to a large positive number, can not enter the error handling branch,
therefore, the error code is returned directly and the sem is returned
through the parameters.
Signed-off-by: zhanghongyu <zhanghongyu@xiaomi.com>
This moves all the public POSIX semaphore functions into libc and with
this most of the user-space logic is also moved; namely cancel point and
errno handling.
This also removes the need for the _SEM_XX macros used to differentiate
which API is used per user-/kernel mode. Such macros are henceforth
unnecessary.
1. Update all CMakeLists.txt to adapt to new layout
2. Fix cmake build break
3. Update all new file license
4. Fully compatible with current compilation environment(use configure.sh or cmake as you choose)
------------------
How to test
From within nuttx/. Configure:
cmake -B build -DBOARD_CONFIG=sim/nsh -GNinja
cmake -B build -DBOARD_CONFIG=sim:nsh -GNinja
cmake -B build -DBOARD_CONFIG=sabre-6quad/smp -GNinja
cmake -B build -DBOARD_CONFIG=lm3s6965-ek/qemu-flat -GNinja
(or full path in custom board) :
cmake -B build -DBOARD_CONFIG=$PWD/boards/sim/sim/sim/configs/nsh -GNinja
This uses ninja generator (install with sudo apt install ninja-build). To build:
$ cmake --build build
menuconfig:
$ cmake --build build -t menuconfig
--------------------------
2. cmake/build: reformat the cmake style by cmake-format
https://github.com/cheshirekow/cmake_format
$ pip install cmakelang
$ for i in `find -name CMakeLists.txt`;do cmake-format $i -o $i;done
$ for i in `find -name *\.cmake`;do cmake-format $i -o $i;done
Co-authored-by: Matias N <matias@protobits.dev>
Signed-off-by: chao an <anchao@xiaomi.com>
This PR is a modification that optimizes priority inheritance
for only one holder. After the above modifications are completed,
the mutex lock->unlock process that supports priority inheritance
can be optimized by 200 cycles.
Before modify: 2000 cycle
After modify: 1742 cycle
Signed-off-by: zhangyuan21 <zhangyuan21@xiaomi.com>
Add a list in TCB to track all semphores the task held, so we
can release all holders when exit, so nxsched_verify_tcb
is unnecessary.
Signed-off-by: Zeng Zhaoxiu <walker.zeng@transtekcorp.com>
Squashed commit of the following:
libs/libxx: Fix some confusing in naming. If the directory is called libxx, then the library must be libxx.a (unless perhaps LIBCXX is selected).
libs/: Fix paths in moved library directories.
libs: Brute force move of libc, libnx, and libxx to libs. Cannot yet build it in that configuration.