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

142 lines
3.5 KiB
Markdown

[← Home](../README.md) · [Exec Kernel](README.md)
# 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
```c
/* 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
```c
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
```c
/* 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
```c
/* 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)
```c
struct Message *msg = GetMsg(my_port);
/* Returns NULL if queue is empty */
```
---
## Public Named Ports
```c
/* 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:
```c
/* 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