mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-13 00:26:28 +00:00
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.
This commit is contained in:
parent
f07a368bf1
commit
21751c0025
172 changed files with 19701 additions and 0 deletions
18
07_dos/README.md
Normal file
18
07_dos/README.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
[← Home](../README.md)
|
||||
|
||||
# dos.library — AmigaDOS Overview
|
||||
|
||||
## Section Index
|
||||
|
||||
| File | Description |
|
||||
|---|---|
|
||||
| [dos_base.md](dos_base.md) | DosLibrary structure and global state |
|
||||
| [file_io.md](file_io.md) | Open, Close, Read, Write, Seek |
|
||||
| [locks_examine.md](locks_examine.md) | Lock, UnLock, Examine, ExNext, ExAll |
|
||||
| [pattern_matching.md](pattern_matching.md) | ParsePattern, MatchPattern, wildcards |
|
||||
| [process_management.md](process_management.md) | CreateNewProc, SystemTagList, Execute |
|
||||
| [packet_system.md](packet_system.md) | DosPacket, ACTION_* codes, handler protocol |
|
||||
| [filesystem.md](filesystem.md) | FFS/OFS layout, block structure |
|
||||
| [environment.md](environment.md) | GetVar/SetVar, local/global env variables |
|
||||
| [error_handling.md](error_handling.md) | IoErr, Fault, PrintFault, error codes |
|
||||
| [cli_shell.md](cli_shell.md) | CLI/Shell: pipes, redirection, scripts, ReadArgs |
|
||||
176
07_dos/cli_shell.md
Normal file
176
07_dos/cli_shell.md
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
[← Home](../README.md) · [AmigaDOS](README.md)
|
||||
|
||||
# CLI and Shell — Command Interpreter
|
||||
|
||||
## Overview
|
||||
|
||||
The AmigaDOS **Shell** (called CLI in OS 1.x) is the command-line interface. It processes scripts, handles I/O redirection, pipes, and environment variable expansion. Understanding Shell internals is essential for writing scripts and understanding process creation.
|
||||
|
||||
---
|
||||
|
||||
## Shell vs CLI
|
||||
|
||||
| Feature | CLI (OS 1.x) | Shell (OS 2.0+) |
|
||||
|---|---|---|
|
||||
| Command history | No | Yes |
|
||||
| Line editing | Minimal | Full (cursor keys, delete) |
|
||||
| Pipes | No | Yes (`|` and `|&`) |
|
||||
| Wildcards | Manual `#?` | Automatic in `Dir`, `List`, etc. |
|
||||
| Resident commands | No | Yes (`Resident` command) |
|
||||
| Background execution | `Run` only | `Run` + `&` suffix |
|
||||
|
||||
---
|
||||
|
||||
## I/O Redirection
|
||||
|
||||
```
|
||||
; Redirect output to file:
|
||||
Dir >RAM:listing.txt SYS:
|
||||
|
||||
; Redirect input from file:
|
||||
Type <RAM:data.txt
|
||||
|
||||
; Append output:
|
||||
Echo "log entry" >>RAM:log.txt
|
||||
|
||||
; Discard output:
|
||||
Copy >NIL: file1 file2
|
||||
|
||||
; Redirect stderr (error output) — OS 2.0+:
|
||||
command *>RAM:errors.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pipes
|
||||
|
||||
```
|
||||
; Pipe output of one command to input of another:
|
||||
List SYS:C | Sort | More
|
||||
|
||||
; Pipe both stdout and stderr:
|
||||
command |& Filter
|
||||
```
|
||||
|
||||
Pipes create temporary files in `T:` (assigned to `RAM:T`). Not true Unix-style byte streams.
|
||||
|
||||
---
|
||||
|
||||
## Script Execution
|
||||
|
||||
Scripts are text files executed line by line. Use `.` or `Execute`:
|
||||
|
||||
```
|
||||
; Run a script:
|
||||
Execute S:MyScript
|
||||
|
||||
; Or make executable and run directly (with Execute bit set):
|
||||
Protect S:MyScript +s
|
||||
S:MyScript
|
||||
```
|
||||
|
||||
### Script Control Structures
|
||||
|
||||
```
|
||||
; Conditional:
|
||||
IF EXISTS SYS:Libs/68040.library
|
||||
Echo "68040 detected"
|
||||
ELSE
|
||||
Echo "No 68040"
|
||||
ENDIF
|
||||
|
||||
; Loop:
|
||||
LAB loop
|
||||
Echo "iteration"
|
||||
SKIP loop
|
||||
|
||||
; Fail handling:
|
||||
FailAt 21
|
||||
Copy SYS:Missing RAM:
|
||||
IF WARN
|
||||
Echo "Copy had warnings"
|
||||
ENDIF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ReadArgs — Argument Parsing
|
||||
|
||||
AmigaDOS provides `ReadArgs()` for standardised argument parsing:
|
||||
|
||||
```c
|
||||
/* Template syntax: KEYWORD/A = required, /S = switch, /K = keyword,
|
||||
/N = numeric, /M = multi, /F = rest-of-line */
|
||||
LONG args[4] = {0};
|
||||
struct RDArgs *rd = ReadArgs("FROM/A,TO/A,ALL/S,BUFFER/K/N", args, NULL);
|
||||
if (rd) {
|
||||
char *from = (char *)args[0];
|
||||
char *to = (char *)args[1];
|
||||
BOOL all = (BOOL)args[2];
|
||||
LONG *bufsize = (LONG *)args[3];
|
||||
FreeArgs(rd);
|
||||
}
|
||||
```
|
||||
|
||||
### Template Format
|
||||
|
||||
| Qualifier | Meaning | Example |
|
||||
|---|---|---|
|
||||
| `/A` | Required argument | `FROM/A` |
|
||||
| `/K` | Keyword (must use keyword=value) | `PUBSCREEN/K` |
|
||||
| `/S` | Switch (boolean flag) | `ALL/S` |
|
||||
| `/N` | Numeric value | `BUF/N` |
|
||||
| `/M` | Multiple values (array) | `FILES/M` |
|
||||
| `/F` | Rest of line (to end) | `CMD/F` |
|
||||
| `=` | Alias | `FILE=FROM/A` |
|
||||
|
||||
---
|
||||
|
||||
## Resident Commands
|
||||
|
||||
Frequently used commands can be made **resident** (kept in RAM):
|
||||
|
||||
```
|
||||
; Make a command resident:
|
||||
Resident C:Dir PURE
|
||||
Resident C:List PURE
|
||||
Resident C:Copy PURE
|
||||
|
||||
; List resident commands:
|
||||
Resident
|
||||
|
||||
; Remove:
|
||||
Resident C:Dir REMOVE
|
||||
```
|
||||
|
||||
Requires the binary to be compiled as `PURE` (position-independent, no writeable globals in code section).
|
||||
|
||||
---
|
||||
|
||||
## Built-in Shell Commands
|
||||
|
||||
| Command | Description |
|
||||
|---|---|
|
||||
| `CD` | Change directory |
|
||||
| `Echo` | Print text |
|
||||
| `If/Else/EndIf` | Conditional |
|
||||
| `Skip/Lab` | Loop |
|
||||
| `FailAt` | Set error threshold |
|
||||
| `Set/Unset` | Local variables |
|
||||
| `SetEnv/GetEnv` | Global (ENV:) variables |
|
||||
| `Alias` | Command aliases |
|
||||
| `Path` | Manage command search path |
|
||||
| `Prompt` | Set shell prompt |
|
||||
| `Protect` | Set file protection bits |
|
||||
| `Run` | Execute command in background |
|
||||
| `Execute` | Run script file |
|
||||
| `EndCLI` | Close this shell |
|
||||
| `NewCLI`/`NewShell` | Open new shell |
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `dos/rdargs.h`
|
||||
- RKRM: Shell chapter
|
||||
- ADCD 2.1: AmigaDOS Guide
|
||||
77
07_dos/dos_base.md
Normal file
77
07_dos/dos_base.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
[← Home](../README.md) · [AmigaDOS](README.md)
|
||||
|
||||
# DosLibrary — Structure and Global State
|
||||
|
||||
## Overview
|
||||
|
||||
`dos.library` is opened by nearly every Amiga program. The library base `DOSBase` is a `struct DosLibrary` that extends `struct Library` with process-level state, the root node, and handler management.
|
||||
|
||||
---
|
||||
|
||||
## struct DosLibrary
|
||||
|
||||
```c
|
||||
/* dos/dosextens.h — NDK39 */
|
||||
struct DosLibrary {
|
||||
struct Library dl_lib; /* standard Library header */
|
||||
struct RootNode *dl_Root; /* pointer to the system root node */
|
||||
APTR dl_GV; /* BCPL global vector */
|
||||
LONG dl_A2; /* BCPL scratch */
|
||||
LONG dl_A5; /* BCPL scratch */
|
||||
LONG dl_A6; /* BCPL scratch */
|
||||
struct ErrorString *dl_Errors; /* error string table */
|
||||
struct timerequest *dl_TimeReq; /* timer.device request */
|
||||
struct Library *dl_UtilityBase; /* cached UtilityBase */
|
||||
struct Library *dl_IntuitionBase;/* cached IntuitionBase */
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## struct RootNode
|
||||
|
||||
```c
|
||||
struct RootNode {
|
||||
BPTR rn_TaskArray; /* BPTR to CLI task array */
|
||||
BPTR rn_ConsoleSegment; /* console handler segment */
|
||||
struct DateStamp rn_Time; /* current system time */
|
||||
LONG rn_RestartSeg; /* restart segment */
|
||||
BPTR rn_Info; /* BPTR to DosInfo */
|
||||
BPTR rn_FileHandlerSegment;
|
||||
struct MinList rn_CliList; /* list of CLI processes */
|
||||
/* ... OS 3.x additions ... */
|
||||
ULONG rn_BootFlags;
|
||||
APTR rn_BootProc;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Opening dos.library
|
||||
|
||||
```c
|
||||
struct DosLibrary *DOSBase;
|
||||
DOSBase = (struct DosLibrary *)OpenLibrary("dos.library", 40);
|
||||
if (!DOSBase) { /* OS 3.1 or later required */ }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## BCPL Heritage
|
||||
|
||||
AmigaDOS was originally written in BCPL. Artifacts remain:
|
||||
- **BPTR** — pointers right-shifted by 2 (`real = bptr << 2`)
|
||||
- `dl_GV` — BCPL global vector (used internally by filesystem handlers)
|
||||
- File handles and locks are BPTRs, not real pointers
|
||||
|
||||
```c
|
||||
/* Convert BPTR to C pointer: */
|
||||
#define BADDR(bptr) ((APTR)((ULONG)(bptr) << 2))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `dos/dosextens.h`, `dos/dos.h`
|
||||
- ADCD 2.1: dos.library autodocs
|
||||
67
07_dos/environment.md
Normal file
67
07_dos/environment.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
[← Home](../README.md) · [AmigaDOS](README.md)
|
||||
|
||||
# Environment Variables — GetVar, SetVar
|
||||
|
||||
## Overview
|
||||
|
||||
AmigaDOS supports both **local** (per-process) and **global** (system-wide) environment variables. Local variables are stored in the process's `pr_LocalVars` MinList; global variables are stored as files in `ENV:` (RAM-backed) and `ENVARC:` (persistent on disk).
|
||||
|
||||
---
|
||||
|
||||
## API
|
||||
|
||||
| LVO | Function | Description |
|
||||
|---|---|---|
|
||||
| −900 | `GetVar(name, buf, size, flags)` | Read a variable |
|
||||
| −906 | `SetVar(name, buf, size, flags)` | Set or create a variable |
|
||||
| −912 | `DeleteVar(name, flags)` | Remove a variable |
|
||||
| −918 | `FindVar(name, type)` | Find a LocalVar node |
|
||||
|
||||
### Flags
|
||||
|
||||
```c
|
||||
/* dos/var.h — NDK39 */
|
||||
#define GVF_GLOBAL_ONLY 0x100 /* search only ENV: */
|
||||
#define GVF_LOCAL_ONLY 0x200 /* search only pr_LocalVars */
|
||||
#define GVF_BINARY_VAR 0x10 /* treat value as binary data */
|
||||
#define GVF_DONT_NULL_TERM 0x20 /* don't null-terminate result */
|
||||
#define LV_VAR 0 /* standard variable */
|
||||
#define LV_ALIAS 1 /* shell alias */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```c
|
||||
/* Set a global variable: */
|
||||
SetVar("EDITOR", "ed", -1, GVF_GLOBAL_ONLY);
|
||||
|
||||
/* Read it back: */
|
||||
char buf[256];
|
||||
if (GetVar("EDITOR", buf, sizeof(buf), 0) >= 0) {
|
||||
Printf("EDITOR = %s\n", buf);
|
||||
}
|
||||
|
||||
/* Delete: */
|
||||
DeleteVar("EDITOR", GVF_GLOBAL_ONLY);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Storage Locations
|
||||
|
||||
| Scope | Storage | Persistent? |
|
||||
|---|---|---|
|
||||
| Local | `pr_LocalVars` MinList (in-memory) | No — dies with process |
|
||||
| Global (volatile) | `ENV:` — assign to `RAM:Env/` | No — lost on reboot |
|
||||
| Global (persistent) | `ENVARC:` — assign to `SYS:Prefs/Env-Archive/` | Yes — survives reboot |
|
||||
|
||||
The startup-sequence copies `ENVARC:` to `ENV:` at boot.
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `dos/var.h`
|
||||
- ADCD 2.1: `GetVar`, `SetVar`, `DeleteVar`
|
||||
89
07_dos/error_handling.md
Normal file
89
07_dos/error_handling.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
[← Home](../README.md) · [AmigaDOS](README.md)
|
||||
|
||||
# Error Handling — IoErr, Fault, PrintFault, Error Codes
|
||||
|
||||
## Overview
|
||||
|
||||
Every DOS function that can fail sets an error code retrievable via `IoErr()`. The error code is stored in `pr_Result2` of the calling process.
|
||||
|
||||
---
|
||||
|
||||
## API
|
||||
|
||||
| LVO | Function | Description |
|
||||
|---|---|---|
|
||||
| −132 | `IoErr()` | Return last error code |
|
||||
| −138 | `SetIoErr(code)` | Set error code manually |
|
||||
| −468 | `Fault(code, header, buf, len)` | Format error message into buffer |
|
||||
| −474 | `PrintFault(code, header)` | Print error message to stderr |
|
||||
|
||||
---
|
||||
|
||||
## Complete Error Code Table
|
||||
|
||||
| Code | Constant | Meaning |
|
||||
|---|---|---|
|
||||
| 103 | `ERROR_NO_FREE_STORE` | Out of memory |
|
||||
| 104 | `ERROR_TASK_TABLE_FULL` | Process table full |
|
||||
| 114 | `ERROR_BAD_TEMPLATE` | Bad template for ReadArgs |
|
||||
| 115 | `ERROR_BAD_NUMBER` | Bad number in argument |
|
||||
| 116 | `ERROR_REQUIRED_ARG_MISSING` | Required argument missing |
|
||||
| 117 | `ERROR_KEY_NEEDS_ARG` | Keyword requires an argument |
|
||||
| 118 | `ERROR_TOO_MANY_ARGS` | Too many arguments |
|
||||
| 119 | `ERROR_UNMATCHED_QUOTES` | Unmatched quotes |
|
||||
| 120 | `ERROR_LINE_TOO_LONG` | Argument line too long |
|
||||
| 121 | `ERROR_FILE_NOT_OBJECT` | Not a valid executable |
|
||||
| 122 | `ERROR_INVALID_RESIDENT_LIBRARY` | Invalid resident library |
|
||||
| 202 | `ERROR_OBJECT_IN_USE` | Object is in use |
|
||||
| 203 | `ERROR_OBJECT_EXISTS` | Object already exists |
|
||||
| 204 | `ERROR_DIR_NOT_FOUND` | Directory not found |
|
||||
| 205 | `ERROR_OBJECT_NOT_FOUND` | Object not found |
|
||||
| 206 | `ERROR_BAD_STREAM_NAME` | Invalid stream name |
|
||||
| 207 | `ERROR_OBJECT_TOO_LARGE` | Object too large |
|
||||
| 209 | `ERROR_ACTION_NOT_KNOWN` | Action not known (by handler) |
|
||||
| 210 | `ERROR_INVALID_COMPONENT_NAME` | Invalid filename component |
|
||||
| 211 | `ERROR_INVALID_LOCK` | Invalid lock |
|
||||
| 212 | `ERROR_OBJECT_WRONG_TYPE` | Object wrong type |
|
||||
| 213 | `ERROR_DISK_NOT_VALIDATED` | Disk not validated |
|
||||
| 214 | `ERROR_DISK_WRITE_PROTECTED` | Disk is write-protected |
|
||||
| 215 | `ERROR_RENAME_ACROSS_DEVICES` | Rename across devices |
|
||||
| 216 | `ERROR_DIRECTORY_NOT_EMPTY` | Directory not empty |
|
||||
| 217 | `ERROR_TOO_MANY_LEVELS` | Too many directory levels |
|
||||
| 218 | `ERROR_DEVICE_NOT_MOUNTED` | Device not mounted |
|
||||
| 219 | `ERROR_SEEK_ERROR` | Seek error |
|
||||
| 220 | `ERROR_COMMENT_TOO_BIG` | Comment too big |
|
||||
| 221 | `ERROR_DISK_FULL` | Disk full |
|
||||
| 222 | `ERROR_DELETE_PROTECTED` | Delete protected |
|
||||
| 223 | `ERROR_WRITE_PROTECTED` | Write protected |
|
||||
| 224 | `ERROR_READ_PROTECTED` | Read protected |
|
||||
| 225 | `ERROR_NOT_A_DOS_DISK` | Not a DOS disk |
|
||||
| 226 | `ERROR_NO_DISK` | No disk in drive |
|
||||
| 232 | `ERROR_NO_MORE_ENTRIES` | No more directory entries |
|
||||
| 233 | `ERROR_IS_SOFT_LINK` | Object is a soft link |
|
||||
| 234 | `ERROR_OBJECT_LINKED` | Object is hard-linked |
|
||||
| 235 | `ERROR_BAD_HUNK` | Bad hunk in executable |
|
||||
| 236 | `ERROR_NOT_IMPLEMENTED` | Function not implemented |
|
||||
| 240 | `ERROR_RECORD_NOT_LOCKED` | Record not locked |
|
||||
| 241 | `ERROR_LOCK_COLLISION` | Record lock collision |
|
||||
| 242 | `ERROR_LOCK_TIMEOUT` | Record lock timeout |
|
||||
| 243 | `ERROR_UNLOCK_ERROR` | Unlock error |
|
||||
|
||||
---
|
||||
|
||||
## Usage Pattern
|
||||
|
||||
```c
|
||||
BPTR fh = Open("nonexistent", MODE_OLDFILE);
|
||||
if (!fh) {
|
||||
LONG err = IoErr();
|
||||
PrintFault(err, "myapp");
|
||||
/* prints: "myapp: Object not found" */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `dos/dos.h`, `dos/dosasl.h`
|
||||
- ADCD 2.1: `IoErr`, `Fault`, `PrintFault`
|
||||
107
07_dos/file_io.md
Normal file
107
07_dos/file_io.md
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
[← Home](../README.md) · [AmigaDOS](README.md)
|
||||
|
||||
# File I/O — Open, Close, Read, Write, Seek
|
||||
|
||||
## Overview
|
||||
|
||||
AmigaDOS file I/O is synchronous from the caller's perspective. All functions use `BPTR` file handles and communicate errors via `IoErr()`.
|
||||
|
||||
---
|
||||
|
||||
## Core Functions
|
||||
|
||||
| LVO | Function | Registers | Returns |
|
||||
|---|---|---|---|
|
||||
| −30 | `Open(name, mode)` | D1=name, D2=mode | D0=BPTR handle (0=fail) |
|
||||
| −36 | `Close(fh)` | D1=handle | D0=BOOL |
|
||||
| −42 | `Read(fh, buf, len)` | D1=handle, D2=buf, D3=len | D0=actual bytes (−1=error) |
|
||||
| −48 | `Write(fh, buf, len)` | D1=handle, D2=buf, D3=len | D0=actual bytes (−1=error) |
|
||||
| −66 | `Seek(fh, pos, mode)` | D1=handle, D2=pos, D3=mode | D0=old position (−1=error) |
|
||||
|
||||
---
|
||||
|
||||
## Access Modes
|
||||
|
||||
```c
|
||||
/* dos/dos.h — NDK39 */
|
||||
#define MODE_READWRITE 1004 /* open existing, read+write */
|
||||
#define MODE_OLDFILE 1005 /* open existing, read only */
|
||||
#define MODE_NEWFILE 1006 /* create new (truncate if exists) */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Seek Modes
|
||||
|
||||
```c
|
||||
#define OFFSET_BEGINNING -1 /* from start of file */
|
||||
#define OFFSET_CURRENT 0 /* from current position */
|
||||
#define OFFSET_END 1 /* from end of file */
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File Handle (BPTR)
|
||||
|
||||
The returned handle is a BPTR to a `struct FileHandle`:
|
||||
|
||||
```c
|
||||
struct FileHandle {
|
||||
struct Message *fh_Link;
|
||||
struct MsgPort *fh_Interactive; /* non-NULL if console */
|
||||
struct MsgPort *fh_Type; /* handler process port */
|
||||
BPTR fh_Buf; /* I/O buffer (BPTR) */
|
||||
LONG fh_Pos; /* current position in buffer */
|
||||
LONG fh_End; /* end of valid data in buffer */
|
||||
LONG fh_Funcs; /* unused */
|
||||
LONG fh_Func2; /* unused */
|
||||
LONG fh_Func3; /* unused */
|
||||
LONG fh_Args; /* packet args */
|
||||
BPTR fh_Arg2;
|
||||
};
|
||||
```
|
||||
|
||||
To access as a C pointer: `struct FileHandle *fh = BADDR(handle);`
|
||||
|
||||
---
|
||||
|
||||
## Usage Example
|
||||
|
||||
```c
|
||||
BPTR fh = Open("RAM:test.txt", MODE_NEWFILE);
|
||||
if (fh) {
|
||||
Write(fh, "Hello Amiga\n", 12);
|
||||
Close(fh);
|
||||
}
|
||||
|
||||
fh = Open("RAM:test.txt", MODE_OLDFILE);
|
||||
if (fh) {
|
||||
UBYTE buf[64];
|
||||
LONG n = Read(fh, buf, sizeof(buf));
|
||||
if (n > 0) Write(Output(), buf, n); /* echo to stdout */
|
||||
Close(fh);
|
||||
} else {
|
||||
PrintFault(IoErr(), "Open failed");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Error Checking
|
||||
|
||||
```c
|
||||
LONG err = IoErr(); /* LVO −66 — returns last DOS error code */
|
||||
/* Common codes: */
|
||||
#define ERROR_OBJECT_NOT_FOUND 205
|
||||
#define ERROR_OBJECT_EXISTS 203
|
||||
#define ERROR_DISK_FULL 221
|
||||
#define ERROR_SEEK_ERROR 219
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `dos/dos.h`, `dos/dosextens.h`
|
||||
- `07_dos/error_handling.md` — full error code list
|
||||
- ADCD 2.1: `Open`, `Close`, `Read`, `Write`, `Seek`
|
||||
90
07_dos/filesystem.md
Normal file
90
07_dos/filesystem.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
[← Home](../README.md) · [AmigaDOS](README.md)
|
||||
|
||||
# Filesystem — FFS/OFS Block Structure
|
||||
|
||||
## Overview
|
||||
|
||||
AmigaOS supports two native filesystem types: **OFS** (Old File System, OS 1.x) and **FFS** (Fast File System, OS 2.0+). Both use a block-based layout with 512-byte blocks. FFS differs by storing data blocks without headers, improving throughput.
|
||||
|
||||
---
|
||||
|
||||
## Block Types
|
||||
|
||||
| Block | Type ID | Description |
|
||||
|---|---|---|
|
||||
| Boot block | `"DOS\0"` / `"DOS\1"` | Blocks 0–1; OFS=`DOS\0`, FFS=`DOS\1` |
|
||||
| Root block | `T_HEADER` (2) | Always at middle of partition; directory root |
|
||||
| File header | `T_HEADER` (2) | Metadata for one file |
|
||||
| Directory header | `T_HEADER` (2) | Metadata for one directory |
|
||||
| Data block | `T_DATA` (8) | OFS: header + data; FFS: pure data |
|
||||
| File extension | `T_LIST` (16) | Overflow pointer table for large files |
|
||||
| Hash chain | — | Root/dir blocks have a 72-entry hash table |
|
||||
|
||||
---
|
||||
|
||||
## Root Block Layout (Simplified)
|
||||
|
||||
| Offset | Field | Description |
|
||||
|---|---|---|
|
||||
| 0 | `type` | Always 2 (`T_HEADER`) |
|
||||
| 4 | `header_key` | Own block number |
|
||||
| 8 | `high_seq` | Number of data blocks in hash table |
|
||||
| 12 | `ht_size` | Hash table size (usually 72) |
|
||||
| 16 | `first_data` | Unused |
|
||||
| 20 | `checksum` | Block checksum |
|
||||
| 24–312 | `ht[72]` | Hash table: block pointers for directory entries |
|
||||
| 420 | `bm_flag` | Bitmap valid flag (`-1` = valid) |
|
||||
| 424–472 | `bm_pages[25]` | Pointers to bitmap blocks |
|
||||
| 484 | `last_altered_days` | Modification date |
|
||||
| 504 | `disk_name` | BSTR: volume name |
|
||||
|
||||
---
|
||||
|
||||
## Hash Function
|
||||
|
||||
File/directory names are hashed into the 72-slot table:
|
||||
|
||||
```c
|
||||
ULONG hash_name(const char *name, int table_size) {
|
||||
ULONG hash = strlen(name);
|
||||
for (int i = 0; name[i]; i++) {
|
||||
hash = hash * 13 + toupper(name[i]);
|
||||
hash &= 0x7FF;
|
||||
}
|
||||
return hash % table_size;
|
||||
}
|
||||
```
|
||||
|
||||
Collisions are resolved by chaining: each file/dir header has a `hash_chain` pointer to the next entry in the same slot.
|
||||
|
||||
---
|
||||
|
||||
## OFS vs FFS
|
||||
|
||||
| Feature | OFS (`DOS\0`) | FFS (`DOS\1`) |
|
||||
|---|---|---|
|
||||
| Data blocks | 24-byte header + 488 bytes data | Pure 512 bytes data |
|
||||
| Max filename | 30 chars | 30 chars |
|
||||
| International | No | `DOS\2` (INTL OFS), `DOS\3` (INTL FFS) |
|
||||
| Dir cache | No | `DOS\4` (FFS + dir cache) |
|
||||
| Throughput | ~488/512 = 95% efficiency | 100% efficiency |
|
||||
|
||||
---
|
||||
|
||||
## Checksum Algorithm
|
||||
|
||||
```c
|
||||
LONG compute_checksum(ULONG *block, int longs) {
|
||||
LONG sum = 0;
|
||||
for (int i = 0; i < longs; i++) sum += block[i];
|
||||
return -sum; /* stored in the checksum field to make total = 0 */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `dos/filehandler.h`
|
||||
- Ralph Babel: *The AmigaDOS Manual* (3rd edition) — definitive FFS reference
|
||||
- Laurent Clevy: *The Amiga Filesystem* — http://lclevy.free.fr/adflib/
|
||||
126
07_dos/locks_examine.md
Normal file
126
07_dos/locks_examine.md
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
[← Home](../README.md) · [AmigaDOS](README.md)
|
||||
|
||||
# Locks and Examine — Lock, UnLock, Examine, ExNext, ExAll
|
||||
|
||||
## Overview
|
||||
|
||||
AmigaDOS uses **locks** to reference files and directories. A lock is a BPTR to a `FileLock` structure. Locks provide exclusive or shared access and are used for directory scanning, attribute reading, and path resolution.
|
||||
|
||||
---
|
||||
|
||||
## Lock Types
|
||||
|
||||
```c
|
||||
/* dos/dos.h */
|
||||
#define SHARED_LOCK -2 /* read-only; multiple readers allowed */
|
||||
#define ACCESS_READ SHARED_LOCK
|
||||
#define EXCLUSIVE_LOCK -1 /* read/write; only one holder */
|
||||
#define ACCESS_WRITE EXCLUSIVE_LOCK
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Core Functions
|
||||
|
||||
| LVO | Function | Registers | Returns |
|
||||
|---|---|---|---|
|
||||
| −84 | `Lock(name, mode)` | D1=name, D2=mode | D0=lock BPTR (0=fail) |
|
||||
| −90 | `UnLock(lock)` | D1=lock | — |
|
||||
| −96 | `DupLock(lock)` | D1=lock | D0=new lock |
|
||||
| −102 | `Examine(lock, fib)` | D1=lock, D2=fib | D0=BOOL |
|
||||
| −108 | `ExNext(lock, fib)` | D1=lock, D2=fib | D0=BOOL |
|
||||
| −78 | `CurrentDir(lock)` | D1=lock | D0=old lock |
|
||||
| −654 | `ExAll(lock, buf, size, type, ctrl)` | D1–D5 | D0=BOOL |
|
||||
|
||||
---
|
||||
|
||||
## struct FileInfoBlock
|
||||
|
||||
```c
|
||||
/* dos/dos.h — NDK39 */
|
||||
struct FileInfoBlock {
|
||||
LONG fib_DiskKey; /* handler-private key */
|
||||
LONG fib_DirEntryType; /* >0 = directory, <0 = file */
|
||||
char fib_FileName[108]; /* null-terminated name */
|
||||
LONG fib_Protection; /* rwed bits */
|
||||
LONG fib_EntryType; /* same as DirEntryType */
|
||||
LONG fib_Size; /* file size in bytes */
|
||||
LONG fib_NumBlocks; /* blocks used */
|
||||
struct DateStamp fib_Date; /* modification date */
|
||||
char fib_Comment[80]; /* file comment string */
|
||||
UWORD fib_OwnerUID;
|
||||
UWORD fib_OwnerGID;
|
||||
char fib_Reserved[32];
|
||||
};
|
||||
```
|
||||
|
||||
> [!IMPORTANT]
|
||||
> `FileInfoBlock` must be longword-aligned. Use `AllocDosObject(DOS_FIB, NULL)` on OS 2.0+ or `AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC)`.
|
||||
|
||||
---
|
||||
|
||||
## Protection Bits
|
||||
|
||||
```c
|
||||
/* dos/dos.h */
|
||||
#define FIBF_SCRIPT (1<<6) /* s — script (executable script) */
|
||||
#define FIBF_PURE (1<<5) /* p — pure (re-entrant) */
|
||||
#define FIBF_ARCHIVE (1<<4) /* a — archived */
|
||||
#define FIBF_READ (1<<3) /* r — readable (0=allowed, 1=denied!) */
|
||||
#define FIBF_WRITE (1<<2) /* w — writable */
|
||||
#define FIBF_EXECUTE (1<<1) /* e — executable */
|
||||
#define FIBF_DELETE (1<<0) /* d — deletable */
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Amiga protection bits are **inverted** from Unix: bit SET means access is **denied**.
|
||||
|
||||
---
|
||||
|
||||
## Directory Scanning
|
||||
|
||||
```c
|
||||
BPTR lock = Lock("SYS:", SHARED_LOCK);
|
||||
struct FileInfoBlock *fib = AllocDosObject(DOS_FIB, NULL);
|
||||
|
||||
if (Examine(lock, fib)) { /* read dir's own info */
|
||||
while (ExNext(lock, fib)) { /* iterate entries */
|
||||
Printf("%-30s %8ld %s\n",
|
||||
fib->fib_FileName,
|
||||
fib->fib_Size,
|
||||
fib->fib_DirEntryType > 0 ? "(dir)" : "");
|
||||
}
|
||||
/* ExNext returns FALSE when done; IoErr() == ERROR_NO_MORE_ENTRIES */
|
||||
}
|
||||
|
||||
FreeDosObject(DOS_FIB, fib);
|
||||
UnLock(lock);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ExAll (OS 2.0+) — Bulk Scan
|
||||
|
||||
```c
|
||||
struct ExAllControl *eac = AllocDosObject(DOS_EXALLCONTROL, NULL);
|
||||
UBYTE buf[4096];
|
||||
BOOL more;
|
||||
|
||||
eac->eac_LastKey = 0;
|
||||
do {
|
||||
more = ExAll(lock, buf, sizeof(buf), ED_NAME, eac);
|
||||
struct ExAllData *ead = (struct ExAllData *)buf;
|
||||
while (ead) {
|
||||
Printf("%s\n", ead->ed_Name);
|
||||
ead = ead->ed_Next;
|
||||
}
|
||||
} while (more);
|
||||
FreeDosObject(DOS_EXALLCONTROL, eac);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `dos/dos.h`, `dos/dosextens.h`, `dos/exall.h`
|
||||
- ADCD 2.1: `Lock`, `UnLock`, `Examine`, `ExNext`, `ExAll`
|
||||
93
07_dos/packet_system.md
Normal file
93
07_dos/packet_system.md
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
[← Home](../README.md) · [AmigaDOS](README.md)
|
||||
|
||||
# Packet System — DosPacket, ACTION_* Codes
|
||||
|
||||
## Overview
|
||||
|
||||
AmigaDOS filesystem handlers communicate via **DosPackets** — messages sent to the handler's `MsgPort`. Every file operation (`Open`, `Read`, `Lock`, etc.) is internally translated into an `ACTION_*` packet. Understanding packets is essential for writing custom handlers or intercepting filesystem calls.
|
||||
|
||||
---
|
||||
|
||||
## struct DosPacket
|
||||
|
||||
```c
|
||||
/* dos/dosextens.h — NDK39 */
|
||||
struct DosPacket {
|
||||
struct Message *dp_Link; /* exec message (backlink) */
|
||||
struct MsgPort *dp_Port; /* reply port */
|
||||
LONG dp_Type; /* ACTION_* code */
|
||||
LONG dp_Res1; /* primary result */
|
||||
LONG dp_Res2; /* secondary result (error code) */
|
||||
LONG dp_Arg1; /* argument 1 — type depends on dp_Type */
|
||||
LONG dp_Arg2;
|
||||
LONG dp_Arg3;
|
||||
LONG dp_Arg4;
|
||||
LONG dp_Arg5;
|
||||
LONG dp_Arg6;
|
||||
LONG dp_Arg7;
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common ACTION_* Codes
|
||||
|
||||
| Code | Dec | Action | Args |
|
||||
|---|---|---|---|
|
||||
| `ACTION_FINDINPUT` | 1005 | Open for reading | Arg1=FileHandle, Arg2=Lock, Arg3=name(BSTR) |
|
||||
| `ACTION_FINDOUTPUT` | 1006 | Open for writing (create) | same |
|
||||
| `ACTION_FINDUPDATE` | 1004 | Open for r/w | same |
|
||||
| `ACTION_READ` | 82 | Read bytes | Arg1=FH_Arg1, Arg2=buf, Arg3=len |
|
||||
| `ACTION_WRITE` | 87 | Write bytes | Arg1=FH_Arg1, Arg2=buf, Arg3=len |
|
||||
| `ACTION_SEEK` | 1008 | Seek | Arg1=FH_Arg1, Arg2=pos, Arg3=mode |
|
||||
| `ACTION_END` | 1007 | Close file | Arg1=FH_Arg1 |
|
||||
| `ACTION_LOCATE_OBJECT` | 8 | Lock (obtain) | Arg1=dirLock, Arg2=name(BSTR), Arg3=mode |
|
||||
| `ACTION_FREE_LOCK` | 15 | UnLock | Arg1=lock |
|
||||
| `ACTION_EXAMINE_OBJECT` | 23 | Examine (stat) | Arg1=lock, Arg2=FIB(BPTR) |
|
||||
| `ACTION_EXAMINE_NEXT` | 24 | ExNext | Arg1=lock, Arg2=FIB(BPTR) |
|
||||
| `ACTION_PARENT` | 29 | ParentDir | Arg1=lock |
|
||||
| `ACTION_DELETE_OBJECT` | 16 | Delete | Arg1=lock, Arg2=name(BSTR) |
|
||||
| `ACTION_RENAME_OBJECT` | 17 | Rename | Arg1=fromLock, Arg2=fromName, Arg3=toLock, Arg4=toName |
|
||||
| `ACTION_CREATE_DIR` | 22 | CreateDir | Arg1=lock, Arg2=name(BSTR) |
|
||||
| `ACTION_SET_PROTECT` | 21 | SetProtection | Arg1=0, Arg2=lock, Arg3=name(BSTR), Arg4=bits |
|
||||
| `ACTION_DISK_INFO` | 25 | Info | Arg1=InfoData(BPTR) |
|
||||
| `ACTION_IS_FILESYSTEM` | 1027 | Query | (none) → Res1=DOSTRUE if filesystem |
|
||||
|
||||
---
|
||||
|
||||
## Sending a Packet Manually
|
||||
|
||||
```c
|
||||
struct MsgPort *handler = ((struct FileLock *)BADDR(lock))->fl_Task;
|
||||
struct StandardPacket sp;
|
||||
sp.sp_Msg.mn_Node.ln_Name = (char *)&sp.sp_Pkt;
|
||||
sp.sp_Pkt.dp_Link = &sp.sp_Msg;
|
||||
sp.sp_Pkt.dp_Port = CreateMsgPort();
|
||||
sp.sp_Pkt.dp_Type = ACTION_DISK_INFO;
|
||||
sp.sp_Pkt.dp_Arg1 = MKBADDR(infodata);
|
||||
PutMsg(handler, &sp.sp_Msg);
|
||||
WaitPort(sp.sp_Pkt.dp_Port);
|
||||
GetMsg(sp.sp_Pkt.dp_Port);
|
||||
/* sp.sp_Pkt.dp_Res1 = result */
|
||||
DeleteMsgPort(sp.sp_Pkt.dp_Port);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## BSTR — BCPL Strings
|
||||
|
||||
Handler packets use **BSTR** for filenames: a BPTR to a length-prefixed string:
|
||||
```
|
||||
[len_byte][char_0][char_1]...[char_n]
|
||||
```
|
||||
- `len_byte` = string length (max 255)
|
||||
- No null terminator
|
||||
- Convert: `UBYTE *bstr = (UBYTE *)BADDR(bstr_bptr); int len = bstr[0]; char *name = &bstr[1];`
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `dos/dosextens.h`, `dos/dos.h`
|
||||
- ADCD 2.1: `DoPkt`, packet system
|
||||
- *Amiga ROM Kernel Reference Manual: Devices* — filesystem handler chapter
|
||||
77
07_dos/pattern_matching.md
Normal file
77
07_dos/pattern_matching.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
[← Home](../README.md) · [AmigaDOS](README.md)
|
||||
|
||||
# Pattern Matching — ParsePattern, MatchPattern
|
||||
|
||||
## Overview
|
||||
|
||||
AmigaDOS provides built-in wildcard/pattern matching for file operations. Patterns are compiled into token streams via `ParsePattern` and matched via `MatchPattern`.
|
||||
|
||||
---
|
||||
|
||||
## Wildcard Syntax
|
||||
|
||||
| Pattern | Meaning | Example |
|
||||
|---|---|---|
|
||||
| `?` | Match exactly one character | `file?.txt` matches `file1.txt` |
|
||||
| `#` | Match zero or more of the following | `#?.info` matches anything ending in `.info` |
|
||||
| `#?` | Match any string (equivalent to `*`) | `#?` matches everything |
|
||||
| `(a\|b)` | Alternation — match a or b | `(read\|write)` |
|
||||
| `~` | Negation — match if NOT | `~(#?.info)` matches non-info files |
|
||||
| `[abc]` | Character class | `[abc]` matches a, b, or c |
|
||||
| `[a-z]` | Character range | `[0-9]` matches digits |
|
||||
| `'` | Quote next character literally | `'#` matches literal `#` |
|
||||
|
||||
---
|
||||
|
||||
## API
|
||||
|
||||
```c
|
||||
/* dos/dos.h — NDK39 */
|
||||
|
||||
/* Compile a pattern into tokenised form: */
|
||||
LONG ParsePattern(STRPTR pat, STRPTR buf, LONG buflen);
|
||||
/* Returns: 1 = pattern has wildcards, 0 = plain string, -1 = error */
|
||||
|
||||
/* Test a name against a compiled pattern: */
|
||||
BOOL MatchPattern(STRPTR pat_compiled, STRPTR name);
|
||||
|
||||
/* Case-insensitive variants: */
|
||||
LONG ParsePatternNoCase(STRPTR pat, STRPTR buf, LONG buflen);
|
||||
BOOL MatchPatternNoCase(STRPTR pat_compiled, STRPTR name);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Usage Example
|
||||
|
||||
```c
|
||||
char pat[256], buf[256];
|
||||
LONG is_wild;
|
||||
|
||||
is_wild = ParsePatternNoCase("#?.txt", pat, sizeof(pat));
|
||||
if (is_wild >= 0) {
|
||||
if (MatchPatternNoCase(pat, "readme.txt"))
|
||||
Printf("Match!\n");
|
||||
if (!MatchPatternNoCase(pat, "readme.doc"))
|
||||
Printf("No match\n");
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Patterns
|
||||
|
||||
| Pattern | Matches |
|
||||
|---|---|
|
||||
| `#?` | Everything (wildcard all) |
|
||||
| `#?.info` | All `.info` icon files |
|
||||
| `~(#?.info)` | Everything except `.info` files |
|
||||
| `(#?.c\|#?.h)` | All C source and header files |
|
||||
| `file[0-9]` | `file0` through `file9` |
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `dos/dos.h`
|
||||
- ADCD 2.1: `ParsePattern`, `MatchPattern`
|
||||
89
07_dos/process_management.md
Normal file
89
07_dos/process_management.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
[← Home](../README.md) · [AmigaDOS](README.md)
|
||||
|
||||
# Process Management — CreateNewProc, SystemTagList, Execute
|
||||
|
||||
## Overview
|
||||
|
||||
AmigaDOS provides several ways to launch child processes, ranging from the low-level `CreateNewProc` to the shell-level `Execute` and `SystemTagList`.
|
||||
|
||||
---
|
||||
|
||||
## CreateNewProcTags (OS 2.0+)
|
||||
|
||||
```c
|
||||
/* dos/dostags.h — NDK39 */
|
||||
struct Process *proc = CreateNewProcTags(
|
||||
NP_Entry, myFunction, /* function pointer */
|
||||
NP_Name, "Worker", /* task name */
|
||||
NP_StackSize, 8192, /* stack size in bytes */
|
||||
NP_Priority, 0, /* scheduling priority */
|
||||
NP_Input, Open("NIL:", MODE_OLDFILE),
|
||||
NP_Output, Open("NIL:", MODE_NEWFILE),
|
||||
NP_CloseInput, TRUE, /* close input on exit */
|
||||
NP_CloseOutput, TRUE,
|
||||
NP_CurrentDir, DupLock(currentDir),
|
||||
TAG_DONE);
|
||||
```
|
||||
|
||||
### Tag Constants
|
||||
|
||||
| Tag | Value | Meaning |
|
||||
|---|---|---|
|
||||
| `NP_Entry` | — | Function to run as the new process |
|
||||
| `NP_Seglist` | — | Alternative: run from a loaded segment list |
|
||||
| `NP_Name` | — | Process name (appears in task list) |
|
||||
| `NP_StackSize` | — | Stack size in bytes (default 4096) |
|
||||
| `NP_Priority` | — | Task priority (−128 to +127) |
|
||||
| `NP_Input` | — | BPTR stdin handle |
|
||||
| `NP_Output` | — | BPTR stdout handle |
|
||||
| `NP_Error` | — | BPTR stderr handle (OS 3.0+) |
|
||||
| `NP_CurrentDir` | — | Lock for current directory |
|
||||
| `NP_HomeDir` | — | Lock for PROGDIR: |
|
||||
| `NP_CopyVars` | — | Copy parent's local vars to child |
|
||||
|
||||
---
|
||||
|
||||
## SystemTagList — Run a Shell Command
|
||||
|
||||
```c
|
||||
/* Execute a command string as if typed in a shell: */
|
||||
LONG rc = SystemTagList("dir SYS: ALL", NULL);
|
||||
/* rc = return code from the command */
|
||||
|
||||
/* With custom I/O: */
|
||||
LONG rc = SystemTagList("list RAM:", (struct TagItem[]){
|
||||
{ SYS_Input, Open("NIL:", MODE_OLDFILE) },
|
||||
{ SYS_Output, Open("RAM:output.txt", MODE_NEWFILE) },
|
||||
{ TAG_DONE, 0 }
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Execute — Legacy Command Execution
|
||||
|
||||
```c
|
||||
/* dos.library LVO −132 */
|
||||
BOOL Execute(STRPTR command, BPTR input, BPTR output);
|
||||
```
|
||||
|
||||
- `command` — shell command string
|
||||
- `input` — BPTR to additional input (0 = none)
|
||||
- `output` — BPTR to output handle (0 = current)
|
||||
|
||||
---
|
||||
|
||||
## WaitForChild / Process Exit
|
||||
|
||||
Child processes are independent tasks. To synchronize:
|
||||
1. Use a shared `MsgPort` — child sends a death message
|
||||
2. Check `pr_Result2` after the child task exits
|
||||
3. Use `SYS_Asynch` tag with `SystemTagList` for fire-and-forget
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- NDK39: `dos/dostags.h`, `dos/dosextens.h`
|
||||
- ADCD 2.1: `CreateNewProc`, `SystemTagList`, `Execute`
|
||||
- `06_exec_os/tasks_processes.md` — Task/Process structures
|
||||
Loading…
Add table
Add a link
Reference in a new issue