exec.library Reference¶
exec.library is the AmigaOS kernel — the lowest-level system library, always present and resident in ROM. It provides task scheduling, memory management, message-passing IPC, interrupt handling, library/device/resource management, signals, semaphores, and timers. All exec functions are called through the global SysBase pointer (memory location $4).
Cache SysBase in a local variable rather than re-reading $4 on every call — it's a documented performance win. Per the FutureOS rules, SysBase->ThisTask is private; use FindTask(NULL) instead.
Tasks vs. Processes¶
This is the single most important distinction in exec:
- Task (
struct Task) — the exec-level scheduling unit. Created viaAddTask(). Tasks cannot calldos.libraryor anything that calls it. They have no DOS file handles, no CLI structure, no current directory. Useful for low-level background work, interrupt servicing, device IO. - Process (
struct Process, extendsstruct Task) — created viados.library/CreateProc()orCreateNewProc(). Processes have DOS context: current directory, CLI structure, file handles, environment variables. Most application code runs as a process.
Minimum stack sizes per the autodoc: ~256 bytes if only calling exec, 4K if calling anything in the system. "DO NOT UNDERESTIMATE."
Memory allocation¶
void *AllocMem(ULONG byteSize, ULONG attributes);
void FreeMem(void *memoryBlock, ULONG byteSize);
void *AllocVec(ULONG byteSize, ULONG attributes); /* V36+ — tracks size */
void FreeVec(void *memoryBlock); /* no size needed */
Key memory flags:
- MEMF_CHIP — chip memory, reachable by custom-chip DMA. Must be set for bitmaps, audio data, copper lists, sprites — anything the hardware touches directly. Without this flag, you may get fast memory and the hardware can't see it.
- MEMF_FAST — fast (CPU-only) memory.
- MEMF_CLEAR — zero the block before returning it.
- MEMF_PUBLIC — memory visible to all tasks; never combine with MEMF_CHIP or MEMF_FAST.
Prefer AllocVec/FreeVec (V36+) over AllocMem/FreeMem — AllocVec records the allocation size so FreeVec doesn't need it, eliminating a class of bugs.
ULONG AvailMem(ULONG attributes);
Returns free memory. Add MEMF_LARGEST to get the size of the largest single free block (useful for knowing if an allocation will succeed).
Signals and Wait¶
Signals are the fundamental IPC primitive — a 32-bit bitmask per task. Up to 16 user signals (SIGB_USER through SIGB_USER+15) can be allocated; the rest are system signals.
BYTE AllocSignal(ULONG signalNum); /* -1 = any available */
void FreeSignal(BYTE signalNum);
ULONG Wait(ULONG signalSet); /* blocks until any signal fires */
void Signal(struct Task *task, ULONG signalSet);
ULONG SetSignal(ULONG newSignals, ULONG signalMask);
Wait() cannot be called from interrupt or supervisor mode. It also breaks any active Forbid() or Disable(). If a signal was already set before Wait() is called, the function returns immediately — no race.
The standard message-port notification signal is obtained automatically when you create a port with CreateMsgPort() (V36+).
Message ports and messages¶
The core IPC pattern for AmigaOS — message ports (struct MsgPort) with queues:
struct MsgPort *CreateMsgPort(void); /* V36 — allocates signal */
void DeleteMsgPort(struct MsgPort *);
void PutMsg(struct MsgPort *port, struct Message *msg);
struct Message *GetMsg(struct MsgPort *port); /* non-blocking; NULL if empty */
struct Message *WaitPort(struct MsgPort *port);/* blocking */
void ReplyMsg(struct Message *msg); /* return to sender */
Pattern: sender PutMsg()s a message to a port. Receiver WaitPort()s on the port, then GetMsg()s the message. After processing, receiver ReplyMsg()s it back. Sender WaitPort()s on the reply port to know it's done.
Never modify a message after sending it until you've received the reply.
IO Requests (device I/O)¶
struct IORequest *CreateIORequest(struct MsgPort *ioReplyPort, ULONG size);
void DeleteIORequest(struct IORequest *);
LONG DoIO(struct IORequest *ioReq); /* synchronous — returns when done */
void SendIO(struct IORequest *ioReq); /* asynchronous — returns immediately */
BOOL CheckIO(struct IORequest *ioReq); /* non-blocking completion check */
LONG WaitIO(struct IORequest *ioReq); /* wait for async IO */
LONG AbortIO(struct IORequest *ioReq); /* try to abort pending IO */
DoIO = blocking convenience (send + wait). SendIO + WaitIO = async pattern (fire off multiple IOs, wait later).
Semaphores (V36+)¶
The correct synchronization primitive for shared data, per the FutureOS rules:
void InitSemaphore(struct SignalSemaphore *sigSem);
void ObtainSemaphore(struct SignalSemaphore *sigSem); /* exclusive */
void ObtainSemaphoreShared(struct SignalSemaphore *sigSem); /* shared/read */
LONG AttemptSemaphore(struct SignalSemaphore *sigSem); /* non-blocking */
void ReleaseSemaphore(struct SignalSemaphore *sigSem);
Semaphores are reentrant from the same task for exclusive locks — obtaining twice from the same task is fine; you must release twice. Shared locks allow multiple concurrent readers.
Avoid
Forbid()/Disable()for synchronization — use semaphores instead.Forbid()only disables task switching (not interrupts);Disable()disables interrupts entirely. Both are called out as dangerous in the FutureOS compatibility notes.
Library management¶
struct Library *OpenLibrary(STRPTR libName, ULONG minVersion);
void CloseLibrary(struct Library *library);
minVersion = the minimum library version your code requires (e.g., 37 for V37/V2.04 features). Returns NULL if not found or version too old. Always check the return value.
OldOpenLibrary() ignores the version requirement and will eventually Alert() in future OS versions — do not use.
Alert() (Guru Meditation)¶
void Alert(ULONG alertNum);
Alert number format: the high bit (AT_DeadEnd, 0x80000000) determines whether the system halts (Guru Meditation) or the alert is recoverable. Alert() is the last-resort error mechanism for unrecoverable errors.
SAD — Simple Amiga Debugging Kernel (V39+)¶
Built into exec from V39. Communicates via the motherboard serial port at 9600 baud. Requires only that ExecBase be valid — does not need the full OS running. Supports read/write memory, get register frame, JSR to address, and return-to-system. Used by external debuggers like wack.
Status: Outdated (V46.37, AmigaOS 3.1.4/3.2). SAD was removed: "The sad story of SAD ends here. ROMWack is back." ROMWack replaced SAD in exec V46.37. On OS 3.2 use ROMWack / mmu.library-based MuForce instead. See AmigaOS 3.2 — What Changed for Developers.
AmigaOS 3.2 (V47) exec changes¶
If you target OS 3.2, several exec internals documented above changed (see AmigaOS 3.2 — What Changed for Developers):
- Task trees and AVL trees were removed. Any use ends in a recoverable alert and returns zero — they were never fully functional.
- Memory pools reverted to the V40 puddle scheme ("just without the V40 bugs"); released puddles bubble to the top immediately.
- Coldstart detects a 68060 FPU and suppresses the bogus FPU-present report (the
68060.libraryowns FPU handling). - On 68040+,
ExitIntrdoes an extra custom-register access to suppress spurious interrupts.
exec functions to avoid (per FutureOS rules)¶
These exec functions are on the forbidden/restricted list for future compatibility: AllocAbs, AllocTrap, Disable, Enable, Forbid, FreeTrap, GetCC, ObtainQuickVector, OldOpenLibrary, Permit, SetExcept, SetFunction, SetIntVector, SetSR, SetTaskPri, SuperState, Supervisor, UserState.
See Also¶
- mmu.library
- exec Memory Pools — the puddle/threshold scheme in depth, with the
show_memory_pool_insights()diagnostic (NDK 3.2 R4). - 68000 Programming Model
- dos.library Reference
- AmigaOS 3.2 — What Changed for Developers
- PowerPC and Future-OS Compatibility Rules
- AmigaOS Programming Philosophy
Sources: Commodore-Amiga / ESCOM AG, exec.library Autodoc + Function Descriptors (1985-1996); Hyperion Entertainment, NDK 3.2 exec RelNotes (2016-2021).
Raw: raw/exec/exec-library.md; raw/architecture/os-3.2-release-notes.md; raw/tutorials/amiga-system-prog-guide.md
Updated: 2026-08-09
Updated: 2026-08-08