Skip to content

POSIX compatibility layer does not work on 64-bit ports #628

Description

@fdesbiens

The POSIX compatibility layer cannot work on a 64-bit port. It compiles there and produces a library, but its message queues corrupt the pointer they carry, and the configuration that would fix that does not build. This came out of wiring the layer into CMake in #626.

Why it is broken as it stands

The layer passes a message by allocating a private buffer, copying the caller's data into it and putting the buffer's address into a ThreadX queue. ULONG is 32 bits on every ThreadX port, including the 64-bit ones, so on a 64-bit target that address does not fit in a message word.

tx_posix.h accounts for this with TX_64_BIT, which widens the message and splits the pointer across two words:

#ifdef TX_64_BIT
#define TX_POSIX_MESSAGE_SIZE           5
#else
#define TX_POSIX_MESSAGE_SIZE           4
#endif

with matching code in px_mq_send.c:198 and px_mq_receive.c:209. Without TX_64_BIT the send truncates the pointer and the receive casts the truncated value back. The compiler says nothing worse than a warning, which is why the target builds cleanly on AArch64 and RV64:

px_mq_send.c:205:14: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
px_mq_receive.c:214:27: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]

Why defining TX_64_BIT does not fix it

TX_64_BIT is never defined by any port; it is only ever tested. Defining it makes tx_api.h use the extension pointer macros, which need tx_thread_extension_ptr in the thread control block:

px_pth_create.c:235:5: error: 'TX_THREAD' has no member named 'tx_thread_extension_ptr'
px_pth_init.c:361:5:   error: 'TX_THREAD' has no member named 'tx_thread_extension_ptr'

Outside ports_smp and ports/linux, no port declares it. None of risc-v64, cortex_a53, cortex_a55 or cortex_a34 does.

What I measured

I prototyped the whole thing on risc-v64 to find out how much is actually missing.

The port change is one line. risc-v64 has an empty slot already:

#define TX_THREAD_EXTENSION_3                   VOID        *tx_thread_extension_ptr;

cortex_a53 and the other 64-bit Arm ports have a free slot too. This is the same declaration ports_smp/cortex_a72_smp already carries.

With that line and -DTX_64_BIT, the layer compiles clean. All 106 sources plus the #626 tests, riscv64-unknown-elf, -Werror, no warnings.

But it deadlocks at runtime. Built for risc-v64 and run under qemu-system-riscv64, the test produces no output at all. Attaching gdb shows the system parked in the idle loop with nothing runnable:

#0  _tx_thread_schedule_loop () at ports/risc-v64/gnu/src/tx_thread_schedule.S:77
#1  _tx_thread_system_suspend (thread_ptr=0x801012d0 <ptcb_pool>) at common/src/tx_thread_system_suspend.c:372

with these threads:

thread state meaning
System Timer Thread 3 suspended
test control thread 3 suspended
POSIX System Manager 5 waiting on its work queue (expected)
pthr 4 TX_SLEEP

The worker pthread is asleep although the test never sleeps, and nothing wakes it. The same BSP and QEMU invocation run the stock ThreadX RISC-V64 regression tests without trouble, so this is the layer rather than the port or the harness.

What is already correct

Worth recording, because it narrows the search. Every TX_64_BIT path I checked handles 64 bits properly:

  • px_mq_send.c:198 / px_mq_receive.c:209 — the message pointer split.
  • px_pth_init.c:720 / px_system_manager.c:87 — the work request pack and unpack.
  • WORK_REQ_SIZE in tx_posix.h:257 — already scales by sizeof(ALIGN_TYPE)/sizeof(ULONG).

So the 64-bit paths were written plausibly; they appear never to have been executed. The remaining defect is somewhere less obvious, and there is likely more than one.

Suggested work

  1. Add tx_thread_extension_ptr to the 64-bit ports. Trivial, but the generated ports need regenerating rather than hand-editing.
  2. Debug the deadlock, and whatever it uncovers.
  3. Re-enable the 64-bit tests. Added the POSIX compatibility layer to the CMake build, with regression tests #626 already handles both widths; test/posix/cmake/CMakeLists.txt currently stops with an explanation for risc-v64, and that becomes add_compile_options(-DTX_64_BIT).
  4. Consider making the silent truncation loud, so a 64-bit build without TX_64_BIT fails instead of producing a library whose queues do not work.

Step 1 is an hour. Step 2 is the real cost: it is bring-up of code that has never run, so it is hard to bound. #626 gives somewhere to run it.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions