Resident Segments

AmigaDOS keeps a list of resident segments: loaded seglists registered under a name, so that the Shell can run a command without loading it from disk and system components can find each other's code. Resident commands made with the Resident command, the Shell's built-in commands, the ROM handlers and the Shell itself all live on this list. It is a DOS structure (struct Segment, dos/dosextens.h) and has nothing to do with exec's ROMTag list in SysBase->ResModules (struct Resident), even though the purpose is similar.

The functions are FindSegment(), AddSegment() and RemSegment() (V36). There is no locking: the list must be used under Forbid().

How segments get on the list

Source Entry type (seg_UC)
Resident command on a file with the p (pure) bit 1 (unused user segment)
Shell: a command with p and h (hold) set is made resident the first time it runs (V39, removed in V40, back in V45) 1
Shell built-in commands (CD, Execute, …) added when the Shell starts CMD_INTERNAL
System-Startup: FileHandler (FFS), CON-Handler, RAM-Handler CMD_SYSTEM
System-Startup: the Shell as shell, BootShell and CLI system entries

The p bit claims the code is re-entrant and can run in several processes at once. AmigaDOS does not check this; a wrongly flagged command will crash when two shells run it.

The three shell entries

Name Use
shell Default user shell: Shell icon, NewShell, Run, System() with SYS_UserShell. May be replaced by a custom shell.
BootShell The shell that booted the system; used by System() by default and always by Execute(). Leave it alone.
CLI Same shell with BCPL binding; legacy, used only if requested with SYS_CustomShell.

To install a custom shell as the user shell:

Resident shell MyShell REPLACE SYSTEM

See Shell Internals for how such a shell must start.

struct Segment

struct Segment {
    BPTR  seg_Next;      /* next segment, ZERO at the end */
    LONG  seg_UC;        /* use count or type */
    BPTR  seg_Seg;       /* the seglist, as from LoadSeg() */
    UBYTE seg_Name[4];   /* BSTR name, really variable length */
};

Never allocate one yourself; AddSegment() builds it. seg_Name is a BSTR of any length, not 4 characters. seg_Next must not be modified.

seg_UC

Value Constant Meaning Found by the Shell
1 Disk-based command, not in use yes
> 1 In use by seg_UC − 1 users; cannot be removed yes
−1 CMD_SYSTEM System component (handler, file system); not executable no
−2 CMD_INTERNAL Shell built-in, code in ROM yes
≤ −999 CMD_DISABLED Disabled system or built-in entry (what Resident REMOVE does to them) no

An unused user segment has seg_UC = 1, not 0. The Shell increments the count when it starts a resident command and decrements it when the command ends. The Resident command prints seg_UC − 1, so it shows 0 for an idle command.

FindSegment

struct Segment *FindSegment(CONST_STRPTR name, CONST struct Segment *seg, LONG system);  /* V36 */
  • Case-insensitive search for name, from the start of the list (seg = NULL) or after seg (to find further entries of the same name).
  • system = FALSE finds only user entries (seg_UC > 0); system = TRUE finds only entries with negative seg_UC, including disabled ones: filter CMD_DISABLED yourself.
  • Returns a struct Segment * (a real pointer), not a seglist BPTR.
  • Does not increment seg_UC. Call it under Forbid() and increment seg_UC of a user segment before Permit(). System entries cannot go away (they can only be disabled), so they need no count.
  • Sets IoErr() to ERROR_OBJECT_NOT_FOUND when nothing matches; leaves it alone on success.
/* Use a resident command if one is there. */
struct Segment *seg;
BPTR code = 0;

Forbid();
seg = FindSegment("MyTool", NULL, FALSE);
if (seg) {
    seg->seg_UC++;                 /* keep it from being removed */
    code = seg->seg_Seg;
}
Permit();

if (code) {
    LONG rc = RunCommand(code, 8192, "\n", 1);
    Forbid();
    seg->seg_UC--;                 /* release our use */
    Permit();
}

AddSegment

LONG AddSegment(CONST_STRPTR name, BPTR seg, LONG system);   /* V36; BOOL result */

Adds seg under a copy of name; seg_UC is set to the third argument.

Third argument For
1 A pure command made resident
CMD_SYSTEM 2.0+ A non-command system segment. It can never be safely unloaded and stays for the life of the system.
CMD_INTERNAL 2.0+ Only for the ROM Shell's built-ins
CMD_DISABLED 2.0+ Only used by Resident when removing system or internal entries

Returns non-zero on success (IoErr() untouched); DOSFALSE with ERROR_NO_FREE_STORE on failure. The seglist now belongs to the list.

Note: the NDK 3.2 autodoc says the type is "normally 0"; neither the Shell nor the Resident command uses 0.

/* Make C:MyTool resident, like "Resident C:MyTool". */
BPTR seglist = LoadSeg("C:MyTool");
if (seglist && !AddSegment("MyTool", seglist, 1)) {
    PrintFault(IoErr(), "AddSegment");
    UnLoadSeg(seglist);
}

RemSegment

LONG RemSegment(struct Segment *seg);   /* V36; BOOL result */

Removes a user segment and unloads its seglist with UnLoadSeg(), releasing all its resources. It fails with DOSFALSE and ERROR_OBJECT_IN_USE for a system or internal segment, or for a user segment that is in use (seg_UC > 1).

Another process may remove the same segment at the same time, so find and remove it in one Forbid():

struct Segment *seg;
LONG ok = DOSFALSE;

Forbid();
if ((seg = FindSegment("MyTool", NULL, FALSE)) != NULL)
    ok = RemSegment(seg);
Permit();

Because of a defect in the current dos.library, RemSegment() sets IoErr() to ERROR_OBJECT_IN_USE even on success: test the return value, not IoErr().

Note: the NDK 3.2 autodoc says RemSegment() "will only succeed if the seg_UC (usecount) is 0".

Where the list is

The head of the list is in DosInfo.di_NetHand, which is really a BPTR to the first Segment. di_McName (alias di_ResList) is not used. Programs should not walk the list through either field; use FindSegment(). See AmigaDOS Library Internals.

Note: the NDK 3.2 dos/dosextens.h comments di_McName as "system resident module list" and di_NetHand as "Network handler processid; currently zero".

See Also


Sources: Thomas Richter, Amiga ROM Kernel Reference Manual: AmigaDOS (2024, v1.27), §15.6 (pp. 346–349), §15.7 (p. 349), §17.3 (p. 369); NDK 3.2 R4 Include_H/dos/dosextens.h; Autodocs/dos.doc (AddSegment, RemSegment, FindSegment); SFD/dos_lib.sfd Updated: 2026-11-13