RTE OSAdapter POSIX 0.1.0 build 41b3eb3
POSIX/Linux OAL OSAdapter for Platform_RTE
Loading...
Searching...
No Matches
MISRA C:2012 Compliance Report — Platform_OS_POSIX

Guideline: MISRA C:2012 (with Amendment 1). Target: EN 50128 SIL 4. All 13 files under src/ are in scope (this OSAdapter has no non-vital/vital split of its own — its consumers, e.g. RBC_GP's role C, decide which parts of the call surface they use vitally).

This is a cppcheck MISRA-addon screening pass, not a full compliance verdict** — see RBC_GP's own docs/MISRA_COMPLIANCE_REPORT.dox for the full explanation of why (no licensed --rule-texts= available; this report's rule glosses are this report's own plain-language paraphrase, not the official wording). Tracked as a still-open, larger item in the root TODO.dox for a real, individually-reviewed compliance verdict.

Update log

Update 1 — 2026-09-22 — cppcheck --addon=misra screening pass (all 13 files under src/)

Ran cppcheck --addon=misra --enable=warning,style,performance,portability against this project's own build/compile_commands.json, filtered to src/ (13 files), then filtered a second time on each finding's own reported file path to drop findings cppcheck attributes to a Platform_RTE header this project #includes but does not own — those belong to Platform_RTE's own (already existing, much larger) docs/MISRA_COMPLIANCE_REPORT.dox.

605 MISRA-addon findings**:

Rule Count General topic (this report's own gloss, not official text)
15.5 191 Multiple return statements in one function
17.3 151 A function called without a visible prototype in scope (largely POSIX libc calls: socket/bind/recvfrom/etc. — declared in system headers cppcheck's own built-in library description does not always resolve the same way a real compiler's does)
22.10 68 errno tested without confirming the call that set it actually indicates an error first
11.5 53 A cast from void * to an object pointer type
5.9 33 An identifier reused across a wider scope than an inner one (shadowing)
21.6 21 <stdio.h> use (rte_posix_osadapter_nvm.c's own file-per-region backend, rte_posix_osadapter_log.c) — not yet recorded as a formal deviation the way RBC_GP's vital A/B code is; this OSAdapter's own posture on it is a separate, not-yet-done piece of work
8.9 15 An object could be defined with a narrower scope/lifetime
... 73 19 further rules, single/low-digit counts each — full breakdown: misra_screening/posix_misra_rule_counts.txt

6 free-tier findings** (misra_screening/posix_cppcheck_free_findings.txt; warning/style/performance/portability — need no licensed text, every one a real finding, not a rule-number-only flag): five constVariablePointer (cosmetic), and one worth a closer look — rte_posix_osadapter_reboot.c:175 — if (!resolve_self_exe_path(self_path, sizeof(self_path), NULL)) flagged as always true, meaning the false branch (the success path) may be unreachable by cppcheck's own analysis; not investigated further this pass — a real candidate for the next person to look at this report to check by hand.

No code changed by this update.

Update 2 — 2026-10-03 — rte_posix_osadapter_mutex.c: priority inheritance mandatory (OSA rule R2)

osadapter_create() rewritten (REQ-OAL-MUTEX-004): PI requested at run time on every host, any refusal fails the create, no plain-mutex fallback; single exit point. Screened before and after with cppcheck --addon=misra --std=c99 --library=posix --enable=warning,style,performance,portability -DPTHREAD_PRIO_INHERIT=1 -I include -I ../../Platform_RTE/include -I src src/rte_posix_osadapter_mutex.c (the -D only tells cppcheck the system constant; without it the addon stops at misra-config), findings in this file only:

Rule Before After Note
15.5 8 6 osadapter_create() has one exit now; the 6 left are lock/unlock/destroy, unchanged
17.3 2 3 POSIX calls (pthread_mutexattr_setprotocol() is no longer behind a compile gate); same category as Update 1
21.1, 2.5 0 1 each #define _POSIX_C_SOURCE 200809L (glibc declares PTHREAD_PRIO_INHERIT only under a feature-test macro); the same define the other src/ files already carry
11.5, 2.3, 8.7, 8.9 5, 1, 1, 1 unchanged pre-existing

Free-tier: the old pi_requested == 0 always-true condition (knownConditionTrueFalse) is gone with the code; no new finding. No errno use; fixed-width/rte_status_t types as before.

Update 3 — 2026-10-03 — rte_posix_osadapter_memory.c: pool lock with priority inheritance, created at init (OSA rule R2)

g_mem_lock is no longer PTHREAD_MUTEX_INITIALIZER; the new rte_posix_osadapter_memory_init() creates it with PTHREAD_PRIO_INHERIT (single exit point, same three calls as mutex.c's create) and sets an init flag; the pool operations take the lock through a new single-exit helper mem_lock() that returns RTE_STATUS_INVALID_STATE before init, so create/acquire/stats keep their number of returns. release checks the flag before it reads the pool state, one added early return. rte_posix_osadapter.c: register_all() calls the init, same early-return pattern as its other steps. Screened before and after with the Update 2 command line on each file, findings in that file only:

File Rule Before After Note
memory.c 15.5 14 15 the release init check; the other ops route the check through mem_lock()
memory.c 17.3 0 3 pthread_mutexattr_init/setprotocol/destroy() - POSIX calls, same category as Update 1/2
memory.c 21.1, 2.5 0 1 each #define _POSIX_C_SOURCE 200809L (glibc declares PTHREAD_PRIO_INHERIT only under it), as in mutex.c
memory.c 8.7 1 2 rte_posix_osadapter_memory_init() is external but called from rte_posix_osadapter.c; single-file analysis, as for the existing accessor
memory.c 10.8, 11.5, 12.1, 18.4, 2.3, 8.9 1, 6, 1, 4, 1, 3 unchanged pre-existing
rte_posix_osadapter.c 15.5 12 13 one more early-return step in register_all()
rte_posix_osadapter.c 8.7 1 1 pre-existing

Free-tier: the one pre-existing constVariablePointer in memory.c is unchanged; no new finding. No errno use, no dynamic memory; bool/rte_status_t types as before.

Update 4 — 2026-10-03 — rte_posix_osadapter_mutex.c: timed lock (OSA rule R2)

New osadapter_lock_timed() (REQ-OAL-MUTEX-014) and three static helpers: try_lock_once(), lock_until_deadline() (Linux: pthread_mutex_timedlock() on a CLOCK_REALTIME deadline; other hosts: a pthread_mutex_trylock() loop on a CLOCK_MONOTONIC deadline) and deadline_add_ms(). All four have a single exit. Error codes are read from return values only (EBUSY, ETIMEDOUT); the errno object is not used. Screened before and after with the Update 2 command line, once as is (macOS branch) and once with -D__linux__ (Linux branch), findings in this file only:

Rule Before After (macOS / Linux) Note
11.5 5 6 / 6 osadapter_lock_timed() casts the handle to the state, same as lock/unlock/destroy
17.3 3 3 / 4 Linux: pthread_mutex_timedlock(), POSIX call, same category as Update 1/2
21.10 0 1 / 1 <time.h> for clock_gettime()/nanosleep(); same as task.c, timer.c, ipc.c, netlink.c (Update 1: 4)
2.5 1 1 / 2 with -D__linux__ cppcheck also reports the macOS-only POSIX_MUTEX_POLL_NS as unused
15.5, 2.3, 21.1, 8.7, 8.9 6, 1, 1, 1, 1 unchanged pre-existing

A first draft had two 10.8 findings (cast of a composite ms / 1000U, ms % 1000U); deadline_add_ms() now assigns both to rte_duration_ms_t locals before the cast. Free-tier (--enable=warning,style,performance,portability, no addon): no finding. No dynamic memory; the nanosecond arithmetic of the polling loop is in int64_t.

Update 5 — 2026-10-03 — bounded memory-pool lock (OSA rule R2), shared lock helper

try_lock_once(), lock_until_deadline() (both host variants) and deadline_add_ms() moved unchanged from rte_posix_osadapter_mutex.c into the new internal src/rte_posix_osadapter_lock.c (header src/rte_posix_osadapter_lock.h, not installed; macros renamed POSIX_MUTEX_* -> POSIX_LOCK_*), behind one single-exit entry point posix_osa_lock_bounded() that adds a NULL check. osadapter_lock_timed() in mutex.c calls it (REQ-OAL-MUTEX-014 behaviour unchanged); mem_lock() in memory.c calls it with RTE_POSIX_MEM_LOCK_TIMEOUT_MS (default 50 ms, REQ-OAL-MEM-015) instead of pthread_mutex_lock(). Screened before and after with the Update 2 command line, once as is (macOS branch) and once with -D__linux__, findings per file:

File Rule Before (macOS / Linux) After (macOS / Linux) Note
mutex.c 21.10 1 / 1 0 / 0 <time.h> moved to lock.c with the code
mutex.c 17.3 3 / 4 3 / 3 pthread_mutex_timedlock() moved to lock.c
mutex.c 2.5 1 / 2 1 / 1 the macOS-only poll macro moved to lock.c
mutex.c 11.5, 15.5, 2.3, 21.1, 8.7, 8.9 6, 6, 1, 1, 1, 1 unchanged pre-existing
lock.c (new) 21.1, 2.5 - 1 / 1, 1 / 2 #define _POSIX_C_SOURCE 200809L, as in every other src/ file; with -D__linux__ cppcheck also reports the macOS-only POSIX_LOCK_POLL_NS (as Update 4 did in mutex.c)
lock.c (new) 21.10 - 1 / 1 <time.h>, moved from mutex.c
lock.c (new) 17.3 - 0 / 1 pthread_mutex_timedlock(), moved from mutex.c
lock.c (new) 8.7 - 1 / 1 posix_osa_lock_bounded() is external, called from mutex.c and memory.c; single-file analysis, as for the accessors
memory.c all see Update 3 unchanged mem_lock() keeps one exit; the only new call is posix_osa_lock_bounded()

misra-config notes (cppcheck does not know EBUSY, CLOCK_MONOTONIC from its POSIX library) moved from mutex.c to lock.c with the code, 3 before and 3 after. Free-tier (--enable=warning,style,performance,portability, no addon): no finding in lock.c or mutex.c; memory.c keeps its one pre-existing constVariablePointer. No dynamic memory, no errno use; the pool's critical sections are unchanged.

Update 6 — 2026-10-03 — rte_posix_osadapter_task.c: task-thread attributes set before creation (OSA rule R1)

apply_priority_best_effort() (post-create pthread_setschedparam(), one early return) is replaced by two static helpers with a single exit each: set_fifo_attributes() (clamps the uint32_t priority into the SCHED_FIFO range, comparing on uint32_t, and sets PTHREAD_EXPLICIT_SCHED, SCHED_FIFO, the priority as nested ifs, so no call sits in the right operand of &&) and create_task_thread() (attribute init, stack size, explicit-sched create, on refusal or EPERM one report and a create with PTHREAD_INHERIT_SCHED, pthread_attr_destroy on every path after a successful init). osadapter_start() loses its two returns after the create. Error codes are read from return values only (EPERM); the errno object is not used by the new code. Screened before (git show HEAD:) and after with the Update 2 command line, once as is (macOS branch) and once with -D__linux__, findings in this file only:

Rule Before (macOS / Linux) After (macOS / Linux) Note
15.5 6 / 6 4 / 4 gone: the early return in apply_priority_best_effort() and the two returns after pthread_create in osadapter_start(); left: lines 277 (create), 294 (suspend), 312, 320 (start), pre-existing parameter/suspend checks
17.3 1 / 2 4 / 5 pthread_setschedparam() gone; new lines 120, 122, 124 (pthread_attr_setinheritsched/setschedpolicy/setschedparam) and 255 (pthread_attr_setinheritsched, fallback) - POSIX calls cppcheck's POSIX library does not declare, same category as Update 1/2; Linux line 174 (clock_nanosleep) pre-existing
22.10 1 / 0 1 / 0 pre-existing errno == EINTR after nanosleep() (macOS branch), now line 197
10.4, 10.7, 10.8, 11.5, 2.3, 2.5, 21.1, 21.10, 21.5, 8.7, 8.9 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1 unchanged pre-existing

misra-config notes (constants cppcheck's POSIX library does not know): before 2 / 3 (SCHED_FIFO, EINTR; Linux also CLOCK_MONOTONIC), after 5 / 6 (PTHREAD_EXPLICIT_SCHED line 120, SCHED_FIFO line 122, EINTR line 197 / 175, EPERM line 238, PTHREAD_INHERIT_SCHED line 255; Linux also CLOCK_MONOTONIC line 162). Free-tier (--enable=warning,style,performance,portability): none before; a first draft had three variableScope findings (wanted, inherit_fallback, rc), fixed by declaring them in the inner block; none after. No dynamic memory; the public header change (rte_posix_osadapter.h) is documentation only.

Update 7 — 2026-10-03 — rte_posix_osadapter_timer.c: timer-thread attributes set before creation (OSA rule R1)

osadapter_start() no longer calls pthread_create(..., NULL, ...) with two returns after it; it calls the new static create_timer_thread() (attribute init, fixed stack size RTE_POSIX_TIMER_STACK_SIZE raised to PTHREAD_STACK_MIN if below it, explicit-sched create, on refusal or EPERM one report and a create with PTHREAD_INHERIT_SCHED, pthread_attr_destroy on every path after a successful init) and keeps one final return status. The new static set_creator_sched_attributes() reads the caller's policy and priority with pthread_getschedparam(pthread_self()) and sets PTHREAD_EXPLICIT_SCHED, the policy and the priority as nested ifs (no call in the right operand of &&). Both helpers have a single exit, the same shape as task.c's (Update 6). Error codes are read from return values only (EPERM); the errno object is not used by the new code. Screened before (git show HEAD:) and after with the Update 2 command line, once as is (macOS branch) and once with -D__linux__, findings in this file only:

Rule Before (macOS / Linux) After (macOS / Linux) Note
15.5 7 / 7 6 / 6 gone: the return after a failed pthread_create in osadapter_start(); left: lines 279 (create), 296 (stop), 315, 323 (start), 346, 351 (now), pre-existing parameter/stop/clock checks
17.3 0 / 1 6 / 7 new lines 194 (pthread_getschedparam(), pthread_self()), 196, 198, 200 (pthread_attr_setinheritsched/setschedpolicy/setschedparam) and 256 (pthread_attr_setinheritsched, fallback) - POSIX calls cppcheck's POSIX library does not declare, same category as Update 1/2/6; Linux line 154 (clock_nanosleep) pre-existing
22.10 1 / 0 1 / 0 pre-existing errno == EINTR after nanosleep() (macOS branch), now line 163
10.4, 10.7, 10.8, 11.5, 15.4, 2.3, 2.5, 21.1, 21.10, 21.5, 8.7, 8.9 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1 unchanged pre-existing; the new <limits.h>, <sched.h>, <stdbool.h>, <stddef.h> includes add none

Totals in this file (rule findings, without misra-config): 24 / 24 before, 29 / 29 after. misra-config notes (constants cppcheck's POSIX library does not know): before 2 / 3 (EINTR, CLOCK_MONOTONIC; Linux also CLOCK_MONOTONIC in the thread loop), after 5 / 6 (EINTR line 163 / 155, PTHREAD_EXPLICIT_SCHED line 196, EPERM line 239, PTHREAD_INHERIT_SCHED line 256, CLOCK_MONOTONIC line 348; Linux also CLOCK_MONOTONIC line 137). Free-tier (--enable=warning,style,performance,portability, no addon): none before, none after. No dynamic memory; the public header change (rte_posix_osadapter.h) is documentation only.

Update 8 — 2026-10-03 — rte_posix_osadapter_socket.c: O_NONBLOCK at open (OSA rule R5)

posix_socket_open() now calls the file's existing posix_socket_set_nonblocking(fd, true) (fcntl(F_GETFL), then fcntl(F_SETFL, flags | O_NONBLOCK), each return code checked) after the SO_REUSE* options; on failure it closes the fd, leaves *out_handle unwritten and returns RTE_STATUS_INTERNAL_ERROR. A static forward declaration of posix_socket_set_nonblocking() (line 22) makes it visible above open; no new fcntl call site. Screened before (git show HEAD:) and after with the Update 2 command line, once as is (macOS branch) and once with -D__linux__ (identical results on both), findings in this file only:

Rule Before After Note
15.5 30 31 new: line 65, the early return RTE_STATUS_INTERNAL_ERROR after a refused O_NONBLOCK (the function already had three early returns, lines 33, 46, 52); every other finding moved by +2 (above line 58) or +10 lines
17.3 10 10 unchanged; the new close() is declared for cppcheck, the fcntl calls are the existing ones (lines 332, 339)
10.4, 11.5, 12.1, 17.7, 2.5, 21.1, 22.10, 8.7, 8.9 4, 4, 1, 5, 1, 1, 10, 1, 1 unchanged pre-existing; the (void)close(fd) adds no 17.7

Totals in this file (rule findings, without misra-config): 68 before, 69 after. misra-config notes (constants cppcheck's POSIX library does not know: AF_INET, EINPROGRESS, EAGAIN, EWOULDBLOCK, EINTR, POLL*, F_SETFL): 19 before, 19 after, all pre-existing (now lines 92 to 339). Free-tier (--enable=warning,style,performance,portability, no addon): none before, none after. No dynamic memory, no new errno use; the public header change (rte_posix_osadapter.h) is documentation only.

Update 9 — 2026-10-03 — rte_posix_osadapter_ipc.c: bounded queue of whole messages (OSA rule R5)

osadapter_create() stores queue_depth, refuses message_size > PIPE_BUF and a message_size * queue_depth overflow, makes both pipe ends non-blocking through the new set_nonblocking() (each fcntl() result checked) and checks the pipe capacity through the new ensure_pipe_capacity() (Linux: required_pipe_bytes(), F_SETPIPE_SZ, F_GETPIPE_SZ; other hosts: RTE_POSIX_IPC_PIPE_CAPACITY), closing both fds on any failure. backend_send() checks the size and calls the new send_until_deadline() / try_send_once() (ioctl(FIONREAD) depth check, one write()) / sleep_before_retry() (at most 1 ms, never past the deadline). backend_receive() checks the buffer size and calls read_message(), the old transfer_all() reduced to the read direction. compute_deadline() returns whether the clock was read and builds the deadline in rte_duration_ms_t locals (as lock.c's deadline_add_ms()). Every new or rewritten function has a single exit; remaining_ms() and osadapter_destroy() are unchanged. Screened before (git show HEAD:) and after with the Update 2 command line plus --template='{file}:{line}:{column}:{severity}:{id}:{message}', three ways: as is (macOS branch; the -D of the Update 2 command line limits cppcheck to that one configuration), with -D__linux__ (identical to as is: cppcheck does not read the system <fcntl.h>, so F_SETPIPE_SZ stays undefined) and with -D__linux__ -DF_SETPIPE_SZ=1031 -DF_GETPIPE_SZ=1032 (the Linux pipe-size branch). Findings in this file only; counts as is / Linux pipe-size branch:

Rule Before After Note
15.5 11 / 11 2 / 2 left: lines 112 (remaining_ms()) and 523 (osadapter_destroy()), pre-existing
11.5 7 / 7 6 / 6 lines 456, 462 (create: storage to state, storage to handle), 477 (send), 499, 512 (receive: handle to state, out_message to uint8_t *), 519 (destroy)
17.3 2 / 3 3 / 4 lines 221, 223 (fcntl(F_SETFL), now checked), 310 (ioctl(FIONREAD), new); pipe-size branch also 271 (fcntl(F_SETPIPE_SZ), before line 160) - POSIX calls, same category as Update 1
22.10 4 / 4 7 / 7 lines 184, 195 (3, errno after poll()/read() in read_message(), the old checks at 107, 117) and 328 (3, new: EAGAIN/EWOULDBLOCK/EINTR after write() in try_send_once(); the send direction used to share the read loop's checks)
10.4, 10.7, 10.8 1, 1, 2 0, 0, 0 gone: the old compute_deadline() arithmetic (line 60: 10.4, 10.7; line 59: 10.8) and the requested_capacity cast (line 158: 10.8)
18.4 2 / 2 0 &dst[done] instead of dst_bytes + done
2.5 1 / 1 2 / 2 line 6 _GNU_SOURCE (pre-existing) and the macro of the other host branch, reported unused: line 63 POSIX_IPC_EXTRA_SLOTS (as is) / line 72 RTE_POSIX_IPC_PIPE_CAPACITY (pipe-size branch), as Update 4 and 5 noted for the poll macro
2.3, 21.1, 21.10, 8.7, 8.9 1 each 1 each pre-existing, now lines 85, 6, 46, 535, 531

Totals (rule findings, without misra-config): 36 / 37 before, 25 / 26 after. misra-config notes (constants cppcheck's POSIX library does not know): 5 before (CLOCK_MONOTONIC 43, EINTR 107, EAGAIN/EWOULDBLOCK/EINTR 117), 16 after (CLOCK_MONOTONIC 110, 128, 358; EINTR 184; EAGAIN/EWOULDBLOCK/EINTR 195 and 328; F_SETFL and O_NONBLOCK 221 and 223; FIONREAD 310; _POSIX_PIPE_BUF 434, because cppcheck does not see the system PIPE_BUF and takes the fallback), the same in all three runs. Free-tier (--enable=warning,style,performance,portability): 3 constVariablePointer before (send, receive, destroy), 1 after (line 519, destroy, pre-existing; send and receive now use a pointer to const), the same in all three runs. No dynamic memory; the pipe-size arithmetic is overflow-checked (SIZE_MAX, INT_MAX) before any multiplication; the public header change (rte_posix_osadapter.h) is documentation only.

Update 10 — 2026-10-03 — shared posix_remaining_ms() capped at INT_MAX (OSA rules R2, R5)

The two identical local remaining_ms() copies (rte_posix_osadapter_ipc.c, rte_posix_osadapter_netlink.c; two returns each, a bare (int) cast of an int64_t) are replaced by one static inline int posix_remaining_ms() in the internal header src/rte_posix_osadapter_poll.h: same contract and rounding, single exit, the result capped at INT_MAX before the cast. The header now includes <time.h> for clock_gettime(); it is also included by rte_posix_osadapter_socket.c and rte_posix_osadapter_channel_service.c, which only use posix_poll_timeout_ms(). Screened before (the files at HEAD) and after with the Update 9 command line (Update 2 plus --template=...), as is and with -D__linux__ for all four files, and for ipc.c also with -D__linux__ -DF_SETPIPE_SZ=1031 -DF_GETPIPE_SZ=1032; results as is and -D__linux__ identical in every file:

File Rule Before After Note
ipc.c 15.5 2 1 gone: line 112 (remaining_ms()); left: line 507 (osadapter_destroy()), pre-existing
ipc.c 11.5, 17.3, 2.3, 2.5, 21.1, 21.10, 22.10, 8.7, 8.9 6, 3 (pipe-size 4), 1, 2, 1, 1, 7, 1, 1 unchanged pre-existing; lines moved by the removed function
netlink.c 15.5 39 38 gone: line 129 (return -1 in remaining_ms())
netlink.c 10.4, 10.7, 10.8, 11.5, 15.7, 17.3, 2.3, 2.5, 21.1, 21.10, 21.6, 22.10, 8.7, 8.9 1, 1, 1, 9, 1, 10, 1, 1, 1, 1, 13, 33, 1, 1 unchanged pre-existing (the 10.x are in netlink's own compute_deadline(), not touched)
poll.h (via socket.c) 21.10 0 1 line 18, #include <time.h> for clock_gettime(); socket.c did not include <time.h> before. Through ipc.c, netlink.c and channel_service.c the finding stays on their own pre-existing <time.h> line, so it is not counted again
socket.c, channel_service.c all 69, 81 69, 81 unchanged

Totals in the .c files (rule findings, without misra-config): ipc.c 25 / 26 (pipe-size branch) before, 24 / 25 after; netlink.c 114 before, 113 after; socket.c 69 and channel_service.c 81 unchanged; poll.h 0 before, 1 after (21.10, only through socket.c). No 8.x finding for the static inline functions in the header (8.7 / 8.9 counts unchanged in all four files, none at poll.h), no 2.7 or unused-function report in the two files that do not call posix_remaining_ms(). misra-config notes: the CLOCK_MONOTONIC of the old copies (ipc.c line 110, netlink.c line 127) is now reported once at poll.h line 45 - ipc.c 16 and netlink.c 37 unchanged; socket.c 19 -> 20 and channel_service.c 20 -> 21 (the same poll.h line 45; these two files read no clock). Free-tier (--enable=warning,style,performance,portability): ipc.c 1 and netlink.c 1 (constVariablePointer, pre-existing), socket.c and channel_service.c 0, before and after. No dynamic memory, no errno use, int64_t arithmetic unchanged; no public header changed.

Update 11 — 2026-10-03 — socket buffer sizes from the link config (OSA rules R5, R6)

New internal src/rte_posix_osadapter_sockbuf.{h,c} (header not installed): posix_socket_apply_buffers() and the static apply_one(), single exit each. For a non-zero rcvbuf_bytes / sndbuf_bytes (Platform_RTE REQ-OAL-NETLINK-015) setsockopt(SOL_SOCKET, SO_RCVBUF / SO_SNDBUF) with the uint32_t capped at INT_MAX before the cast to int, then getsockopt() of the same option, both return codes and the returned length checked as nested ifs (no call in the right operand of &&); the read-back is compared in int64_t with the value times POSIX_SOCKBUF_READBACK_FACTOR (2 on Linux, 1 elsewhere). A field of 0 makes no call. rte_posix_osadapter_netlink.c (open_listen_udp() after bind, open_connect_udp() after socket) and rte_posix_osadapter_channel_service.c (init_listen_socket() after bind, init_connect_socket() after socket) call it and on a failure close the fd (and freeaddrinfo() in the connect paths) and return its status, the same shape as their existing error paths. Screened before (the files at HEAD) and after with the Update 9 command line (Update 2 plus --template=...), as is and with -D__linux__ (identical results in every file), findings in each file only:

File Rule Before After Note
netlink.c 15.5 38 40 new: lines 196 (listen) and 338 (connect), return buf_status after a refused buffer size; the rule 15.5 bucket of Update 1
netlink.c 17.3 10 11 new: line 337, freeaddrinfo() in the new connect error path - POSIX call cppcheck's library does not declare, same category as Update 1; the call of posix_socket_apply_buffers() adds none
netlink.c 10.4, 10.7, 10.8, 11.5, 15.7, 2.3, 2.5, 21.1, 21.10, 21.6, 22.10, 8.7, 8.9 as Update 10 unchanged pre-existing; lines moved by the file header note (+5), the include (+1) and the two new blocks
channel_service.c 15.5 39 41 new: lines 126 (listen) and 181 (connect), return buf_status
channel_service.c 17.3 10 11 new: line 180, freeaddrinfo() in the new connect error path, as in netlink.c
channel_service.c all others unchanged unchanged pre-existing
sockbuf.c (new) 21.1, 2.5 - 1 each line 3, #define _POSIX_C_SOURCE 200809L, as in every other src/ file
sockbuf.c (new) 8.7 - 1 line 75, posix_socket_apply_buffers() is external, called from netlink.c and channel_service.c; single-file analysis, as for lock.c

Totals (rule findings, without misra-config): netlink.c 113 before, 116 after; channel_service.c 81 before, 84 after; sockbuf.c 3 (new); the new header reports nothing; the findings in included Platform_RTE headers (rte_safestate.h, rte_types.h) are their existing ones. No 10.x finding for the INT_MAX cap or the int64_t comparison. misra-config notes: netlink.c 37 and channel_service.c 21 unchanged; sockbuf.c 2 (SOL_SOCKET, lines 53 and 55, a constant cppcheck's POSIX library does not know). Free-tier (--enable=warning,style,performance,portability, no addon): netlink.c 1 (constVariablePointer, pre-existing, now line 728), channel_service.c and sockbuf.c 0, before and after. No dynamic memory, no errno use in the new code; the public header change (rte_posix_osadapter_channel_service.h) is Doxygen only.

Update 12 — 2026-10-04 — listen-role send with no peer returns RTE_STATUS_NOT_CONNECTED (OSA rule R5)

rte_posix_osadapter_channel_service.c backend_send(): the existing early return for a listen-role link with no known peer returns RTE_STATUS_NOT_CONNECTED (Platform_RTE REQ-CHANSVC-001) instead of RTE_STATUS_OK; its comment grows from one line to two. No new branch, call or variable. Screened with cppcheck 2.21 before (the file at HEAD) and after with the Update 9 command line (Update 2 plus --template=...), as is and with -D__linux__ (identical results), findings in this file only:

File Rule Before After Note
channel_service.c 15.5 41 41 the changed return (line 463 -> 464) was already counted; lines after it move by +1
channel_service.c 11.5, 15.7, 17.3, 2.3, 2.5, 21.1, 21.10, 21.6, 22.10, 8.7 4, 1, 11, 1, 1, 1, 1, 4, 17, 2 unchanged pre-existing

Totals (rule findings, without misra-config): 84 before, 84 after. misra-config notes: 20 before, 20 after (this run counts 20 where Update 11 wrote 21; the before and after runs are the same command). Free-tier (--enable=warning,style,performance,portability): 0 before, 0 after. No dynamic memory, no new errno use; the public header change (rte_posix_osadapter_channel_service.h) is Doxygen only.

Update 13 — 2026-10-04 — timer and task OSAdapters join every created thread (OSA rule R2)

rte_posix_osadapter_timer.c and rte_posix_osadapter_task.c: the running field (cleared by the thread itself) is replaced by bool joinable, read and written by the controlling thread only. New static functions per file, single exit each: create_timer_key() / create_task_key() (the pthread_once() routine, pthread_key_create() with no destructor) and timer_key_ready() / task_key_ready() (pthread_once() on a block-scope static pthread_once_t, so no new file-scope object is used by one function only); is_timer_thread() / is_task_thread() (pthread_getspecific(key) == (const void *)state); join_timer_thread() / join_task_thread() (sets should_stop, pthread_join() with its result checked, clears joinable only on 0, else RTE_STATUS_INTERNAL_ERROR); and run_timer_loop() / run_task(), the old thread body moved unchanged out of timer_thread_main() / task_thread_main(), which now call pthread_setspecific(key, state) first and on failure report DEGRADED and run nothing. New file-scope objects: static pthread_key_t s_timer_key / s_task_key and static bool s_timer_key_ready / s_task_key_ready (written only inside pthread_once()). No dynamic memory in this code; the key and the per-thread value are libc-managed (glibc keeps the first 32 keys' values in the thread descriptor, pthread_setspecific() may allocate for a higher key index, hence its ENOMEM path); the key is never deleted (process lifetime). osadapter_create() gains an early return RTE_STATUS_INTERNAL_ERROR when the key is not available; osadapter_stop() / osadapter_suspend() set should_stop before the self check and end in one return status; osadapter_start() ends in one return status (its early return after a failed stop is gone). The timer loop also breaks when should_stop is set after a callback (one more operand in the existing if). Screened with cppcheck 2.21 before (the files at HEAD) and after with the Update 9 command line (Update 2 plus --template='{file}:{line}:{column}:{severity}:{id}:{message}'), as is (macOS branch) and with -D__linux__, findings in each file only; counts as is / Linux:

File Rule Before After Note
timer.c 15.5 6 / 6 6 / 6 gone: line 323 (return stop_status in osadapter_start()); new: line 404 (return RTE_STATUS_INTERNAL_ERROR in osadapter_create() when the key is not available); left: 399 (create, was 279), 422 (stop, was 296), 446 (start, was 315), 484, 489 (now, were 346, 351)
timer.c 17.3 6 / 7 10 / 11 new: lines 186 (pthread_key_create()), 196 (pthread_once()), 209 (pthread_setspecific()), 278 (pthread_getspecific()) - POSIX calls cppcheck's POSIX library does not declare, same category as Update 1/7 (the now checked pthread_join() adds none); moved: 194 (2) -> 314, 196 -> 316, 198 -> 318, 200 -> 320, 256 -> 376, Linux 154 -> 246 (clock_nanosleep)
timer.c 22.10 1 / 0 1 / 0 pre-existing errno == EINTR after nanosleep() (macOS branch), line 163 -> 255
timer.c 10.4, 10.7, 10.8, 11.5, 15.4, 2.3, 2.5, 21.1, 21.5, 21.10, 8.7, 8.9 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1, 1 unchanged pre-existing, moved: 10.x 114/113 -> 165/164 (Linux 122/121 -> 173/172), 11.5 133, 282, 285, 292, 309 -> 207, 407, 410, 417, 441, 15.4 148 -> 240, 2.3 78 -> 118, 21.5 50 -> 90, 21.10 54 -> 94, 8.7 102 -> 153, 8.9 95 -> 140 (the vtable object)
task.c 15.5 4 / 4 4 / 4 gone: line 320 (return status after a failed suspend in osadapter_start()); new: line 397 (return RTE_STATUS_INTERNAL_ERROR in osadapter_create(), as in timer.c); left: 392 (create, was 277), 415 (suspend, was 294), 439 (start, was 312)
task.c 17.3 4 / 5 8 / 9 new: lines 185 (pthread_key_create()), 195 (pthread_once()), 285 (pthread_setspecific()), 303 (pthread_getspecific()), as in timer.c; moved: 120, 122, 124 -> 167, 169, 171, 255 -> 370, Linux 174 -> 243 (clock_nanosleep)
task.c 22.10 1 / 0 1 / 0 pre-existing errno == EINTR after nanosleep() (macOS branch), line 197 -> 266
task.c 10.4, 10.7, 10.8, 11.5, 2.3, 2.5, 21.1, 21.5, 21.10, 8.7, 8.9 1, 1, 1, 5, 1, 1, 1, 1, 1, 1, 1 unchanged pre-existing, moved: 10.x 72/71 -> 119/118 (Linux 80/79 -> 127/126), 11.5 136, 280, 283, 290, 307 -> 283, 400, 403, 410, 434, 2.3 66 -> 107, 21.5 50 -> 91, 21.10 53 -> 94, 8.7 341 -> 474, 8.9 338 -> 471

Totals (rule findings, without misra-config): timer.c 29 / 29 before, 33 / 33 after; task.c 24 / 24 before, 28 / 28 after; all four added findings per file are 17.3 on the thread-specific-data calls. A first draft declared the pthread_once_t at file scope and drew one 8.9 per file (an object used in one function only); it is a block-scope static now. misra-config notes (constants cppcheck's POSIX library does not know), unchanged in number, lines moved: timer.c 5 / 6 (163, 196, 239, 256, 348 -> 255, 316, 359, 376, 486; Linux 137, 155 -> 229, 247 in place of 163), task.c 5 / 6 (120, 122, 197, 238, 255 -> 167, 169, 266, 353, 370; Linux 162, 175 -> 231, 244 in place of 197). Free-tier (--enable=warning,style,performance,portability): 0 before, 0 after in both files. No errno use in the new code; the public header change (rte_posix_osadapter.h) is Doxygen only.

Update 14 — 2026-10-04 — timer and task threads paced by an absolute monotonic deadline (OSA rule R3)

New internal src/rte_posix_osadapter_period.{h,c} (header not installed): posix_period_init(), posix_period_advance(), posix_period_sleep_until() and the static sleep_to_deadline() (one variant per host), single exit each. The init reads CLOCK_MONOTONIC into a local and copies it out only on success. The advance assigns period_ms / 1000U and period_ms % 1000U to rte_duration_ms_t locals before the casts (as lock.c's deadline_add_ms()). The Linux sleep is the previous clock_nanosleep() loop with the error read from the return value; the other-host sleep computes the time left in int64_t and assigns / and % to int64_t locals before the casts to time_t / long; nanosleep()'s result is discarded with (void) (the next clock read decides), so the errno object is no longer used. rte_posix_osadapter_timer.c and rte_posix_osadapter_task.c lose ms_to_timespec() / timespec_add_ms() and their host #if branches; run_timer_loop() is a while (running) loop with a flag instead of for (;;) with two breaks, and the periodic branch of run_task() moves into the new static run_periodic_task() (same shape, single exit). Each loop reports once after it ended if the clock failed. Screened with cppcheck 2.21 before (the files at HEAD) and after with the Update 9 command line (Update 2 plus --template='{file}:{line}:{column}:{severity}:{id}:{message}'), as is (macOS branch) and with -D__linux__, findings in each file only; counts as is / Linux:

File Rule Before After Note
timer.c 10.4, 10.7, 10.8 1, 1, 1 / 1, 1, 1 0 / 0 gone with ms_to_timespec() (macOS lines 165, 165, 164) and timespec_add_ms() (Linux lines 173, 173, 172)
timer.c 15.4 1 / 1 0 / 0 gone: line 240, the for (;;) of run_timer_loop() with two breaks, now while (running)
timer.c 22.10 1 / 0 0 / 0 gone: line 255, errno == EINTR after nanosleep() (macOS branch)
timer.c 17.3 10 / 11 10 / 10 gone (Linux): line 246, clock_nanosleep(), moved to period.c; moved: 186, 196, 209, 278, 314 (2), 316, 318, 320, 376 -> 175, 185, 198, 257, 293 (2), 295, 297, 299, 355
timer.c 11.5, 15.5, 2.3, 2.5, 21.1, 21.5, 21.10, 8.7, 8.9 5, 6, 1, 1, 1, 1, 1, 1, 1 unchanged pre-existing, moved: 11.5 207, 407, 410, 417, 441 -> 196, 386, 389, 396, 420; 15.5 399, 404, 422, 446, 484, 489 -> 378, 383, 401, 425, 463, 468; 2.3 118 -> 131; 21.5 90 -> 103; 21.10 94 -> 107; 8.7 153 -> 163; 8.9 140 -> 150; 21.1, 2.5 line 1
task.c 10.4, 10.7, 10.8 1, 1, 1 / 1, 1, 1 0 / 0 gone with ms_to_timespec() (macOS lines 119, 119, 118) and timespec_add_ms() (Linux lines 127, 127, 126)
task.c 22.10 1 / 0 0 / 0 gone: line 266, errno == EINTR after nanosleep() (macOS branch)
task.c 17.3 8 / 9 8 / 8 gone (Linux): line 243, clock_nanosleep(), moved to period.c; moved: 167, 169, 171, 185, 195, 285, 303, 370 -> 158, 160, 162, 176, 186, 264, 282, 349
task.c 11.5, 15.5, 2.3, 2.5, 21.1, 21.5, 21.10, 8.7, 8.9 5, 4, 1, 1, 1, 1, 1, 1, 1 unchanged pre-existing, moved: 11.5 283, 400, 403, 410, 434 -> 262, 379, 382, 389, 413; 15.5 392, 397, 415, 439 -> 371, 376, 394, 418; 2.3 107 -> 119; 21.5 91 -> 103; 21.10 94 -> 106; 8.7 474 -> 453; 8.9 471 -> 450; 21.1, 2.5 line 1
period.c (new) 21.1, 2.5 - 1, 1 / 1, 1 line 3, #define _POSIX_C_SOURCE 200809L, as in every other src/ file
period.c (new) 21.5 - 1 / 1 line 17, <signal.h> for sig_atomic_t (the should_stop parameter), as in timer.c and task.c
period.c (new) 21.10 - 1 / 1 line 21, <time.h> for clock_gettime() / clock_nanosleep() / nanosleep(), as in timer.c, task.c, lock.c
period.c (new) 8.7 - 3 / 3 lines 38, 60, 77: the three functions are external, called from timer.c and task.c; single-file analysis, as for lock.c and sockbuf.c
period.c (new) 17.3 - 0 / 1 line 101, clock_nanosleep(), moved from timer.c and task.c (one call site now)

Totals (rule findings, without misra-config): timer.c 33 / 33 before, 28 / 28 after; task.c 28 / 28 before, 24 / 24 after; period.c 7 / 8 (new). Through period.c the header adds nothing; screened on its own (the same command line on src/rte_posix_osadapter_period.h), it reports 21.5 (line 18, <signal.h> for sig_atomic_t) and 21.10 (line 19, <time.h> for struct timespec) on both hosts, the same two rules period.c, timer.c and task.c already report for their own includes. misra-config notes (constants cppcheck's POSIX library does not know): timer.c 5 / 6 before (macOS EINTR 255; Linux CLOCK_MONOTONIC 229, EINTR 247; both 316, 359, 376, 486), 4 / 4 after (295, 338, 355, 465: PTHREAD_EXPLICIT_SCHED, EPERM, PTHREAD_INHERIT_SCHED, CLOCK_MONOTONIC of osadapter_now()); task.c 5 / 6 before (macOS EINTR 266; Linux CLOCK_MONOTONIC 231, EINTR 244; both 167, 169, 353, 370), 4 / 4 after (158, 160, 332, 349); period.c 2 / 3 (CLOCK_MONOTONIC 47 and, macOS, 122; Linux EINTR 102, 104). Free-tier (--enable=warning,style,performance,portability): 0 before, 0 after in timer.c and task.c, 0 in period.c. No dynamic memory; the errno object is no longer read in timer.c or task.c and not used in period.c (error codes come from return values: EPERM, EINTR); no public header changed. The nanosleep() mentions in Updates 6, 7 and 13 describe the code as it was then and are left as written.

Update 15 — 2026-10-04 — stop, suspend and destroy wake a waiting timer or periodic task thread (OSA rule R2)

src/rte_posix_osadapter_period.c: the sleep (clock_nanosleep() on Linux, nanosleep() elsewhere) is replaced by a timed wait on one process-wide wake object, a priority-inheritance mutex and a condition variable (file-scope static pthread_mutex_t s_wake_lock, static pthread_cond_t s_wake_cond, static bool s_wake_ready, the last written only inside pthread_once()). New external functions posix_period_wake_ready() (pthread_once() on a block-scope static pthread_once_t, as the thread keys of Update 13) and posix_period_wake_all(); new static functions create_wake_object() (the pthread_once() routine: pthread_mutexattr_init/setprotocol/destroy, pthread_mutex_init, pthread_condattr_init/destroy, pthread_cond_init, pthread_mutex_destroy on a refused condition variable, the report), set_wake_clock() (non-Apple: pthread_condattr_setclock(CLOCK_MONOTONIC); macOS: nothing), time_left_ns(), ns_to_ms_rounded_up() (capped at UINT32_MAX before the cast), wait_to_deadline() (the loop), wait_locked() (one step with the mutex held) and wait_for_wake() (non-Apple: pthread_cond_timedwait(); macOS: pthread_cond_timedwait_relative_np() of the time left, computed in int64_t with / and % assigned to int64_t locals before the casts, as before). Every function has a single exit; calls that test a result are nested ifs, no call sits in the right operand of && / ||. The host split is now #if defined(__APPLE__) (was __linux__). Error codes come from return values (ETIMEDOUT); the errno object is not used. A second feature-test macro, _DARWIN_C_SOURCE, is defined on macOS only (with _POSIX_C_SOURCE set, macOS's <pthread.h> declares pthread_cond_timedwait_relative_np() only under it). posix_period_sleep_until() keeps its name and signature. src/rte_posix_osadapter_timer.c / src/rte_posix_osadapter_task.c: osadapter_stop() / osadapter_suspend() and join_timer_thread() / join_task_thread() call posix_period_wake_all(&state->should_stop) instead of state->should_stop = 1; osadapter_create() checks posix_period_wake_ready() after the key through a bool ready and one if (!ready) with the existing early return (no new return); task.c drops its unused <time.h> include.

Screened with cppcheck 2.21 before (the files at HEAD) and after with the Update 9 command line (Update 2 plus --template='{file}:{line}:{column}:{severity}:{id}:{message}'), findings in each file only. Because period.c now splits on __APPLE__, it is screened three ways after: as is and with -D__linux__ (both the non-Apple branch; identical results) and with -D__APPLE__ (the macOS branch). timer.c and task.c give identical results in all three runs, and before as is and with -D__linux__. Counts as is / -D__linux__ (before) and as is = -D__linux__ / -D__APPLE__ (after):

File Rule Before After Note
period.c 17.3 0 / 1 9 / 8 gone: line 101, clock_nanosleep() (Linux before); new, both branches: 132 (pthread_once()), 176, 178, 182 (pthread_mutexattr_init/setprotocol/destroy()), 187, 193 (pthread_condattr_init/destroy()), 191 (pthread_cond_init()); non-Apple only: 223 (pthread_condattr_setclock()), 362 (pthread_cond_timedwait()); macOS only: 349 (pthread_cond_timedwait_relative_np()) - POSIX / Darwin calls cppcheck's POSIX library does not declare, the Update 1 category (pthread_mutex_init/destroy/unlock(), pthread_cond_broadcast() and clock_gettime() add none)
period.c 8.7 3 / 3 4 / 4 new: line 139, posix_period_wake_all() is external, called from timer.c and task.c (single-file analysis, as Update 14); moved: 38, 60, 77 -> 70, 92, 109. posix_period_wake_ready() (line 127) is not reported: it is also called inside period.c
period.c 21.1, 2.5 1, 1 / 1, 1 2, 2 / 2, 2 new: line 6, #define _DARWIN_C_SOURCE (macOS only; reported in every run); line 3 -> 4 _POSIX_C_SOURCE
period.c 21.5, 21.10 1, 1 / 1, 1 unchanged moved: <signal.h> 17 -> 27, <time.h> 21 -> 31
timer.c all 28 / 28 28 / 28 no new finding; moved by the longer file header and the bool ready check: 2.3 131 -> 150; 8.7 163 -> 182; 8.9 150 -> 169; 11.5 196, 386, 389, 396, 420 -> 215, 412, 415, 422, 447; 15.5 378, 383, 401, 425, 463, 468 -> 398, 409, 427, 452, 490, 495 (409 is the existing early return of osadapter_create(), now after the combined check); 17.3 175, 185, 198, 257, 293 (2), 295, 297, 299, 355 -> 194, 204, 217, 276, 312 (2), 314, 316, 318, 374; 21.5 103 -> 122; 21.10 107 -> 126; 2.5, 21.1 line 1
task.c 21.10 1 / 1 0 / 0 gone: line 106, the unused <time.h> (task.c reads no clock; struct timespec comes from period.h, whose own 21.10 is not reported again through task.c)
task.c all others 23 / 23 23 / 23 moved: 2.3 119 -> 139; 8.7 453 -> 481; 8.9 450 -> 478; 11.5 262, 379, 382, 389, 413 -> 282, 406, 409, 416, 441; 15.5 371, 376, 394, 418 -> 392, 403, 421, 446; 17.3 158, 160, 162, 176, 186, 264, 282, 349 -> 178, 180, 182, 196, 206, 284, 302, 369; 21.5 103 -> 124; 2.5, 21.1 line 1

Totals (rule findings, without misra-config): period.c 7 / 8 before, 19 / 18 after; timer.c 28 / 28 before and after; task.c 24 / 24 before, 23 / 23 after. period.h screened on its own (the same command line): 21.5 and 21.10 before and after (<signal.h>, <time.h>, lines 18, 19 -> 48, 50); the new <stdbool.h> adds none. misra-config notes (constants cppcheck's POSIX library does not know): period.c 2 / 3 before (CLOCK_MONOTONIC 47 and, macOS branch, 122; Linux EINTR 102, 104), 3 / 3 after in all three runs (CLOCK_MONOTONIC 79 and 234, ETIMEDOUT 319); timer.c 4 and task.c 4 unchanged in number, moved (timer.c 295, 338, 355, 465 -> 314, 357, 374, 492; task.c 158, 160, 332, 349 -> 178, 180, 352, 369). Free-tier (--enable=warning,style,performance,portability): 0 before and after in all four files. No dynamic memory (the mutex and condition variable are static objects, created once, never deleted after a successful create); the public header change (rte_posix_osadapter.h) is Doxygen only.

Deviations

None recorded yet. The 21.6 (<stdio.h>) findings above are real and not yet formally dispositioned the way RBC_GP's vital A/B code's are (application/RBC_GP/docs/MISRA_COMPLIANCE_REPORT.dox Update 1) — this OSAdapter implements the actual file I/O behind rte_nvm/rte_log, so unlike an application-level <stdio.h> call this is arguably the intended place for it to live (an OSAdapter is exactly where OS-facing calls belong, ADR-005), but that argument has not been written up and reviewed as a formal deviation yet — flagged here rather than asserted.

Rules to watch as this report grows

Rule Where it will bite Plan
Full per-rule sweep, individually reviewed All of src/ Needs the cppcheck MISRA addon rule text or a licensed tool — tracked in root TODO.dox.
rte_posix_osadapter_reboot.c:175's always-true condition resolve_self_exe_path()'s caller Worth a direct look — see Update 1 above.