amiga-bootcamp/06_exec_os/message_ports.md
Ilia Sharin 21751c0025 docs(amiga): complete AmigaOS 3.1/3.2 developer reference — 172 files across 17 sections
Comprehensive technical documentation covering:
- Hardware: OCS/ECS/AGA custom chip registers, Copper & Blitter deep dives
- Boot sequence: cold boot through startup-sequence
- Binary format: HUNK executable spec, relocation, debug info
- Linking & ABI: .fd files, LVO tables, register calling conventions
- Exec kernel: tasks, interrupts, memory, signals, semaphores
- AmigaDOS: file I/O, FFS/OFS layout, CLI/Shell scripting
- Graphics: planar bitmaps, Copper programming, HAM/EHB modes
- Intuition: screens, windows, IDCMP, BOOPSI
- Devices: trackdisk, SCSI, serial, timer, audio, keyboard
- Libraries: utility, expansion, IFFParse, locale, ARexx
- Networking: bsdsocket API, SANA-II, TCP/IP stack comparison
- Toolchain: GCC, vasm/vlink, SAS/C, NDK, debugging
- Reverse engineering: IDA/Ghidra setup, compiler fingerprints, case studies
- CPU & MMU: 68040/060 emulation libs, PMMU, cache management
- Driver development: SANA-II, Picasso96/RTG, AHI audio

All files include breadcrumb navigation. No local paths or proprietary content.
2026-04-23 12:17:35 -04:00

3.5 KiB

← Home · Exec Kernel

Message Ports — MsgPort, Message, PutMsg, GetMsg, WaitPort

Overview

AmigaOS inter-task communication uses a message passing system. Tasks send Message structures to MsgPort queues. The receiving task either polls (GetMsg) or blocks (WaitPort) for incoming messages. No shared memory is touched without the message handshake.


Core Structures

/* exec/ports.h — NDK39 */

struct MsgPort {
    struct Node  mp_Node;       /* ln_Name = port name (for public ports) */
    UBYTE        mp_Flags;      /* PA_SIGNAL, PA_SOFTINT, PA_IGNORE */
    UBYTE        mp_SigBit;     /* signal bit used for PA_SIGNAL ports */
    APTR         mp_SigTask;    /* task to signal on message arrival */
    struct List  mp_MsgList;    /* queue of pending messages */
};

struct Message {
    struct Node  mn_Node;       /* ln_Type = NT_MESSAGE */
    struct MsgPort *mn_ReplyPort; /* port to send reply to (or NULL) */
    UWORD        mn_Length;     /* total size of message including header */
};

mp_Flags values:

Value Constant Meaning
0 PA_SIGNAL Signal mp_SigTask when message arrives
1 PA_SOFTINT Trigger software interrupt
2 PA_IGNORE Do not wake the task (polling only)

Creating a Message Port

struct MsgPort *port = CreateMsgPort();   /* exec.library LVO -732 (OS 2.0+) */
/* or manually for OS 1.x compatibility: */
struct MsgPort *port = AllocMem(sizeof(struct MsgPort), MEMF_PUBLIC|MEMF_CLEAR);
port->mp_Node.ln_Type = NT_MSGPORT;
port->mp_Flags        = PA_SIGNAL;
port->mp_SigBit       = AllocSignal(-1);   /* any free signal bit */
port->mp_SigTask      = FindTask(NULL);    /* signal current task */
NewList(&port->mp_MsgList);

Sending a Message

/* PutMsg: add message to queue, signal receiver */
PutMsg(target_port, (struct Message *)my_msg);
/* Non-blocking — returns immediately */

PutMsg can be called from interrupt context.


Receiving Messages

/* Block until at least one message arrives: */
WaitPort(my_port);

/* Then drain the queue: */
struct MyMsg *msg;
while ((msg = (struct MyMsg *)GetMsg(my_port)) != NULL) {
    /* process msg */
    ReplyMsg((struct Message *)msg);  /* send reply if mn_ReplyPort != NULL */
}

GetMsg (non-blocking poll)

struct Message *msg = GetMsg(my_port);
/* Returns NULL if queue is empty */

Public Named Ports

/* Register a port so others can find it by name: */
port->mp_Node.ln_Name = "myapp.port";
Forbid();
AddPort(port);
Permit();

/* From another task: */
Forbid();
struct MsgPort *remote = FindPort("myapp.port");
Permit();
if (remote) PutMsg(remote, my_msg);

/* Cleanup: */
Forbid();
RemPort(port);
Permit();

Forbid() is required around FindPort/AddPort/RemPort to prevent the task list from changing mid-operation.


Reply Pattern

The standard request-reply idiom:

/* Sender: */
my_msg->mn_ReplyPort = reply_port;
PutMsg(server_port, &my_msg->mn_Message);
WaitPort(reply_port);
struct MyMsg *reply = (struct MyMsg *)GetMsg(reply_port);
/* reply now contains the server's response */

/* Server: */
WaitPort(server_port);
struct MyMsg *req = (struct MyMsg *)GetMsg(server_port);
/* process req... */
req->result = 42;
ReplyMsg(&req->mn_Message);  /* sends back to req->mn_ReplyPort */

References

  • NDK39: exec/ports.h, exec/messages.h
  • ADCD 2.1: CreateMsgPort, PutMsg, GetMsg, WaitPort, ReplyMsg
  • Amiga ROM Kernel Reference Manual: Exec — messages and ports chapter