Contributed by marco on from the wait-long-enough-for-someone-else-to-scratch dept.
Here is what miod came up with:
ENTRY(rfork_thread, 0) SYSCALL(rfork) comb,<> r0, ret0, 1f nop /* * In child process: switch stack, invoke function, then exit. */ /* * PIC code expects 32 bytes of room available below sp. * Then the regular procedure invocation requires us to allocate * 64 bytes as well. */ copy arg1, sp ldo 0(sp), r3 stw,ma r0, HPPA_FRAME_SIZE(sp) stw r0, HPPA_FRAME_CRP(sp) stw r0, HPPA_FRAME_PSP(sp) copy arg3, arg0 /* arg */ copy arg2, t1 bl $$dyncall, r31 copy r31, rp copy r0, arg0 SYSCALL(threxit) 1: bv r0(rp) nop EXIT(rfork_thread)
A couple of comments here. General purpose register 0 (r0) is hardwired to always return 0x00. The hard part of this code was to call the thread. We had to emulate the $$dyncall (dynamic call) mechanism that is defined in the ABI and used by gcc. There is a downside to this code and that is the offset can not be more than a 256k range. Consensus is that this should be sufficient.
What I was doing wrong was that I was setting up the stackframe *before* rfork and fixing it back in the parent before returning to librthread. Another thing I was doing that was unnecessary was to create an additional stack frame; it didn't matter just an extra step.
A couple of people were involved in making this tiny piece of code work. Credit goes to Miod, Kettenis & Mickey. Amazing how simple things can take so long to get right.
(Comments are closed)