z_time_slice() computed z_time_slice_size(curr) to decide whether the
slice had expired, and then z_time_slice_reset() computed it a second
time to rearm the slice timeout. Cache the value instead: split the
rearm body into a slice_reset(slice_size) helper (z_time_slice_reset()
becomes a thin wrapper that still computes the size for its other
callers) and pass the already-known size from z_time_slice().
The size is still only computed when the slice has actually expired, so
the per-tick fast path is unchanged. In the CONFIG_TIMESLICE_PER_THREAD
case the expiry handler runs with the scheduler lock dropped and may
change the thread's slice configuration, so the cached value is
recomputed after the handler returns; behavior is therefore unchanged.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
The strncpy + NUL-termination + arch_thread_name_set() hook sequence
behind CONFIG_THREAD_NAME was duplicated in z_impl_k_thread_name_set()
and z_setup_new_thread(). Extract it into a single set_thread_name()
helper and call it from both places, removing the duplicated logic and
the risk of the two copies drifting apart.
The helper treats a NULL name as "clear the name" (writes an empty
string), matching the previous z_setup_new_thread() behavior; the
k_thread_name_set() path always passed a non-NULL string, so its
behavior is unchanged.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
z_impl_k_thread_stack_free() tested _THREAD_DUMMY and _THREAD_DEAD
with two separate z_is_thread_state_set() calls combined with a
logical OR. z_is_thread_state_set() returns (thread_state & state)
!= 0, so the two calls are equivalent to a single call with both
bits ORed into the mask. Collapse them into one call; this is
smaller and clearer with no change in behavior.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
The CPU object core type was registered through a dedicated SYS_INIT. Like
threads, CPUs have no statically defined instances to walk at boot: each
CPU links its own object core in z_init_cpu(). The boot init only
registered the type and its stats descriptor.
Use K_OBJ_TYPE_DEFINE_TYPE_ONLY() for the CPU type, dropping
init_cpu_obj_core_list() and its SYS_INIT. The type is still registered at
PRE_KERNEL_1 by the single object core init walk, before z_init_cpu(0)
runs during prepare_multithreading(), so ordering is unchanged. The kernel
system object keeps its own init, as it links the singleton _kernel object.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
Threads registered their object core type through a dedicated SYS_INIT.
Unlike the other object types they have no statically defined instances
to walk at boot: each thread links its own object core as it is created
in z_setup_new_thread(). The boot init therefore only registered the type
and its stats descriptor.
Add a K_OBJ_TYPE_DEFINE_TYPE_ONLY() variant that registers the type (and
optional stats descriptor) without walking a static object section, and
use it for threads. The type is still registered at PRE_KERNEL_1 via the
single object core init walk, before any thread is created, so ordering is
unchanged. Only the internal cpu/kernel system objects (which are not in
iterable sections) now remain outside the table.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
mem_slab was the one statically defined object type left out of the
object core registration table, because its boot-time init bundled two
unrelated concerns: building each slab's free block list (create_free_list,
mandatory functional init) and its object core duties (type init, stats
descriptor init, linking and per-slab stats registration).
Separate the two. The object core duties now go through the registration
table like every other object type, and the per-slab statistics buffer is
registered generically by the table walk: the descriptor optionally carries
the offset and size of an embedded stats buffer (only present under
CONFIG_OBJ_CORE_STATS), set via the new K_OBJ_TYPE_DEFINE_STATS() macro.
K_OBJ_TYPE_DEFINE() forwards to it with no per-object stats.
create_free_list stays as its own SYS_INIT: it is required whether or not
the object core framework is enabled (CONFIG_OBJ_CORE is off by default),
so it cannot move into the object-core-gated table walk. mem_slab.c is
linked only when slab APIs are used, so this init carries no extra
footprint for builds that do not use slabs.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
Each kernel object type that participates in the object core framework
previously supplied its own SYS_INIT routine to initialize its
k_obj_type and to walk its static-object linker section, linking each
object core. These routines were near-identical across 11 object types
and differed only in the type id, the object struct and the obj_core
offset.
Replace that per-type boilerplate with a declarative K_OBJ_TYPE_DEFINE()
macro that emits a const descriptor into a new iterable ROM section, and
walk those descriptors once from a single SYS_INIT in obj_core.c. The
descriptor captures the type storage, type id, obj_core offset, the
static object section bounds and the object stride, which is all the
shared loop needs to initialize and link every statically defined
object.
Converted: condvar, event, fifo, lifo, mailbox, msgq, mutex, pipe, sem,
stack and timer. The non-uniform initializers (thread, mem_slab and the
internal cpu/kernel objects) are left unchanged and will be dealt with
in followup commits.
Footprint on qemu_cortex_m3 (tests/kernel/obj_core/obj_core, all types
enabled): flash 32012 -> 30880 (-1132 B), RAM unchanged. With
CONFIG_OBJ_CORE disabled the image is byte-for-byte identical.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
sys_clock_announce() reports ticks elapsed since the previous announce. The
quantity that must stay in range is therefore the distance of the next
timeout from that announce, not its distance from "now" as next_timeout()
previously bounded. When an early timeout is repeatedly replaced by a later
one, announces are deferred and that distance can exceed the range even
though each set_timeout() delay was in range, which every driver has had to
defend against on its own.
Cap it in the core instead: SYS_CLOCK_MAX_WAIT becomes UINT32_MAX/2 (the
clamp, with the upper half of the range left as slack for a late announce)
and next_timeout() clamps the inter-announce distance to it. Drivers no
longer need to clamp for the announce range and only have to honour their
own cycle-count limits.
The core no longer emits K_TICKS_FOREVER; the reported delay is always
finite, saturating at SYS_CLOCK_MAX_WAIT. Drivers that stop the timer
entirely when idle now key off ticks == SYS_CLOCK_MAX_WAIT under
CONFIG_SYSTEM_CLOCK_SLOPPY_IDLE.
z_get_next_timeout_expiry() still reports to the idle and PM paths as a
signed int32_t. It keeps its K_TICKS_FOREVER default and adopts the
next_timeout() value only when that fits, so the unsigned cap can never
surface there as a negative number.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
The sys_clock_set_timeout(), sys_clock_announce() and
sys_clock_announce_locked() interfaces carry a number of ticks to be
scheduled or announced. Those ticks have no negative meaning, so a signed
argument is both wasteful and error prone: it invites incorrect handling in
drivers and it halves the range that sys_clock_announce() can represent.
Switch the tick argument of these interfaces, along with the internal
announce_remaining accounting, from int32_t to uint32_t. This is a
mechanical change: driver bodies perform plain arithmetic on the value and
are unaffected by the signedness, and the kernel never passes a negative
tick count. The freed sign bit doubles the representable announce range,
which a later change will use to move the announce range limit out of the
drivers and into the core.
One config is not strictly neutral: under CONFIG_TIMEOUT_64BIT,
K_TICKS_FOREVER is a 64-bit value that an unsigned 32-bit argument can no
longer compare equal to, so the K_TICKS_FOREVER tests in drivers stop
matching there. K_TICKS_FOREVER is a k_ticks_t concept and has no business
in this tick count interface; a follow-up removes it from the driver side
entirely, which closes this gap.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
Bringing the kernel/ sources into the Doxygen requirements-traceability
INPUT (for @satisfies links) surfaces a handful of latent documentation
warnings that would break the -W docs build. Fix them.
With these, the kernel/ tree is clean under doxygen 1.17.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
Lightweight write sanitizer for sys_heap. Uses
-fsanitize=kernel-address compiler instrumentation combined with a
per-heap shadow bitarray (one bit per granule) to detect buffer
overflows, underflows, and use-after-free on write accesses.
Ships its own lightweight sanitizer runtime (__asan_store* callbacks);
does not depend on an external ASAN library and supports debugging on
real embedded targets.
Instrumentation is opt-in per CMake target via
zephyr_target_enable_heap_kasan(), or per directory via
zephyr_heap_kasan_enable_directory(). Only writes are checked
(-asan-instrument-reads=0). Bulk-write library calls (memset,
memcpy, str*, printf family) are redirected to checked wrappers at
compile time via -Dfoo=__asan_foo, requiring no source changes in
application code.
Heap tracking is likewise opt-in: register each heap with
SYS_HEAP_KASAN_ENABLE() / K_HEAP_KASAN_ENABLE(), or enable
CONFIG_SYS_HEAP_KASAN_MALLOC / CONFIG_SYS_HEAP_KASAN_SYSTEM for the
common libc malloc and kernel system heaps.
Usage:
CONFIG_SYS_HEAP_KASAN=y
CONFIG_SYS_HEAP_KASAN_MALLOC=y # auto-track malloc/free
CONFIG_SYS_HEAP_KASAN_SYSTEM=y # auto-track k_malloc/k_free
# Instrument all sources of <target> (CMakeLists.txt)
zephyr_target_enable_heap_kasan(app)
# Or instrument sources under <dir>
zephyr_heap_kasan_enable_directory(src/mymodule)
/* Opt-in tracking for a custom heap */
K_HEAP_DEFINE(my_heap, 4096);
K_HEAP_KASAN_ENABLE(my_heap, 4096);
Signed-off-by: Jinming Zhao <jinmzhao@qti.qualcomm.com>
Some private symbol names were widely duplicated throughout the kernel
such as lock and handle_poll_event. This arguably made the kernel less
readable as the locality of the name lock is highly confusing.
Rename all compilation unit locks to match their usage (e.g.
mutex_lock). Improving readability.
Furthermore, by deduplicating these symbols we enable potential
amalgamation builds of the kernel where all C files are merged
into one large C file or compliation unit allowing for better
compiler visibility and optimization.
Signed-off-by: Tom Burdick <thomas.burdick@infineon.com>
The `thread_id` member should be used instead, because this also works for
work queues which run on a thread, that was not started by the work queue
implementation.
Signed-off-by: Michael Zimmermann <michael.zimmermann@sevenlab.de>
The `thread` field is not initialized, if it's being animated via
k_work_queue_run instead of k_work_queue_start.
Signed-off-by: Michael Zimmermann <michael.zimmermann@sevenlab.de>
z_unpend_all() and unpend_all() skipped readying a woken thread when
z_try_abort_thread_timeout() returned -EAGAIN, on the assumption that
an in-flight timeout handler on another CPU would ready the thread
itself once the scheduler lock was dropped.
That assumption no longer holds. z_thread_timeout() was changed to bail
out when it observes the timeout has been marked superseded, and
z_try_abort_thread_timeout() sets exactly that superseded mark on the
-EAGAIN path. So on SMP, when a waiter's timeout fires on one CPU at
the same moment *unpend_all() processes it on another:
- *unpend_all() unpends the thread and, seeing -EAGAIN, does NOT
ready it.
- the in-flight z_thread_timeout() finds the timeout superseded and
bails, so it does NOT ready it either.
The thread ends up off every wait queue and on no run queue: orphaned,
with no remaining wake source. (k_heap / sys_mempool waiters with a
finite timeout are the reachable callers.)
Fix: ready the thread unconditionally after aborting its timeout, the
same idiom z_unpend_first_thread_locked() and kernel/events.c already
use. The abort still marks the in-flight handler superseded so it bails
and cannot double-wake, and ready_thread() is idempotent regardless.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
z_fatal_error() locks interrupts before calling coredump(). Some
backends (e.g. a UDP socket backend) need IRQ delivery to complete
their TX path. Introduce two weak arch hooks that bracket the
coredump() call:
arch_coredump_fatal_irq_unlock(key, cookie) -- re-enables IRQs
arch_coredump_fatal_irq_lock(cookie) -- restores the mask
Both are declared in kernel_arch_interface.h under
CONFIG_DEBUG_COREDUMP_FATAL_UNLOCK_IRQS. The default weak
implementations in subsys/debug/coredump/ delegate to the standard
arch_irq_unlock()/arch_irq_lock() pair. Architectures where exception
entry independently masks IRQs (e.g. ARM64 DAIF.I) must override them.
Signed-off-by: Appana Durga Kedareswara rao <appana.durga.kedareswara.rao@amd.com>
Inlining z_sched_wake() gives the thread_metric synchronization
benchmark an almost 40% boost. This restores it to its previous
levels when k_sem_give() was using z_unpend_first_thread().
Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
The comment made it seem like we do two passes on the "threads that need
wakeup" list: a first one to unpend and another to ready. In reality,
we do only one path and perform both operations at one using
`z_sched_wake_thread_locked()`.
Update the comment explaining the algorithm so it reflects more
accurately what the code actually does.
Signed-off-by: Mathieu Choplain <mathieu.choplain-ext@st.com>
k_thread_runtime_stack_safety_threshold_check() passed the thread's
unused stack threshold directly as the scan window size to
z_stack_space_get(). When CONFIG_STACK_SENTINEL is enabled,
z_stack_space_get() reserves the first 4 bytes of the stack buffer for
the sentinel and shrinks its scan window by that amount. As a result a
fully unused window reported "threshold - 4" unused bytes, which is
always less than the threshold, so the handler fired on every call
regardless of the actual unused stack space, making the abbreviated
check useless on sentinel-based platforms.
Grow the requested scan window by the sentinel reservation so that up to
"threshold" bytes of the usable stack are actually examined. The
firing condition is unchanged on platforms without the sentinel.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
The runtime stack safety threshold syscalls were declared in kernel.h as
k_thread_runtime_stack_unused_threshold_{pct_set,set,get}, but their
implementations and verifiers in thread.c were named with an extra
"safety_" infix (k_thread_runtime_stack_safety_unused_threshold_*). Since
the __syscall declarations drive code generation, the generated _mrsh.c
files and the expected z_impl_/z_vrfy_ symbols never matched the
definitions, so the feature failed to build/link with
CONFIG_THREAD_RUNTIME_STACK_SAFETY and CONFIG_USERSPACE enabled.
Rename the implementations and verifiers to match the public API names
and fix the corresponding generated-header includes.
Also remove a duplicate, malformed z_vrfy for the threshold "get"
syscall that returned int instead of size_t and called the "set"
implementation with the wrong number of arguments. The correct verifier
is already defined alongside the other threshold syscalls.
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
Clang's RISC-V backend rejects the -mstack-protector-guard=tls family of
flags used to anchor the stack canary to the TLS base register. With those
flags stripped, Clang falls back to an absolute reference to the
thread-local __stack_chk_guard symbol, which resolves to address 0. The
build compiles cleanly but the resulting image faults in the prologue of
the first canary-instrumented function (vprintk during early boot, before
the console is up), then re-faults forever in the trap handler, producing
no output at all.
Guard STACK_CANARIES_TLS so it cannot be selected for Clang on RISC-V,
falling back to the global canary which Clang handles correctly, and
exclude the kernel.memory_protection.stackprot_tls test from zephyr/llvm.
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
CONFIG_LINKER_USE_PINNED_SECTION is the second half of the selective
kernel-pinning model removed in issue #108773. With the kernel image
now always resident at boot (previous commit), the __pinned_*
attribute family is a no-op: every page they would have segregated is
already pinned by z_mem_manage_init()'s whole-image loop, so the
tagging contract neither adds safety nor remains maintainable.
Drop it.
Mechanical removals:
* All ~219 in-tree uses of __pinned_text, __pinned_rodata,
__pinned_data, __pinned_bss, __pinned_noinit, and __pinned_func
across arch/x86, drivers/interrupt_controller, drivers/timer,
arch/common, kernel, lib/libc, subsys/portability/posix, tests, and
the syscall code generator (scripts/build/gen_syscalls.py).
* The assembly aliases PINNED_TEXT/RODATA/DATA/BSS/NOINIT used in
arch/x86/core/ia32/*.S and drivers/interrupt_controller/
intc_loapic_spurious.S become plain TEXT/RODATA/DATA/BSS/NOINIT.
* K_KERNEL_PINNED_STACK_DEFINE, K_KERNEL_PINNED_STACK_ARRAY_DEFINE,
K_KERNEL_PINNED_STACK_ARRAY_DECLARE, K_THREAD_PINNED_STACK_DEFINE,
and K_THREAD_PINNED_STACK_ARRAY_DEFINE are removed. The few
in-tree callers (kernel/init.c, arch/arm/core/cortex_a_r/smp.c,
arch/arm64/core/fatal.c, arch/rx/core/prep_c.c,
arch/x86/core/prep_c.c, kernel/include/kernel_internal.h,
tests/bluetooth/hci_uart_async) move to the corresponding
non-pinned macros.
Machinery removals:
* Kconfig.zephyr drops CONFIG_LINKER_USE_PINNED_SECTION.
qemu_x86_tiny and qemu_x86_atom_virt drop their =y overrides.
* include/zephyr/linker/section_tags.h drops the __pinned_* macro
definitions (both arms). __isr collapses to an empty macro since
its only purpose was to alias __pinned_func.
* include/zephyr/linker/sections.h drops PINNED_TEXT_SECTION_NAME,
PINNED_BSS_SECTION_NAME, etc. and the bare PINNED_TEXT/RODATA/etc.
forwarders, plus the _APP_SMEM_PINNED_SECTION_NAME constant.
* include/zephyr/linker/linker-defs.h drops the lnkr_pinned_*
externs, the _app_smem_pinned_* externs, and the lnkr_is_pinned()
/ lnkr_is_region_pinned() inline helpers.
* include/zephyr/linker/utils.h drops the lnkr_pinned_rodata branch
in linker_is_in_rodata().
* include/zephyr/linker/app_smem_pinned{,_aligned,_unaligned}.ld
are deleted; cmake/linker/ld/target_configure.cmake stops
configuring them.
* boards/qemu/x86/qemu_x86_tiny.ld and
include/zephyr/arch/x86/ia32/linker.ld drop their pinned-section
blocks and the now-redundant #ifndef CONFIG_LINKER_USE_PINNED_SECTION
conditionals throughout the body. The
LIB_KERNEL_IN_SECT / LIB_ARCH_X86_IN_SECT / LIB_ZEPHYR_IN_SECT /
LIB_C_IN_SECT / LIB_DRIVERS_IN_SECT / LIB_SUBSYS_LOGGING_IN_SECT /
LIB_ZEPHYR_OBJECT_FILE_IN_SECT / ZEPHYR_KERNEL_FUNCS_IN_SECT macros
in qemu_x86_tiny.ld are deleted; they existed only to feed the
pinned text/rodata/data/bss/noinit sections.
* kernel/mmu.c drops the mark_linker_section_pinned(lnkr_pinned_start,
...) call. The mark_linker_section_pinned() helper survives but is
now gated only on CONFIG_LINKER_USE_BOOT_SECTION.
* arch/common/init.c and include/zephyr/arch/common/init.h drop
arch_bss_zero_pinned(); arch/x86/core/ia32/crt0.S drops the call
to it.
* arch/x86/core/userspace.c drops the eager k_mem_page_in() of the
thread's privileged stack on user-mode entry. With the kernel
image fully resident the stack is already mapped.
* arch/x86/gen_mmu.py drops map_region("lnkr_pinned") and the
set_region_perms() calls for lnkr_pinned_text / lnkr_pinned_rodata.
* CMakeLists.txt drops the LINKER_USE_PINNED_SECTION block that
generated APP_SMEM_PINNED_* variables and the
pinned_partitions target property feeding gen_app_partitions.py.
cmake/modules/extensions.cmake removes the PINNED_RODATA /
PINNED_RAM_SECTIONS / PINNED_DATA_SECTIONS zephyr_linker_sources()
location keywords and their snippet files.
scripts/build/gen_app_partitions.py drops --pinoutput /
--pinpartitions arguments and the pinned-output branch.
subsys/testsuite/coverage/CMakeLists.txt drops its
CONFIG_DEMAND_PAGING-conditional fork.
* scripts/build/gen_kobject_list.py drops the
app_smem_pinned_start / _end fallback for kobject placement
validation.
* tests/arch/x86/pagetables and tests/kernel/mem_protect/userspace
drop their lnkr_pinned_text / lnkr_pinned_rodata branches.
* include/zephyr/arch/x86/ia32/arch.h folds IRQSTUBS_TEXT_SECTION
to the unconditional ".text.irqstubs" form.
* tests/subsys/llext/src/syscalls_ext.c drops a stale comment about
syscalls landing in .pinned_text.
Targeted retentions:
* arch/x86/core/bootargs.c keeps multiboot_cmdline and efi_bootargs
in .noinit (was __pinned_noinit, which decayed to __noinit when
LINKER_USE_PINNED_SECTION was unset). The multiboot and zefi loader
paths write these buffers before Zephyr's BSS-zero step, so
zeroing them at boot loses the cmdline.
* arch/x86/core/ia32/fatal.c keeps _df_esf and _df_stack in .noinit.
They are scratch space written by the double-fault handler and have
no zero-init requirement; keeping them in .noinit also preserves
the historical post-noinit alignment that gen_mmu.py relies on
(z_mapped_size is computed before CMake-injected iterable sections
are appended to the linker script, so the post-noinit page padding
is what keeps those sections within the mapped region).
* include/zephyr/arch/x86/ia32/syscall.h and
include/zephyr/arch/x86/arch.h wrap the per-arch
arch_syscall_invoke* / arch_is_user_context / arch_k_cycle_get_*
implementations in @cond INTERNAL_HIDDEN. The public Doxygen
contract lives on the prototypes in
include/zephyr/arch/arch_interface.h; the per-arch implementations
are internal. Without this, removing the __pinned_func attribute
exposes the implementations to the doxygen-coverage delta check
as 10 newly-undocumented APIs.
Documentation updates are deferred to a separate commit.
Issue: #108773
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
With qemu_x86_tiny moved off the =n side of this knob in the previous
commit, no in-tree configuration sets
CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT=n anymore. The mode it
selected is also unsafe by construction (issue #108773), so there is
nothing to deprecate -- drop the Kconfig symbol and every #ifdef on
it.
Consequences:
* z_mem_manage_init() pins the whole Zephyr image unconditionally and
no longer calls arch_bss_zero() after demand-paging init. The
pinning loop's TODO about "we will need linker regions for a subset
of kernel code/data pages which are pinned in memory and may not be
evicted" is replaced with a brief note that the kernel image is
always resident now and that pageable kernel regions go through
__ondemand_*.
* arch/x86/core/ia32/crt0.S always calls arch_bss_zero() once
arch_bss_zero_boot and arch_bss_zero_pinned have run.
* kernel/kheap.c and kernel/userspace/userspace.c drop the
pre-kernel/post-kernel "skip non-pinned" dance and zero/init each
heap and app-shmem partition unconditionally at PRE_KERNEL_1.
* arch/x86/core/userspace.c drops the eager k_mem_page_in() of the
thread's privileged stack before dropping to user mode -- with the
full kernel image resident the stack is already mapped.
* arch/x86/gen_mmu.py always maps the Zephyr image with FLAG_P set
(and lnkr_boot_* / lnkr_pinned_* regions just inherit that).
* CMakeLists.txt no longer force-pins z_libc_partition into
pinned_partitions for app_smem.
* The EVICTION_LRU gate
"depends on LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT" goes away;
LRU is now safe by construction on any DEMAND_PAGING board and
becomes the default whenever ARCH_SUPPORTS_EVICTION_TRACKING.
* DEMAND_PAGING_PAGE_FRAMES_RESERVE loses its conditional default of
32 frames; the new model needs no reserve.
* boards/qemu/x86/qemu_x86_tiny.ld drops the FLASH MEMORY region and
the flash_load_offset block that arranged the demand-paged
generic-section layout. boards/qemu/x86/board.cmake drops the
8 MB-RAM bump and the --map flash gen_mmu argument that paired with
that mode.
* tests/arch/x86/pagetables and tests/kernel/fatal/exception drop the
code paths that were guarded on =n.
* tests/kernel/mem_protect/demand_paging/mem_map.lru replaces its
CONFIG_LINKER_GENERIC_SECTIONS_PRESENT_AT_BOOT=y override with an
explicit CONFIG_EVICTION_LRU=y, since the symbol it relied on is
gone.
The __pinned_* tagging convention still expands to its actual linker
sections under CONFIG_LINKER_USE_PINNED_SECTION; that symbol and the
~219 in-tree __pinned_* annotations are cleaned up in the following
commit.
Issue: #108773
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
Move EXECUTE_XOR_WRITE back into userspace and update the comment
to reflect that it only applies to memory partitions.
PMP_DATA_EXECUTION_PREVENTION is now independent from it and no
longer a requirement.
For full protection both options should be enabled. Otherwise,
some data areas my be left executable and writable at the same
time.
Signed-off-by: Christoph Busold <cbusold@qti.qualcomm.com>
CONFIG_EXECUTE_XOR_WRITE is a basic countermeasure to prevent code
injection attacks by making data non-executable. This can be done
on RISC-V with PMP by removing the executable permission.
Since PMP slots are statically prioritized, we can add a region
covering the whole address space into the last register giving
only read-write access. This will be overridden by any other
configured register with lower index so that the code region
remains executable.
In order to make this register apply to kernel threads in M mode,
it needs to be locked, but this means we cannot remove it anymore.
For CONFIG_USERSPACE we therefore need to reserve another register
so that we can add another address space-wide region with higher
priority without any permission to override the last one and limit
user threads to their assigned regions. This needs to be removed
when switching from user to kernel threads, which is done in the
new function z_riscv_pmp_usermode_disable.
This feature simplifies CONFIG_PMP_KERNEL_MODE_DYNAMIC because we
already have a catch-all register for kernel threads.
Does not work with CONFIG_CODE_DATA_RELOCATION for now and requires
PMP region locking.
Signed-off-by: Christoph Busold <cbusold@qti.qualcomm.com>
thread_obj_validate()'s default case passed the (non-zero) error code
`ret` straight to K_SYSCALL_VERIFY_MSG(), which verifies its argument is
true. A non-zero `ret` therefore reads as "verified OK", so K_OOPS()
never raised and control fell through to CODE_UNREACHABLE. With GCC this
path isn't normally reached and __builtin_unreachable() is a no-op; with
Clang it traps (unimp), turning an access-denied into an illegal
instruction. Verify `ret == 0` so the oops is actually raised.
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
Re-implementation of the fix originally proposed as PR #109426 on
top of the z_try_abort_timeout() infrastructure.
When a dynamically allocated k_timer's reference count drops to
zero its storage is about to be freed. If the timer's expiration
handler is in flight on another CPU at this moment, it will
dereference the freed memory.
Introduce k_timer_cleanup(): cancels the timeout and waits for any
in-flight handler to complete. Unlike k_timer_stop() it does not
run the user stop_fn nor wake pending threads -- the caller is
about to drop the storage and there is no further consumer. The
retry-on-EAGAIN loop around z_try_abort_timeout() guarantees that
when this returns 0 the handler has fully run; no in-band sentinel
is involved.
unref_check() in kernel/userspace/userspace.c calls
k_timer_cleanup() for K_OBJ_TIMER, guarded by K_OBJ_FLAG_INITIALIZED
(z_waitq_head() on an uninitialized dnode would otherwise read
garbage).
Add sys_port_trace_k_timer_cleanup_{enter,exit} hooks across the
tracing backends (default no-op).
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
The only reader was z_is_aborted_thread_timeout() in kernel/sleep.c,
used to distinguish a normal timeout-driven wakeup from one caused by
k_wakeup(). That distinction can be made entirely from the time
remaining: a normal wakeup leaves left_ticks <= 0, while an early
k_wakeup() leaves a positive remainder. The signed_left > 0 check
that already follows handles both cases correctly. The
z_is_aborted_thread_timeout() check was an early-return optimization
that the time computation makes redundant.
Drop the early-return in z_tick_sleep(), remove z_is_aborted_timeout(),
z_is_aborted_thread_timeout(), and the TIMEOUT_DTICKS_ABORTED macro.
Stop writing dticks = ABORTED in z_try_abort_timeout()'s linked-removal
path; the same-CPU IRQ branch is simplified to a flat -EINVAL fall-
through (the comment is moved to the cross-CPU/-EAGAIN side which is
the only case the caller needs to distinguish).
After this commit, dticks is purely a queue-management delta; there
are no more in-band sentinel values.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
With every caller now using z_try_abort_timeout() and every handler
relying on subsystem-local wake-ownership flags (queue->finished,
K_WORK_DELAYED_BIT, poller.is_polling, killed/pended_on for threads)
rather than the dticks-cancel check, the in-band cancel mechanism is
dead code. Remove it:
- z_abort_timeout(): no callers; remove the function definition
in kernel/timeout.c and the declaration in kernel/include/timeout_q.h.
- z_is_timeout_handler_canceled(): no callers (handlers no longer
bail on dticks); remove.
- TIMEOUT_DTICKS_ANNOUNCING: nothing reads it; remove the macro and
the corresponding t->dticks = ANNOUNCING write in
sys_clock_announce_locked()'s dispatch loop.
TIMEOUT_DTICKS_ABORTED stays. z_is_aborted_timeout() (used by
kernel/sleep.c via z_is_aborted_thread_timeout to distinguish a
k_wakeup'd thread from one that timed out) reads it, and
z_try_abort_timeout() still writes it on the linked-removal and
the same-CPU IRQ best-effort paths.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
Migrate work.c's two abort sites away from z_abort_timeout() and the
dticks-cancel mechanism.
Work queue timeout monitor (CONFIG_WORKQUEUE_WORK_TIMEOUT):
work_timeout_stop_locked() uses a best-effort (void)
z_try_abort_timeout() -- it does not wait for an in-flight handler.
That abort flags the in-flight timeout superseded, and
work_timeout_handler() bails on it via z_timeout_inflight_superseded(),
in addition to the existing queue->finished check.
Both checks are required. queue->finished alone is insufficient:
if the work thread completes the item and starts a new one before
this handler wins <lock>, finished is reset to false and the stale
handler would abort the wrong (newly-started) worker. The superseded
flag is what distinguishes "this timeout was aborted" from "a new
item is being monitored". This restores, in the new mechanism, the
cancellation guarantee that z_is_timeout_handler_canceled() provided
on main.
Delayable work (work_timeout / unschedule_locked):
work_timeout() drops the z_is_timeout_handler_canceled check and
relies on K_WORK_DELAYED_BIT, the existing wake-ownership flag:
whichever side -- this handler or unschedule_locked() -- atomically
clears it via flag_test_and_clear() first owns the outcome; the
other observes the cleared bit and bails. This is sufficient here
(no superseded check needed) because unschedule_locked() waits:
unschedule_locked() takes the caller's sched-lock key as a pointer
and, on the success path, waits for any in-flight handler to fully
complete before returning true. This closes a pre-existing UAF
window: when unschedule_locked() returned true with the old
z_abort_timeout(), the handler could still be about to run
(blocked on work.c::lock while we held it), and would dereference
work->flags after the caller released the lock. If a user-space
caller freed dwork between k_work_cancel_delayable() returning
and the handler bailing, the read raced with the free. The wait
also serializes against k_work_schedule_for_queue() re-arming the
same dwork for a new schedule -- without it, the old handler could
unblock after the re-arm and erroneously submit against the new
setup.
cancel_delayable_async_locked() and the three callers of
unschedule_locked() (cancel_delayable_async_locked,
k_work_reschedule_for_queue, k_work_flush_delayable) forward the
key pointer through, and the two callers of
cancel_delayable_async_locked (k_work_cancel_delayable,
k_work_cancel_delayable_sync) pass &key.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
triggered_work_expiration_handler and signal_triggered_work /
triggered_work_cancel both want to take a k_work_poll item from
"waiting on event" to "submitted to work queue". Pre-1b8c7a3 the
dticks-cancel check in the handler made it bail when the cancel
side had aborted the timeout; without it, the in-flight handler
could submit the work twice and overwrite poll_result.
Use poller.is_polling as the wake-ownership flag. signal_poll_event
already clears it after a successful signal; the migration makes
signal_triggered_work() and triggered_work_cancel() clear it BEFORE
the abort, and adds a check at handler entry so the loser bails.
All under poll.c::lock, so the flip is atomic between the three
sides.
z_abort_timeout() is replaced by a best-effort (void)
z_try_abort_timeout() at the signal_triggered_work site -- a racing
in-flight handler observes is_polling=false and returns without
doing work.
triggered_work_cancel() additionally waits for any in-flight handler
to fully complete before returning success. This closes a pre-existing
UAF window: when cancel returned 0, the handler could still be about
to run (blocked on poll.c::lock while we held it), and would
dereference work->poller.is_polling after the caller released the
lock. If a user-space caller freed `work` between k_work_poll_cancel()
returning and the handler bailing, the read raced with the free. The
same wait also serializes against k_work_poll_submit_to_queue()
re-arming the same `work` for a new poll: without it, the old
handler could unblock after the re-arm flipped is_polling back to
true and erroneously act on the new setup.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
z_time_slice_reset() calls z_abort_timeout() to cancel the previous
slice timeout before scheduling the next. The slice_timeout handler
only sets a per-CPU flag and flags an IPI -- it does not take
_sched_spinlock or dereference thread storage -- so a best-effort
(void) z_try_abort_timeout() is sufficient: a racing in-flight
handler sets slice_expired[cpu], which the trailing
"slice_expired[cpu] = false" assignment in z_time_slice_reset()
overwrites if our caller cares; if the handler runs after the clear,
the next dispatch picks up the (intentional) "expired" state and
rearms. No correctness concern either way.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
With every caller of z_abort_thread_timeout() now migrated to
z_try_abort_thread_timeout() (sched.c, thread.c, scheduler.c,
events.c, pipe.c) or to z_unpend_first_thread_locked() (sem.c,
mutex.c, mem_slab.c, stack.c, condvar.c, msg_q.c, queue.c, futex.c),
remove the inline wrapper (and !CONFIG_SYS_CLOCK_EXISTS stub) for
z_abort_thread_timeout().
z_thread_timeout() still needs a cancellation check, but it no longer
relies on the dticks=ANNOUNCING sentinel: switch it to
z_timeout_inflight_superseded(). The check is still required, and for
the same reason 1b8c7a3 added it. A concurrent waker on another CPU
(e.g. a sem give via z_unpend_first_thread_locked()) can unpend and
ready the thread while this timeout's handler is blocked on
_sched_spinlock; the thread may then run and re-pend on a different
object -- possibly with no timeout (K_FOREVER). The waker aborts this
timeout, which flags it superseded, and z_thread_timeout() bails on
that flag so it does not wake the thread from its new wait. The
atomic wake-under-_sched_spinlock closes the swap_retval window; the
superseded check closes this re-pend window.
The remaining TIMEOUT_DTICKS_ANNOUNCING sentinel and
z_is_timeout_handler_canceled() helper still have other users
(kernel/timer.c, kernel/poll.c, kernel/work.c) and are removed in the
later cleanup commit once those subsystems have been migrated as well.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
Replace z_unpend_first_thread() with z_unpend_first_thread_locked() and
migrate every caller across the kernel. The old function dropped the
scheduler spinlock before returning, exposing a race window between
its caller's "arch_thread_return_value_set + z_ready_thread" pair and
a still-in-flight timeout handler that could ready the thread first --
the woken thread might then run on another CPU and see an uninitialized
swap_retval. Pre-1b8c7a3 the dticks-cancel check made the handler bail;
here we fix it cleanly by requiring the caller to hold _sched_spinlock
across the entire wake, so the handler is blocked for the duration and
runs as a no-op afterwards.
z_unpend_first_thread_locked() requires the caller to be inside a
locked region and must be paired with z_sched_ready_locked() (and
whatever return-value setup is needed) under the same lock acquisition.
Sites migrated:
Simple "set retval [+ swap_data] and ready" callers use the existing
z_sched_wake() convenience wrapper, refactored to use the new
helper internally:
sem (give, reset), mem_slab (free), stack (push),
condvar (signal, broadcast), msgq (purge),
queue (cancel_wait, queue_insert, append_list),
futex (wake).
Sites that need additional setup on the woken thread use
LOCK_SCHED_SPINLOCK + z_unpend_first_thread_locked() + custom wake:
mutex (unlock -- needs the thread reference to track new owner),
msgq put / get (needs memcpy into the receiver's swap_data
buffer before the return value is set).
The dticks-cancel check in z_thread_timeout() is left in place; it is
no longer load-bearing once z_abort_thread_timeout() has no callers,
and is removed in the next commit.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
Migrate scheduler-internal callers of z_abort_thread_timeout() to the
new z_try_abort_thread_timeout(). This covers the abort sites in
sched.c, thread.c, scheduler.c (z_sched_wake), events.c, and pipe.c.
The patterns used:
z_unpend_thread (sched.c) retries on -EAGAIN: if the timeout
handler is in flight on another CPU, drop _sched_spinlock so the
handler can run to completion and retry. This preserves 1b8c7a3's
unpend+abort atomicity from the caller's perspective.
halt_thread (sched.c) takes the caller's sched-lock key as a pointer
so its direct abort on the dying thread can retry on -EAGAIN.
Waiting for the handler is mandatory: a caller may free the thread's
storage as soon as halt_thread() returns, and without waiting, the
still-in-flight handler would later dereference freed memory.
_THREAD_DEAD is set before the abort, so the handler bails via the
killed check in z_sched_wake_thread_locked().
For next_up() (the scheduler-context caller), the key is not cleanly
available: K_SPINLOCK in z_get_next_switch_handle and do_swap's
(void)k_spin_lock both discard it. halt_thread is invoked on
_current with NULL key and no abort is performed -- _current is
running, so its base.timeout cannot be linked. The gap is closed at
the other end: z_thread_halt() spins on z_try_abort_thread_timeout()
outside any lock after the halt-queue wait completes, before
returning to the caller of k_thread_abort().
z_unpend_all_locked / unpend_all (sched.c) skip the local
ready_thread() on -EAGAIN and let the still-blocked handler ready
the thread when _sched_spinlock drops. The threads being woken are
not freed, so no UAF risk; end state is identical.
z_impl_k_wakeup (thread.c), z_sched_wake (scheduler.c) and
event_walk_op (events.c) perform the wake entirely under
_sched_spinlock, so a (void) abort is race-free -- a racing in-flight
handler is blocked on the same lock during the wake.
copy_to_pending_readers (pipe.c) is restructured to also wake the
reader under the scheduler lock instead of after it, so the
return-value set, unpend, abort, and ready all happen atomically.
The dticks-cancel check in z_thread_timeout() is preserved for now
because other callers (sem.c, mutex.c, ... via z_unpend_first_thread())
still use z_abort_thread_timeout() and rely on it for race protection.
A follow-up commit migrates those, and a final commit drops the
cancel check and removes z_abort_thread_timeout() itself.
Add z_try_abort_thread_timeout() as an inline wrapper.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
Switch z_impl_k_timer_start() and z_impl_k_timer_stop() to the new
z_try_abort_timeout() interface.
Neither waits for an in-flight handler. When z_try_abort_timeout()
returns non-zero (the timeout was not on the queue), the handler is
either inactive or dispatching on another CPU; in the latter case it
has been flagged superseded and will bail at its entry check. This
matches the best-effort behaviour of the legacy z_abort_timeout():
on main, a cross-CPU stop set dticks=ABORTED and returned without
waiting, and the handler bailed on the sentinel. The superseded bit
now carries that signal.
Not waiting is also required for correctness: a k_timer expiry_fn
runs arbitrary user code, which may block on the very CPU that is
trying to stop the timer (e.g. k_thread_abort() of a thread running
there). A mandatory wait-for-handler in k_timer_stop()/start() would
deadlock that case; the only caller that must wait is k_timer_cleanup()
(about to free the storage), which keeps its retry loop.
k_timer_start: the lock encapsulation around abort + add is preserved
(it serializes concurrent k_timer_start on the same timer). The re-arm
re-links the node, which makes a not-yet-committed handler bail via
the sys_dnode_is_linked check too.
k_timer_stop: a non-zero return means "nothing on the queue to stop",
so stop_fn and the wait_q wake run only when the timeout was actually
dequeued (return 0).
z_timer_expiration_handler() drops the z_is_timeout_handler_canceled
check and bails on sys_dnode_is_linked (a higher-priority interrupt
between sys_clock_announce()'s unlock and the handler taking
timer.c::lock can re-link the timeout via k_timer_start) or on
z_timeout_inflight_superseded() (the timeout was aborted while
dispatching). Skipping avoids a double expiry and the periodic
restart asserting in z_add_timeout() on an already-linked node.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
When z_try_abort_timeout() finds the target timeout already popped
from the queue and in flight (its handler dispatching), the abort
cannot remove anything from the queue. The handler is about to run
(or is running) the timeout's callback; the aborter needs a way to
tell it "you were aborted, skip your side effects". main carried that
signal in the per-timeout dticks=ABORTED sentinel, which any CPU
could write under timeout_lock and the handler checked at entry via
z_is_timeout_handler_canceled(). Later commits in this series remove
the dticks-cancel mechanism, so the signal needs a new home.
Encode it in the low bit of the file-local inflight_timeout pointer
(struct _timeout is pointer-aligned, so bit 0 is free):
inflight_timeout == NULL no handler in flight
inflight_timeout == t handler in flight, not superseded
inflight_timeout == t | 1 handler in flight, superseded
z_try_abort_timeout() sets the bit whenever the target is the
in-flight timeout -- on the announcing CPU (same-CPU IRQ that
preempted the dispatch, or a stop after a re-arm) and on another CPU
racing the handler.
A handler with non-idempotent side effects (currently only k_timer's
expiry_fn) checks z_timeout_inflight_superseded() at entry and bails
if set. Idempotent handlers (z_thread_timeout, work, poll, ...)
tolerate the race and don't need the check.
The bit is a best-effort signal, not a barrier: an aborter that sets
it after the handler has passed its check has no effect (the handler
already committed), exactly as the dticks sentinel behaved on main.
The -EAGAIN return for the cross-CPU case is a separate mechanism,
used only by callers that must wait for the handler to fully complete
(e.g. before freeing the timeout's storage); they spin, while
best-effort callers ignore -EAGAIN and rely on the bit.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
Add an `inflight_timeout` pointer in the timeout subsystem, set by
sys_clock_announce_locked() under timeout_lock before a handler is
dispatched and cleared after the handler returns. The single-announcer
SMP invariant (only one CPU is in the dispatch loop at a time) means a
single global pointer suffices, mirroring announcing_cpu.
Add a new abort function z_try_abort_timeout() that uses this pointer
to detect "popped from the queue but handler not yet finished" without
relying on the in-band dticks == ANNOUNCING sentinel that survives
across the timeout's storage being freed only by coincidence.
The new function returns -EAGAIN when a handler is in flight on
another CPU, signalling that the caller must drop any outer lock the
handler may need and retry. A short arch_spin_relax() is performed
before -EAGAIN is returned so callers don't need to add their own
back-off in the retry path. inflight_timeout itself is kept private
to the timeout subsystem; callers only ever see the return value.
This commit introduces the infrastructure but migrates no callers.
The existing z_abort_timeout() and TIMEOUT_DTICKS_ANNOUNCING-based
cancellation in handlers continue to work; the dispatch loop sets
both inflight_timeout and ANNOUNCING so the two paths coexist while
callers are migrated one module at a time.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
Replace the single in-place assertion in do_swap/z_swap_irqlock with a
z_assert_can_swap() helper performing three checks: held spinlock
pointer, hold count, and IRQ state.
To support the hold-count check, add per-CPU tracking arrays
(z_held_spinlock[] and z_held_spinlock_count[]).
Add z_spin_lock_transfer_owner() to update lock ownership after a
context switch, z_spinlock_abort_sentinel to exempt threads aborted by
a ztest expected-fault scenario, and z_spin_validate_reset() to reset
stale per-CPU lock tracking left by such an abort so subsequent tests
can proceed cleanly.
Signed-off-by: Jinming Zhao <jinmzhao@qti.qualcomm.com>
This reverts commit ff508efd6a.
This is causing breakages across the tree. We should fix all issues and
retry. Nothing wrong with the change itself, but the tree was not
prepared for this change.
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
Add 'k_thread_runtime_stats_is_enabled' function, whichs
used to check whether runtime statistics collection is
enabled for a thread.
Signed-off-by: James Roy <rruuaanng@outlook.com>
Add a uintptr_t magic field (K_MUTEX_MAGIC = K_OBJ_TYPE_MUTEX_ID) to
struct k_mutex under CONFIG_ASSERT, written by k_mutex_init() and
Z_MUTEX_INITIALIZER. Assert the sentinel in lock/unlock to catch
use-before-init, and assert the mutex is not held before re-init.
Zero-initialize dynamically allocated objects in dynamic_object_create()
under CONFIG_ASSERT for a known starting state. Fix test bugs where
k_mutex_init() was called on a held mutex. Add assertion path tests.
Signed-off-by: Mayur Salve <msalve@qti.qualcomm.com>
In CONFIG_SCHED_CPU_MASK_PIN_ONLY a thread must always be pinned to
exactly one CPU. Two related gaps let a zero-mask thread slip
through silently:
1. thread_runq() (run_q.h) had an explicit if/else that silently
routed a zero-masked thread to CPU 0 instead of catching the
violation. Replace it with an __ASSERT that fires at the point
where the bad state is used.
2. cpu_mask_mod() (cpu_mask.c) checked '(m == 0) || power-of-two',
which accepted a cleared mask as valid. Tighten the check to
require strictly a single set bit ('m != 0 && power-of-two') so
any API call that would leave the thread with an empty mask (e.g.
k_thread_cpu_mask_clear()) traps at the API boundary rather than
later at queue time.
The two enforcement points now agree: every thread in PIN_ONLY mode
must carry exactly one CPU bit from the moment the mask is written
until the thread is queued.
Assisted-by: GitHub Copilot:claude-sonnet-4-5
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
Now SCHED_CPU_MASK is no longer restricted to SCHED_SIMPLE. Dropped
dependency on SCHED_SIMPLE and made SCHED_CPU_MASK work on all scheduler
types by implementing z_priq_rb_mask_best and z_priq_mq_mask_best for
both scalable and multiq schedulers.
Update the help text and remove the stale claim that the feature only
works with the simple scheduler and document the mask-aware best-thread
search algorithm and its performance characteristics for each of the
three supported backends:
SCHED_SIMPLE: O(N) sorted-list scan; terminates at the first
priority-eligible thread, so cost is proportional to
the number of higher-priority threads pinned away from
the current CPU.
SCHED_SCALABLE: O(N) in-order rbtree walk; benefits from priority
ordering so the walk usually terminates early.
SCHED_MULTIQ: O(P) bitmap iteration over non-empty priority levels
plus an inner O(N) per-level list scan; fast when
affinity-constrained threads are sparse, degrades when
many same-priority threads are pinned away.
Assisted-by: GitHub Copilot:claude-sonnet-4.6
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
Fixes a TOCTOU race in k_queue_unique_append() by locking the
queue's spinlock around both the search and insert operations.
Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
The k_queue helper routine queue_insert() now requires that
the queue's spinlock be obtained prior to calling it. Its
key is now passed as a parameter into it so that the lock
will be released before it returns.
Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
To avoid a TOCTOU type error in k_queue_remove(), it must lock
the queue's spinlock for the duration of the operation.
Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>
When peeking at an allocated node, the allocated node must be
dereferenced. Unless the queue's spinlock is held that allocated
node could be freed and that memory re-used for something else
entirely leading to the kernel dereferencing an invalid pointer.
Signed-off-by: Peter Mitsis <peter.mitsis@intel.com>