Skip to content

Phase 18 arexx integration

Simon Dick edited this page Jun 20, 2026 · 1 revision

Phase 18 — ARexx integration (inbound + outbound)

Part of the Amiga port design log.

ARexx is the Amiga IPC mechanism: every well-behaved app exposes an ARexx port. Both directions implemented. (Phase 32 later adds rexx_exists, rexx_list, and a persistent RexxClient on top of this surface.)

Inbound port

Five C primitives in modamiga.c, RexxMessage facade in amiga.py:

name = amiga.rexx_open()                  # opens MICROPYTHON.1 (or .N)
while True:
    msg = amiga.rexx_recv(timeout_ms=1000)
    if msg is None: continue
    try:    msg.reply(str(eval(msg.command.decode("ascii"))), rc=0)
    except Exception as e: msg.reply(str(e), rc=10)
amiga.rexx_close()

amiga.rexx_serve(lambda cmd: eval(cmd))   # ready-made dispatcher
  • rexx_open(stem="MICROPYTHON") finds the lowest free .N suffix under Forbid()/Permit(), CreateMsgPort() + AddPort().
  • rexx_close() drains the queue (replying rc=20 to anything still queued so a hung rx doesn't stay blocked), RemPort, DeleteMsgPort, closes rexxsyslib.library if opened. Called from main.c on exit as a safety net.
  • rexx_recv(timeout_ms=None) polls then Wait()s. The Phase 25 async timer.device port supplies the timeout signal bit; SIGBREAKF_CTRL_C is always ORed in and raises KeyboardInterrupt if it fires.
  • RexxMessage.reply(result=None, rc=0, secondary=0) sets rm_Result1 = rc. If rc == 0 and result non-None, lazy-opens rexxsyslib.library, CreateArgstring over the bytes, stores in rm_Result2; otherwise secondary goes into rm_Result2. ReplyMsg. __del__ sends an automatic rc=20 reply if the script forgets — a forgotten reply would block the sender forever.

Outbound

result = amiga.rexx("PPAINT.1", "ScreenToFront")           # bytes
rc, result = amiga.rexx("HOST.1", "DoIt", check=False)     # (rc, result|None)

Textbook send-and-wait: FindPort → lazy OpenLibrary("rexxsyslib.library") (cached, two-way scripts pay one open) → CreateMsgPort for private reply port → CreateRexxMsgCreateArgstring for the command → rm_Action = RXCOMM | RXFF_RESULTPutMsgWait(reply | CTRL_C) → unpack rm_Result1/rm_Result2, copy result bytes via mp_obj_new_bytes + LengthArgstring, DeleteArgstring both → DeleteMsgPort.

Ctrl+C is deferred. Once PutMsg is in flight we can't tear down the reply port — the host would PutMsg into freed memory. The wait latches the CTRL_C bit but keeps spinning until the reply is in hand; then KeyboardInterrupt is raised before returning.

rexxsyslib.library missing

Lazy-opened. So import amiga still works, the inbound port works for rc-only replies, but:

  • RexxMessage.reply(result="...", rc=0) → replies rc=10 to sender, raises OSError("rexxsyslib.library unavailable").
  • amiga.rexx(host, command) → raises OSError(...) before any send.

rx script gotcha

call open(...), call writeln(...), call close(...) each clobber the result special variable. Any rx script wanting to inspect the host reply must snapshot it immediately after address:

options results
address MICROPYTHON.1 'some command'
saved_rc = rc
saved_result = result

Clone this wiki locally