exec.library Reference

Comprehensive function reference for exec.library, synthesised from the AmigaOS NDK 3.2 Release 4 (Autodocs/AG/exec).

This page documents 115 functions of exec.library. Each function entry follows the canonical autodoc format. struct Name, union Name, enum Name are clickable links to the type definition in the types reference.

Function index


AbortIO()

AbortIO - attempt to abort an in-progress I/O request

Synopsis

AbortIO(iORequest) A1

VOID AbortIO(IORequest*);

Function

Ask a device to abort a previously started IORequest. This is done by calling the device's AbortIO function, with your given IORequest.

AbortIO is a command the device that may or may not grant.  If
successful, the device will stop processing the IORequest, and
reply to it earlier than it would otherwise have done.

Inputs

iORequest - pointer to an I/O request block (must have been used at least once. May be active or finished).

Note

AbortIO() does NOT Remove() the IORequest from your ReplyPort, OR wait for it to complete. After an AbortIO() you must wait normally for the reply message before actually reusing the request.

If a request has already completed when AbortIO() is called, no
action is taken.

Example

AbortIO(timer_request); WaitIO(timer_request); / Message is free to be reused /

See also

WaitIO(), DoIO(), SendIO(), CheckIO()


AddDevice()

AddDevice -- add a device to the system

Synopsis

AddDevice(device) A1

void AddDevice(Device*);

Function

This function adds a new device to the system device list, making it available to other programs. The device must be ready to be opened at this time.

Inputs

device - pointer to a properly initialized device node

See also

RemDevice(), OpenDevice(), CloseDevice(), MakeLibrary()


AddHead()

AddHead -- insert node at the head of a list

Synopsis

AddHead(list, node) A0 A1

void AddHead(List*,Node*)

Function

Add a node to the head of a doubly linked list. Assembly programmers may prefer to use the ADDHEAD macro from "exec/lists.i".

Inputs

list - a pointer to the target list header node - the node to insert at head

See also

AddTail(), Enqueue(), Insert(), Remove(), RemHead(), RemTail()


AddIntServer()

AddIntServer -- add an interrupt server to a system server chain

Synopsis

AddIntServer(intNum, interrupt) D0-0:4 A1

void AddIntServer(ULONG,Interrupt*);

Function

This function adds a new interrupt server to a given server chain. The node is located on the chain in a priority dependent position. If this is the first server on a particular chain, interrupts will be enabled for that chain.

Each link in the chain will be called in priority order until the
chain ends or one of the servers returns with the 68000's Z condition
code clear (indicating non-zero).  Servers on the chain should return
with the Z flag clear if the interrupt was specifically for that
server, and no one else.  VERTB servers should always return Z set.
(Take care with High Level Language servers, the language may not
have a mechanism for reliably setting the Z flag on exit).

Servers are called with the following register conventions:

    D0 - scratch
    D1 - scratch

    A0 - scratch
    A1 - server is_Data pointer (scratch)

    A5 - jump vector register (scratch)
    A6 - scratch

    all other registers must be preserved

Inputs

intNum - the Paula interrupt bit number (0 through 14). Processor level seven interrupts (NMI) are encoded as intNum 15. The PORTS, COPER, VERTB, EXTER and NMI interrupts are set up as server chains. interrupt - pointer to an Interrupt structure. By convention, the LN_NAME of the interrupt structure must point a descriptive string so that other users may identify who currently has control of the interrupt.

Bugs

The graphics library's VBLANK server, and some user code, currently assume that address register A0 will contain a pointer to the custom chips. If you add a server at a priority of 10 or greater, you must compensate for this by providing the expected value ($DFF000).

See also

RemIntServer(), SetIntVector()


AddLibrary()

AddLibrary -- add a library to the system

Synopsis

AddLibrary(library) A1

void AddLibrary(Library*);

Function

This function adds a new library to the system, making it available to other programs. The library should be ready to be opened at this time. It will be added to the system library name list, and the checksum on the library entries will be calculated.

Inputs

library - pointer to a properly initialized library structure

See also

RemLibrary(), CloseLibrary(), OpenLibrary(), MakeLibrary()


AddMemHandler()

AddMemHandler - Add a low memory handler to exec (V39)

Synopsis

AddMemHandler(memHandler) A1

VOID AddMemHandler(Interrupt*);

Function

This function adds a low memory handler to the system. The handler is described in the Interrupt structure. Due to multitasking issues, the handler must be ready to run the moment this function call is made. (The handler may be called before the call returns)

Inputs

memHandler - A pointer to a completely filled in Interrupt structure The priority field determine the position of the handler with respect to other handlers in the system. The higher the priority, the earlier the handler is called. Positive priorities will have the handler called before any of the library expunge vectors are called. Negative priority handlers will be called after the library expunge routines are called. (Note: RAMLIB is a handler at priority 0)

Note

Adding a handler from within a handler will cause undefined actions. It is safe to add a handler to the list while within a handler but the newly added handler may or may not be called for the specific failure currently running.

Example

struct Interrupt myInt; * Assume it is allocated \

myInt->is_Node.ln_Pri=50;  \* Relatively early; before RAMLIB *\

\* Please fill in the name field! *\
myInt->is_Node.ln_Name="Example Handler";

myInt->is_Data=(APTR)mydata_pointer;
myInt->is_Code=myhandler_code;

AddMemHandler(myInt);
... \* and so on *\

_myhandler_code:
        ; This is the handler code
        ; We are passed a pointer to struct MemHandlerData
        ; in a0, the value of is_Data in a1 and
        ; ExecBase in a6.
        ; We must not break forbid!!!
;
; Start off assuming we did nothing
;
    moveq.l #MEM_DID_NOTHING,d0
    move.l  memh_RequestFlags(a0),d1
    btst.l  #MEMB_CHIP,d1   ; Did the failure happen in CHIP
    beq.s   handler_nop ; If not, we have nothing to do
    bsr DoMyMagic   ; Do the magic...
    ; DoMyMagic frees whatever we can and returns d0 set...
handler_nop:
    rts         ; Return with d0 set...

See also

RemMemHandler()


AddMemList()

AddMemList - add memory to the system free pool

Synopsis

AddMemList( size, attributes, pri, base, name ) D0 D1 D2 A0 A1

void AddMemList(ULONG, ULONG, LONG, APTR, STRPTR);

Function

Add a new region of memory to the system free pool. The first few bytes will be used to hold the MemHeader structure. The remainder will be made available to the rest of the world.

Inputs

size - the size (in bytes) of the memory area attributes - the attributes word that the memory pool will have pri - the priority for this memory. CHIP memory has a pri of -10, 16 bit expansion memory has a priority of 0. The higher the priority, the closer to the head of the memory list it will be placed. base - the base of the new memory area name - the name that will be used in the memory header, or NULL if no name is to be provided. This name is not copied, so it must remain valid for as long as the memory header is in the system.

Notes

DO NOT add memory to the system with the attribute of MEMF_KICK. EXEC will mark your memory as such if it is of the right type.

See also

AllocMem()


AddPort()

AddPort -- add a public message port to the system

Synopsis

AddPort(port) A1

void AddPort(MsgPort*);

Function

This function attaches a message port structure to the system's public message port list, where it can be found by the FindPort() function. The name and priority fields of the port structure must be initialized prior to calling this function. If the user does not require the priority field, it should be initialized to zero.

Only ports that will be searched for with FindPort() need to
be added to the system list.  In addition, adding ports is often
useful during debugging.  If the port will be searched for,
the priority field should be at least 1 (to avoid the large number
of inactive ports at priority zero).  If the port will be searched
for often, set the priority in the 50-100 range (so it will be
before other less used ports).

Once a port has been added to the naming list, you must be careful
to remove the port from the list (via RemPort) before deallocating
its memory.

Inputs

port - pointer to a message port

Note

A point of confusion is that clearing a MsgPort structure to all zeros is not enough to prepare it for use. As mentioned in the Exec chapter of the ROM Kernel Manual, the List for the MsgPort must be initialized. This is automatically handled by AddPort(), and amiga.lib/CreatePort. This initialization can be done manually with amiga.lib/NewList or the assembly NEWLIST macro.

Do not AddPort an active port.

See also

RemPort(), FindPort(), CreatePort(), NewList()


AddResource()

AddResource -- add a resource to the system

Synopsis

AddResource(resource) A1

void AddResource(APTR);

Function

This function adds a new resource to the system and makes it available to other users. The resource must be ready to be called at this time.

Resources currently have no system-imposed structure, however they
must start with a standard named node (LN_SIZE), and should with
a standard Library node (LIB_SIZE).

Inputs

resource - pointer an initialized resource node

See also

RemResource(), OpenResource(), MakeLibrary()


AddSemaphore()

AddSemaphore -- initialize then add a signal semaphore to the system

Synopsis

AddSemaphore(signalSemaphore) A1

void AddSemaphore(SignalSemaphore*);

Function

This function attaches a signal semaphore structure to the system's public signal semaphore list. The name and priority fields of the semaphore structure must be initialized prior to calling this function. If you do not want to let others rendezvous with this semaphore, use InitSemaphore() instead.

If a semaphore has been added to the naming list, you must be
careful to remove the semaphore from the list (via RemSemaphore)
before deallocating its memory.

Semaphores that are linked together in an allocation list (which
ObtainSemaphoreList() would use) may not be added to the system
naming list, because the facilities use the link field of the
signal semaphore in incompatible ways

Inputs

signalSemaphore -- an signal semaphore structure

Bugs

Does not work in Exec <V36. Instead use this code:

    #include <exec/execbase.h>
    #include <exec/nodes.h>
    extern struct ExecBase *SysBase;
    ...
    void LocalAddSemaphore(s)
    struct SignalSemaphore *s;
    {
    s->ss_Link.ln_Type=NT_SIGNALSEM;
    InitSemaphore(s);
    Forbid();
    Enqueue(&SysBase->SemaphoreList,s);
    Permit();
    }

See also

RemSemaphore(), FindSemaphore(), InitSemaphore()


AddTail()

AddTail -- append node to tail of a list

Synopsis

AddTail(list, node) A0 A1

void AddTail(List*,Node*);

Function

Add a node to the tail of a doubly linked list. Assembly programmers may prefer to use the ADDTAIL macro from "exec/lists.i".

Inputs

list - a pointer to the target list header node - a pointer to the node to insert at tail of the list

See also

AddHead(), Enqueue(), Insert(), Remove(), RemHead(), RemTail()


AddTask()

AddTask -- add a task to the system

Synopsis

AddTask(task, initialPC, finalPC) A1 A2 A3

APTR AddTask(Task*, APTR, APTR);

Function

Add a task to the system. A reschedule will be run; the task with the highest priority in the system will start to execute (this may or may not be the new task).

Certain fields of the task control block must be initialized and a
stack allocated prior to calling this function.  The absolute
smallest stack that is allowable is something in the range of 100
bytes, but in general the stack size is dependent on what
subsystems are called. In general 256 bytes is sufficient if only
Exec is called, and 4K will do if anything in the system is called.
DO NOT UNDERESTIMATE.  If you use a stack sniffing utility,
leave a healthy pad above the minimum value.  The system guarantees
that its stack operations will leave the stack longword aligned.

This function will temporarily use space from the new task's stack
for the task's initial set of registers.  This space is allocated
starting at the SPREG location specified in the task control block
(not from SPUPPER).  This means that a task's stack may contain
static data put there prior to its execution.  This is useful for
providing initialized global variables or some tasks may want to
use this space for passing the task its initial arguments.

A task's initial registers are set to zero (except the PC).

The TC_MEMENTRY field of the task structure may be extended by
the user to hold additional MemLists (as returned by AllocEntry()).
These will be automatically be deallocated at RemTask() time.
If the code you have used to start the task has already added
something to the MEMENTRY list, simply use AddHead to add your
new MemLists in.  If no initialization has been done, a NewList will
need to be performed.

Inputs

task - pointer to the task control block (TCB). All unset fields must be zero. initialPC - the initial entry point's address finalPC - the finalization code entry point's address. If zero, the system will use a general finalizer. This pointer is placed on the stack as if it were the outermost return address.

Results

For V36, AddTask returns either a NULL or the address of the new task. Old code need not check this.

See also

RemTask(), FindTask(), CreateTask(), CreateProc(), NewList()


Alert()

Alert -- alert the user of an error

Synopsis

Alert(alertNum) D7

void Alert(ULONG);

Function

Alerts the user of a serious system problem. This function will bring the system to a grinding halt, and do whatever is necessary to present the user with a message stating what happened. Interrupts are disabled, and an attempt to post the alert is made. If that fails, the system is reset. When the system comes up again, Exec notices the cause of the failure and tries again to post the alert.

If the Alert is a recoverable type, this call MAY return.

This call may be made at any time, including interrupts.
(Well, only in interrupts if it is non-recoverable)

New, for V39:
The alert now times out based on the value in LastAlert[3]
This value is transfered accross warm-reboots and thus will let
you set it once.  The value is the number of frames that need to
be displayed before the alert is auto-answered.  A value of
0 will thus make the alert never be displayed.  Note that
it is recommended that applications *NOT* change the value in
LastAlert[] since the main reason for this is to make
unattended operation of the Amiga (in production enviroments)
possible.

POST-MORTEM DIAGNOSIS There are several options for determining the cause of a crash. Descriptions of each alert number can be found in the "alerts.h" include file.

A remote terminal can be attached to the Amiga's first built-in
serial port.  Set the communication parameters to 9600 baud, 8 bits,
no parity.  Before resetting the machine, the Alert function will
blink the power LED 10 times.  While the power indicator is flashing,
pressing DELETE on the remote terminal will invoke the ROM debugger.

INPUT alertNum - a number indicating the particular alert. -1 is not a valid input.

Note

Much more needs to be said about this function and its implications.


AllocAbs()

AllocAbs -- allocate at a given location

Synopsis

memoryBlock = AllocAbs(byteSize, location) D0 D0 A1

void *AllocAbs(ULONG, APTR);

Function

This function attempts to allocate memory at a given absolute memory location. Often this is used by boot-surviving entities such as recoverable ram-disks. If the memory is already being used, or if there is not enough memory to satisfy the request, AllocAbs will return NULL.

This block may not be exactly the same as the requested block
because of rounding, but if the return value is non-zero, the block
is guaranteed to contain the requested range.

Inputs

byteSize - the size of the desired block in bytes This number is rounded up to the next larger block size for the actual allocation. location - the address where the memory MUST be.

Results

memoryBlock - a pointer to the newly allocated memory block, or NULL if failed.

Note

If the free list is corrupt, the system will panic with alert AN_MemCorrupt, $01000005.

The 8 bytes past the end of an AllocAbs will be changed by Exec
relinking the next block of memory.  Generally you can't trust
the first 8 bytes of anything you AllocAbs.

See also

AllocMem(), FreeMem()


Allocate()

Allocate - allocate a block of memory

Synopsis

memoryBlock=Allocate(memHeader, byteSize) D0 A0 D0

void *Allocate(MemHeader*, ULONG);

Function

This function is used to allocate blocks of memory from a given private free memory pool (as specified by a MemHeader and its memory chunk list). Allocate will return the first free block that is greater than or equal to the requested size.

All blocks, whether free or allocated, will be block aligned;
hence, all allocation sizes are rounded up to the next block even
value (e.g. the minimum allocation resolution is currently 8
bytes.  A request for 8 bytes will use up exactly 8 bytes.  A
request for 7 bytes will also use up exactly 8 bytes.).

This function can be used to manage an application's internal data
memory.  Note that no arbitration of the MemHeader and associated
free chunk list is done.  You must be the owner before calling
Allocate.

Inputs

memHeader - points to the local memory list header. byteSize - the size of the desired block in bytes.

Results

memoryBlock - a pointer to the just allocated free block. If there are no free regions large enough to satisfy the request, return zero.

Note

If the free list is corrupt, the system will panic with alert AN_MemCorrupt, $01000005.

Example

include

#include <exec/memory.h>
void *AllocMem();
#define BLOCKSIZE 4096L /* Or whatever you want */

void main()
{
struct MemHeader *mh;
struct MemChunk  *mc;
APTR   block1;
APTR   block2;

    /* Get the MemHeader needed to keep track of our new block */
    mh = (struct MemHeader *)
     AllocMem((long)sizeof(struct MemHeader), MEMF_CLEAR );
    if( !mh )
    exit(10);

    /* Get the actual block the above MemHeader will manage */
    mc = (struct MemChunk *)AllocMem( BLOCKSIZE, 0L );
    if( !mc )
    {
    FreeMem( mh, (long)sizeof(struct MemHeader) ); exit(10);
    }

    mh->mh_Node.ln_Type = NT_MEMORY;
    mh->mh_Node.ln_Name = "myname";
    mh->mh_First = mc;
    mh->mh_Lower = (APTR) mc;
    mh->mh_Upper = (APTR) ( BLOCKSIZE + (ULONG) mc );
    mh->mh_Free  = BLOCKSIZE;

    /* Set up first chunk in the freelist */
    mc->mc_Next  = NULL;
    mc->mc_Bytes = BLOCKSIZE;

    block1 = (APTR) Allocate( mh, 20L );
    block2 = (APTR) Allocate( mh, 314L );
    printf("mh=$%lx mc=$%lx\n",mh,mc);
    printf("Block1=$%lx, Block2=$%lx\n",block1,block2);

    FreeMem( mh, (long)sizeof(struct MemHeader) );
    FreeMem( mc, BLOCKSIZE );
}

See also

Deallocate()


AllocEntry()

AllocEntry -- allocate many regions of memory

Synopsis

memList = AllocEntry(memList) D0 A0

MemList*AllocEntry(MemList*);

Function

This function takes a memList structure and allocates enough memory to hold the required memory as well as a MemList structure to keep track of it.

These MemList structures may be linked together in a task control
block to keep track of the total memory usage of this task. (See
the description of TC_MEMENTRY under RemTask).

Inputs

memList -- A MemList structure filled in with MemEntry structures.

Results

memList -- A different MemList filled in with the actual memory allocated in the me_Addr field, and their sizes in me_Length. If enough memory cannot be obtained, then the requirements of the allocation that failed is returned and bit 31 is set.

    WARNING: The result is unusual!  Bit 31 indicates failure.

Examples

The user wants five regions of 2, 4, 8, 16, and 32 bytes in size with requirements of MEMF_CLEAR, MEMF_PUBLIC, MEMF_CHIP!MEMF_CLEAR, MEMF_CLEAR, and MEMF_PUBLIC!MEMF_CLEAR respectively. The following code fragment would do that:

    MemListDecl:
    DS.B    LN_SIZE         * reserve space for list node
    DC.W    5           * number of entries
    DC.L    MEMF_CLEAR          * entry #0
    DC.L    2
    DC.L    MEMF_PUBLIC         * entry #1
    DC.L    4
    DC.L    MEMF_CHIP!MEMF_CLEAR        * entry #2
    DC.L    8
    DC.L    MEMF_CLEAR          * entry #3
    DC.L    16
    DC.L    MEMF_PUBLIC!MEMF_CLEAR      * entry #4
    DC.L    32

    start:
    LEA.L   MemListDecl(PC),A0
    JSR _LVOAllocEntry(a6)
    BCLR.L  #31,D0
    BEQ.S   success

    ------- Type of memory that we failed on is in D0

Bugs

If any one of the allocations fails, this function fails to back out fully. This is fixed by the "SetPatch" program on V1.3 Workbench disks.


AllocMem()

AllocMem -- allocate memory given certain requirements

Synopsis

memoryBlock = AllocMem(byteSize, attributes) D0 D0 D1

void *AllocMem(ULONG, ULONG);

Function

This is the memory allocator to be used by system code and applications. It provides a means of specifying that the allocation should be made in a memory area accessible to the chips, or accessible to shared system code.

Memory is allocated based on requirements and options.  Any
"requirement" must be met by a memory allocation, any "option" will
be applied to the block regardless.  AllocMem will try all memory
spaces until one is found with the proper requirements and room for
the memory request.

Inputs

byteSize - the size of the desired block in bytes. (The operating system will automatically round this number to a multiple of the system memory chunk size)

attributes -
    requirements

    If no flags are set, the system will return the best
    available memory block.  For expanded systems, the fast
    memory pool is searched first.

    MEMF_CHIP:  If the requested memory will be used by
            the Amiga custom chips, this flag *must*
            be set.

            Only certain parts of memory are reachable
            by the special chip sets' DMA circuitry.
            Chip DMA includes screen memory, images that
            are blitted, audio data, copper lists, sprites
            and Pre-V36 trackdisk.device buffers.

    MEMF_FAST:  This is non-chip memory.  If no flag is set
            MEMF_FAST is taken as the default.

            DO NOT SPECIFY MEMF_FAST unless you know
            exactly what you are doing!  If MEMF_FAST is
            set, AllocMem() will fail on machines that
            only have chip memory!  This flag may not
            be set when MEMF_CHIP is set.

    MEMF_PUBLIC:    Memory that must not be mapped, swapped,
            or otherwise made non-addressable. ALL
            MEMORY THAT IS REFERENCED VIA INTERRUPTS
            AND/OR BY OTHER TASKS MUST BE EITHER PUBLIC
            OR LOCKED INTO MEMORY! This includes both
            code and data.

    MEMF_LOCAL: This is memory that will not go away
            after the CPU RESET instruction.  Normally,
            autoconfig memory boards become unavailable
            after RESET while motherboard memory
            may still be available.  This memory type
            is now automatically set in V36.  Pre-V36
            systems may not have this memory type
            and AllocMem() will then fail.

    MEMF_24BITDMA:  This is memory that is within the address
            range of 24-bit DMA devices.  (Zorro-II)
            This is required if you run a Zorro-II
            DMA device on a machine that has memory
            beyond the 24-bit addressing limit of
            Zorro-II.  This memory type
            is now automatically set in V36.  Pre-V36
            systems may not have this memory type
            and AllocMem() will then fail.

    MEMF_KICK:  This memory is memory that EXEC was able
            to access during/before the KickMem and
            KickTags are processed.  This means that
            if you wish to use these, you should allocate
            memory with this flag.  This flag is
            automaticly set by EXEC in V39.  Pre-V39
            systems may not have this memory type and
            AllocMem() will then fail.  Also, *DO NOT*
            ever add memory the system with this flag
            set.  EXEC will set the flag as needed
            if the memory matches the needs of EXEC.

    options

    MEMF_CLEAR: The memory will be initialized to all
            zeros.

    MEMF_REVERSE:   This allocates memory from the top of
            the memory pool.  It searches the pools
            in the same order, such that FAST memory
            will be found first.  However, the
            memory will be allocated from the highest
            address available in the pool.  This
            option is new as of V36.  Note that this
            option has a bug in pre-V39 systems.

    MEMF_NO_EXPUNGE This will prevent an expunge to happen on
            a failed memory allocation.  This option is
            new to V39 and will be ignored in V37.
            If a memory allocation with this flag
            set fails, the allocator will not cause
            any expunge operations.  (See AddMemHandler())

Results

memoryBlock - a pointer to the newly allocated memory block. If there are no free memory regions large enough to satisfy the request, zero will be returned. The pointer must be checked for zero before the memory block may be used! The memory block returned is long word aligned.

Note

If the free list is corrupt, the system will panic with alert AN_MemCorrupt, $01000005.

This function may not be called from interrupts.

A DOS process will have its pr_Result2 field set to
ERROR_NO_FREE_STORE if the memory allocation fails.

Examples

AllocMem(64,0L) - Allocate the best available memory AllocMem(25,MEMF_CLEAR) - Allocate the best available memory, and clear it before returning. AllocMem(128,MEMF_CHIP) - Allocate chip memory AllocMem(128,MEMF_CHIP|MEMF_CLEAR) - Allocate cleared chip memory AllocMem(821,MEMF_CHIP|MEMF_PUBLIC|MEMF_CLEAR) - Allocate cleared, public, chip memory.

See also

FreeMem()


AllocPooled()

AllocPooled -- Allocate memory with the pool manager (V39)

Synopsis

memory=AllocPooled(poolHeader,memSize) d0 a0 d0

APTR AllocPooled(APTR,ULONG);

Function

Allocate memSize bytes of memory, and return a pointer. NULL is returned if the allocation fails.

Doing a DeletePool() on the pool will free all of the puddles
and thus all of the allocations done with AllocPooled() in that
pool.  (No need to FreePooled() each allocation)

Inputs

poolHeader - a specific private pool header. memSize - the number of bytes to allocate

Results

A pointer to the memory, or NULL. The memory block returned is long word aligned.

Notes

The pool functions do not protect an individual pool from multiple accesses. The reason is that in most cases the pools will be used by a single task. If your pool is going to be used by more than one task you must Semaphore protect the pool from having more than one task trying to allocate within the same pool at the same time. Warning: Forbid() protection will not work in the future. Do NOT assume that we will be able to make it work in the future. AllocPooled() may well break a Forbid() and as such can only be protected by a semaphore.

To track sizes yourself, the following code can be used:
Assumes a6=ExecBase

;
; Function to do AllocVecPooled(Pool,memSize)
;
AllocVecPooled: addq.l  #4,d0       ; Get space for tracking
        move.l  d0,-(sp)    ; Save the size
        jsr _LVOAllocPooled(a6) ; Call pool...
        move.l  (sp)+,d1    ; Get size back...
        tst.l   d0      ; Check for error
        beq.s   avp_fail    ; If NULL, failed!
        move.l  d0,a0       ; Get pointer...
        move.l  d1,(a0)+    ; Store size
        move.l  a0,d0       ; Get result
avp_fail:   rts         ; return

;
; Function to do FreeVecPooled(pool,memory)
;
FreeVecPooled:  move.l  -(a1),d0    ; Get size / ajust pointer
        jmp _LVOFreePooled(a6)

Bugs

Allocations should not exceed 4294967288 (0xFFFFFFF8) bytes because this may trigger a side-effect leading to far less memory to be allocated.

See also

FreePooled(), CreatePool(), DeletePool()


AllocSignal()

AllocSignal -- allocate a signal bit

Synopsis

signalNum = AllocSignal(signalNum) D0 D0

BYTE AllocSignal(BYTE);

Function

Allocate a signal bit from the current tasks' pool. Either a particular bit, or the next free bit may be allocated. The signal associated with the bit will be properly initialized (cleared). At least 16 user signals are available per task. Signals should be deallocated before the task exits.

If the signal is already in use (or no free signals are available)
a -1 is returned.

Allocated signals are only valid for use with the task that
allocated them.

Inputs

signalNum - the desired signal number {of 0..31} or -1 for no preference.

Results

signalNum - the signal bit number allocated {0..31}. If no signals are available, this function returns -1.

See also

FreeSignal()


AllocTrap()

AllocTrap -- allocate a processor trap vector

Synopsis

trapNum = AllocTrap(trapNum) D0 D0

LONG AllocTrap(LONG);

Function

Allocate a trap number from the current task's pool. These trap numbers are those associated with the 68000 TRAP type instructions. Either a particular number, or the next free number may be allocated.

If the trap is already in use (or no free traps are available) a -1
is returned.

This function only affects the currently running task.

Traps are sent to the trap handler pointed at by tc_TrapCode.
Unless changed by user code, this points to a standard trap
handler.  The stack frame of the exception handler will be:

    0(SP) = Exception vector number.  This will be in the
        range of 32 to 47 (corresponding to the
        Trap #1...Trap #15 instructions).
    4(SP) = 68000/68010/68020/68030, etc. exception frame

tc_TrapData is not used.

Inputs

trapNum - the desired trap number {of 0..15} or -1 for no preference.

Results

trapNum - the trap number allocated {of 0..15}. If no traps are available, this function returns -1. Instructions of the form "Trap #trapNum" will be sent to the task's trap handler.

See also

FreeTrap()


AllocVec()

AllocVec -- allocate memory and keep track of the size (V36)

Synopsis

memoryBlock = AllocVec(byteSize, attributes) D0 D0 D1

void *AllocVec(ULONG, ULONG);

Function

This function works identically to AllocMem(), but tracks the size of the allocation.

See the AllocMem() documentation for details.

See also

FreeVec(), AllocMem()


AttemptSemaphore()

AttemptSemaphore -- try to obtain without blocking

Synopsis

success = AttemptSemaphore(signalSemaphore) D0 A0

LONG AttemptSemaphore(SignalSemaphore*);

Function

This call is similar to ObtainSemaphore(), except that it will not block if the semaphore could not be locked.

INPUT signalSemaphore -- an initialized signal semaphore structure

Results

success -- TRUE if the semaphore was locked, false if some other task already possessed the semaphore.

Note

This call does NOT preserve registers.

See also

ObtainSemaphore(), ObtainSemaphoreShared(), ReleaseSemaphore()


AttemptSemaphoreShared()

AttemptSemaphoreShared -- try to obtain without blocking (V37)

Synopsis

success = AttemptSemaphoreShared(signalSemaphore) D0 A0

LONG AttemptSemaphoreShared(SignalSemaphore*);

Function

This call is similar to ObtainSemaphoreShared(), except that it will not block if the semaphore could not be locked.

INPUT signalSemaphore -- an initialized signal semaphore structure

Results

success -- TRUE if the semaphore was granted, false if some other task already possessed the semaphore in exclusive mode.

Note

This call does NOT preserve registers.

Starting in V39 this call will grant the semaphore if the
caller is already the owner of an exclusive lock on the semaphore.
In pre-V39 systems this would not be the case.  If you need this
feature you can do the following workaround:

LONG myAttemptSempahoreShared(struct SignalSemaphore *ss)
{
LONG result;

    \* Try for a shared semaphore *\
    if (!(result=AttemptSemaphoreShared(ss)))
    {
        \* Now try for the exclusive one... *\
        result=AttempSemaphore(ss);
    }
    return(result);
}

See also

ObtainSemaphore(), ObtainSemaphoreShared(), ReleaseSemaphore()


AvailMem()

AvailMem -- memory available given certain requirements

Synopsis

size = AvailMem(attributes) D0 D1

ULONG AvailMem(ULONG);

Function

This function returns the amount of free memory given certain attributes.

To find out what the largest block of a particular type is, add
MEMF_LARGEST into the requirements argument.  Returning the largest
block is a slow operation.

Inputs

requirements - a requirements mask as specified in AllocMem. Any of the AllocMem bits are valid, as is MEMF_LARGEST which returns the size of the largest block matching the requirements.

Results

size - total free space remaining (or the largest free block).

Note

For V36 Exec, AvailMem(MEMF_LARGEST) does a consistency check on the memory list. Alert AN_MemoryInsane will be pulled if any mismatch is noted.

Example

AvailMem(MEMF_CHIP|MEMF_LARGEST); / return size of largest available chip memory chunk /


CacheClearE()

CacheClearE - Cache clearing with extended control (V37)

Synopsis

CacheClearE(address,length,caches) a0 d0 d1

void CacheClearE(APTR,ULONG,ULONG);

Function

Flush out the contents of the CPU instruction and/or data caches. If dirty data cache lines are present, push them to memory first.

Motorola CPUs have separate instruction and data caches.  A data
write does not update the instruction cache.  If an instruction is
written to memory or modified, the old instruction may still exist
in the cache.  Before attempting to execute the code, a flush of
the instruction cache is required.

For most systems, the data cache is not updated by Direct Memory
Access (DMA), or if some external factor changes shared memory.

Caches must be cleared after *any* operation that could cause
invalid or stale data.  The most common cases are DMA and modifying
instructions using the processor.

Some examples:
        Self modifying code
        Building Jump tables
        Run-time code patches
        Relocating code for use at different addresses.
        Loading code from disk

Inputs

address - Address to start the operation. This may be rounded due to hardware granularity. length - Length of area to be cleared, or $FFFFFFFF to indicate all addresses should be cleared. caches - Bit flags to indicate what caches to affect. The current supported flags are: CACRF_ClearI ;Clear instruction cache CACRF_ClearD ;Clear data cache All other bits are reserved for future definition.

Notes

On systems with a copyback mode cache, any dirty data is pushed to memory as a part of this operation.

Regardless of the length given, the function will determine the most
efficient way to implement the operation.  For some cache systems,
including the 68030, the overhead partially clearing a cache is often
too great.  The entire cache may be cleared.

For all current Amiga models, Chip memory is set with Instruction
caching enabled, data caching disabled.  This prevents coherency
conflicts with the blitter or other custom chip DMA.  Custom chip
registers are marked as non-cacheable by the hardware.

The system takes care of appropriately flushing the caches for normal
operations.  The instruction cache is cleared by all calls that
modify instructions, including LoadSeg(), MakeLibrary() and
SetFunction().

See also

CacheControl(), CacheClearU()


CacheClearU()

CacheClearU - User callable simple cache clearing (V37)

Synopsis

CacheClearU()

void CacheClearU(void);

Function

Flush out the contents of any CPU instruction and data caches. If dirty data cache lines are present, push them to memory first.

Caches must be cleared after *any* operation that could cause
invalid or stale data.  The most common cases are DMA and modifying
instructions using the processor.  See the CacheClearE() autodoc
for a more complete description.

Some examples of when the cache needs clearing:
        Self modifying code
        Building Jump tables
        Run-time code patches
        Relocating code for use at different addresses.
        Loading code from disk

See also

CacheControl(), CacheClearE()


CacheControl()

CacheControl - Instruction & data cache control

Synopsis

oldBits = CacheControl(cacheBits,cacheMask) D0 D0 D1

ULONG CacheControl(ULONG,ULONG);

Function

This function provides global control of any instruction or data caches that may be connected to the system. All settings are global -- per task control is not provided.

The action taken by this function will depend on the type of
CPU installed.  This function may be patched to support external
caches, or different cache architectures.  In all cases the function
will attempt to best emulate the provided settings.  Use of this
function may save state specific to the caches involved.

The list of supported settings is provided in the exec/execbase.i
include file.  The bits currently defined map directly to the Motorola
68030 CPU CACR register.  Alternate cache solutions may patch into
the Exec cache functions.  Where possible, bits will be interpreted to
have the same meaning on the installed cache.

Inputs

cacheBits - new values for the bits specified in cacheMask.

cacheMask - a mask with ones for all bits to be changed.

Results

oldBits - the complete prior values for all settings.

Note

As a side effect, this function clears all caches.

See also

CacheClearU(), CacheClearE()


CachePostDMA()

CachePostDMA - Take actions after to hardware DMA (V37)

Synopsis

CachePostDMA(vaddress,&length,flags) a0 a1 d0

CachePostDMA(APTR,LONG *,ULONG);

Function

Take all appropriate steps after Direct Memory Access (DMA). This function is primarily intended for writers of DMA device drivers. The action will depend on the CPU type installed, caching modes, and the state of any Memory Management Unit (MMU) activity.

As implemented
    68000 - Do nothing
    68010 - Do nothing
    68020 - Do nothing
    68030 - Flush the data cache
    68040 - Flush matching areas of the data cache
    ????? - External cache boards, Virtual Memory Systems, or
        future hardware may patch this vector to best emulate
        the intended behavior.
        With a Bus-Snooping CPU, this function my end up
        doing nothing.

Inputs

address - Same as initially passed to CachePreDMA length - Same as initially passed to CachePreDMA flags - Values: DMA_NoModify - If the area was not modified (and thus there is no reason to flush the cache) set this bit.

        DMA_ReadFromRAM - Indicates that this DMA is a
        read from RAM to the DMA device (ie - a write
        to the hard drive)  This flag is not required
        but if used must match in both the PreDMA and
        PostDMA calls.  This flag *should* be used to
        help the system provide the best performance.
        This flag is safe in all versions of CachePostDMA()

See also

CachePreDMA(), CacheClearU(), CacheClearE()


CachePreDMA()

CachePreDMA - Take actions prior to hardware DMA (V37)

Synopsis

paddress = CachePreDMA(vaddress,&length,flags) d0 a0 a1 d0

APTR CachePreDMA(APTR,LONG *,ULONG);

Function

Take all appropriate steps before Direct Memory Access (DMA). This function is primarily intended for writers of DMA device drivers. The action will depend on the CPU type installed, caching modes, and the state of any Memory Management Unit (MMU) activity.

This function supports advanced cache architectures that have
"copyback" modes.  With copyback, write data may be cached, but not
actually flushed out to memory.  If the CPU has unflushed data at the
time of DMA, data may be lost.

As implemented
    68000 - Do nothing
    68010 - Do nothing
    68020 - Do nothing
    68030 - Do nothing
    68040 - Write any matching dirty cache lines back to memory.
        As a side effect of the 68040's design, matching data
        cache lines are also invalidated -- future CPUs may
        be different.
    ????? - External cache boards, Virtual Memory Systems, or
        future hardware may patch this vector to best emulate
        the intended behavior.
        With a Bus-Snooping CPU, this function my end up
        doing nothing.

Inputs

address - Base address to start the action. length - Pointer to a longword with a length. flags - Values: DMA_Continue - Indicates this call is to complete a prior request that was broken up.

        DMA_ReadFromRAM - Indicates that this DMA is a
        read from RAM to the DMA device (ie - a write
        to the hard drive)  This flag is not required
        but if used must match in both the PreDMA and
        PostDMA calls.  This flag *should* be used to
        help the system provide the best performance.
        This flag is safe in all versions of CachePreDMA()

Results

paddress- Physical address that corresponds to the input virtual address. &length - This length value will be updated to reflect the contiguous length of physical memory present at paddress. This may be smaller than the requested length. To get the mapping for the next chunk of memory, call the function again with a new address, length, and the DMA_Continue flag.

Note

Due to processor granularity, areas outside of the address range may be affected by the cache flushing actions. Care has been taken to ensure that no harm is done outside the range, and that activities on overlapping cache lines won't harm data.

See also

CachePostDMA(), CacheClearU(), CacheClearE()


Cause()

Cause -- cause a software interrupt

Synopsis

Cause(interrupt) A1

void Cause(Interrupt*);

Function

This function causes a software interrupt to occur. If it is called from user mode (and processor level 0), the software interrupt will preempt the current task. This call is often used by high-level hardware interrupts to defer medium-length processing down to a lower interrupt level. Note that a software interrupt is still a real interrupt, and must obey the same restrictions on what system function it may call.

Currently only 5 software interrupt priorities are implemented:
-32, -16, 0, +16, and +32.  Priorities in between are truncated,
values outside the -32/+32 range are not allowed.

Inputs

interrupt - pointer to a properly initialized interrupt node

Note

When setting up the Interrupt structure, set the node type to NT_INTERRUPT, or NT_UNKOWN.

IMPLEMENTATION 1> Checks if the node type is NT_SOFTINT. If so does nothing since the softint is already pending. No nest count is maintained. 2> Sets the node type to NT_SOFTINT. 3> Links into one of the 5 priority queues. 4> Pokes the hardware interrupt bit used for softints.

The node type returns to NT_INTERRUPT after removal from the list.

Bugs

Unlike other Interrupts, SoftInts must preserve the value of A6.


CheckIO()

CheckIO -- get the status of an IORequest

Synopsis

result = CheckIO(iORequest) D0 A1

IORequest*CheckIO(IORequest*);

Function

This function determines the current state of an I/O request and returns NULL if the I/O has not yet completed. This function effectively hides the internals of the I/O completion mechanism.

CheckIO() will NOT remove the returned IORequest from the reply port.
This is best performed with WaitIO(). If the request has already
completed, WaitIO() will return quickly. Use of the Remove()
function is dangerous, since other tasks may still be adding things
to your message port; a Disable() would be required.

This function should NOT be used to busy loop (looping until IO is
complete).  WaitIO() is provided for that purpose.

Inputs

iORequest - pointer to an I/O request block

Results

result - NULL if I/O is still in progress. Otherwise D0 points to the IORequest block.

Note

CheckIO can hang if called on an IORequest that has never been used. This occurs if io_Message.mn_Node.ln_Type of the IORequest is set to "NT_MESSAGE". Instead simply set LN_TYPE to 0.

Bugs

Previously, CheckIO() used to be documented to return a BOOL result. This was incorrect.

See also

DoIO(), SendIO(), WaitIO(), AbortIO()


CloseDevice()

CloseDevice -- conclude access to a device

Synopsis

CloseDevice(iORequest) A1

void CloseDevice(IORequest*);

Function

This function informs the device that access to a device/unit previously opened has been concluded. The device may perform certain house-cleaning operations.

The user must ensure that all outstanding IORequests have been
returned before closing the device.  The AbortIO function can kill
any stragglers.

After a close, the I/O request structure is free to be reused.
Starting with V36 exec it is safe to CloseDevice() with an
IORequest that is either cleared to zeros, or failed to
open.

Inputs

iORequest - pointer to an I/O request structure

See also

OpenDevice()


CloseLibrary()

CloseLibrary -- conclude access to a library

Synopsis

CloseLibrary(library) A1

void CloseLibrary(Library*);

Function

This function informs the system that access to the given library has been concluded. The user must not reference the library or any function in the library after this close.

Starting with V36, it is safe to pass a NULL instead of
a library pointer.

Inputs

library - pointer to a library node

Note

Library writers must pass a SegList pointer or NULL back from their open point. This value is used by the system, and not visible as a return code from CloseLibrary.

See also

OpenLibrary()


ColdReboot()

ColdReboot - reboot the Amiga (V36)

Synopsis

ColdReboot()

void ColdReboot(void);

Function

Reboot the machine. All external memory and periperals will be RESET, and the machine will start its power up diagnostics.

This function never returns.

INPUT
A chaotic pile of disoriented bits.

Results

An altogether totally integrated living system.


CopyMem()

CopyMem - general purpose memory copy function

Synopsis

CopyMem( source, dest, size ) A0 A1 D0

void CopyMem(APTR,APTR,ULONG);

Function

CopyMem is a general purpose, fast memory copy function. It can deal with arbitrary lengths, with its pointers on arbitrary alignments. It attempts to optimize larger copies with more efficient copies, it uses byte copies for small moves, parts of larger copies, or the entire copy if the source and destination are misaligned with respect to each other.

The internal implementation of this function will change from
system to system, and may be implemented via hardware DMA.

CAUTION Arbitrary overlapping copies are not supported.

Inputs

source - a pointer to the source data region dest - a pointer to the destination data region size - the size (in bytes) of the memory area. Zero copies zero bytes

See also

CopyMemQuick()


CopyMemQuick()

CopyMemQuick - optimized memory copy function

Synopsis

CopyMemQuick( source, dest, size ) A0 A1 D0

void CopyMemQuick(ULONG *,ULONG *,ULONG);

Function

CopyMemQuick is a highly optimized memory copy function, with restrictions on the size and alignment of its arguments. Both the source and destination pointers must be longword aligned. In addition, the size must be an integral number of longwords (e.g. the size must be evenly divisible by four).

The internal implementation of this function will change from system
to system, and may be implemented via hardware DMA.

CAUTION Arbitrary overlapping copies are not supported.

Inputs

source - a pointer to the source data region, long aligned dest - a pointer to the destination data region, long aligned size - the size (in bytes) of the memory area. Zero copies zero bytes.

See also

CopyMem()


CreateIORequest()

CreateIORequest() -- create an IORequest structure (V36)

Synopsis

ioReq = CreateIORequest( ioReplyPort, size ); A0 D0

IORequest*CreateIORequest(MsgPort*, ULONG);

Function

Allocates memory for and initializes a new IO request block of a user-specified number of bytes. The number of bytes must be at least as large as a "struct Message".

Inputs

ioReplyPort - Pointer to a port for replies (an initialized message port, as created by CreateMsgPort() ). If NULL, this function fails. size - the size of the IO request to be created.

Results

ioReq - A pointer to the new IORequest block, or NULL.

See also

DeleteIORequest(), CreateMsgPort(), CreateExtIO()


CreateMsgPort()

CreateMsgPort - Allocate and initialize a new message port (V36)

Synopsis

CreateMsgPort()

MsgPort* CreateMsgPort(void);

Function

Allocates and initializes a new message port. The message list of the new port will be prepared for use (via NewList). A signal bit will be allocated, and the port will be set to signal your task when a message arrives (PA_SIGNAL).

You *must* use DeleteMsgPort() to delete ports created with
CreateMsgPort()!

Results

MsgPort - A new MsgPort structure ready for use, or NULL if out of memory or signals. If you wish to add this port to the public port list, fill in the mp_Node.ln_Name and mp_Node.ln_Pri fields, then call AddPort(). Don't forget RemPort()!

See also

DeleteMsgPort(), AddPort(), CreatePort()


CreatePool()

CreatePool -- Generate a private memory pool header (V39)

Synopsis

newPool=CreatePool(memFlags,puddleSize,threshSize) a0 d0 d1 d2

APTR CreatePool(ULONG,ULONG,ULONG);

Function

Allocate and prepare a new memory pool header. Each pool is a separate tracking system for memory of a specific type. Any number of pools may exist in the system.

Pools automatically expand and shrink based on demand.  Fixed sized
"puddles" are allocated by the pool manager when more total memory
is needed.  Many small allocations can fit in a single puddle.
Allocations larger than the threshSize are allocation in their own
puddles.

At any time individual allocations may be freed.  Or, the entire
pool may be removed in a single step.

Inputs

memFlags - a memory flags specifier, as taken by AllocMem. puddleSize - the size of Puddles... threshSize - the largest allocation that goes into normal puddles This MUST be less than or equal to puddleSize (CreatePool() will fail if it is not)

Results

The address of a new pool header, or NULL for error.

Notes

The memFlags you specify are used by AllocPooled() only, not by CreatePool(). The CreatePool() function will allocate memory for its management data structures using MEMF_ANY. For example, if you call CreatePool(MEMF_FAST, ...) and expect it to return NULL if no fast memory is available you may find that it succeeds. Subsequent AllocPooled() calls for this pool will, however, fail on a system without fast memory.

The memory pools solve three problems which allocating memory through
AllocMem(), Allocate() and AllocVec() either do not address or which
are part of how they have to work:

* Memory pools keep track of the allocations made, so that you may release
  all of them by calling DeletePool() instead of releasing each single
  allocation separately.

* Allocating and releasing memory from a pool does not need to involve
  the Forbid()/Permit() locking which is mandatory for AllocMem(),
  FreeMem(), etc. Because of how much effort exec.library spends on
  finding a fitting memory chunk to allocate from and in turn freeing
  and coalescing freed memory chunks into larger chunks, you would not
  want this to happen while multitasking is temporarily disabled.

* Small allocations made from pools no longer affect the overall
  fragmentation of the available Amiga memory.

These features benefit not just your application, it also helps every
other Amiga software running at the same time.

These benefits come with costs which you should be aware of when making
the choice to adopt memory pools for your software.

* Tracking memory allocations can add a noticeable overhead to those
  allocations which are smaller than or equal to the threshold size given
  at CreatePool() time. This overhead exists because each such small
  allocation has to be found first when you call FreePooled().
  The more puddles are in use, the more time it will take to find the
  puddle which it was allocated from.

* Only one Task/Process at a time may allocate memory from a pool. This
  is why AllocMem(), FreeMem(), etc. imply Forbid()/Permit() locking.
  If your software is sharing a memory pool among several Tasks/Processes
  then you will have to use an arbitration mechanism such as a
  SignalSemaphore to allow only a single client at a time to access the
  pool.

  This is of particular importance because pools optimize the
  layout of the puddles in response to how frequently allocations and
  deallocations are made from a pool, which is called "bubbling". The
  more often a puddle is used, the less time will be spent on finding
  it when releasing an allocation from it.

  If no arbitration mechanism is available, you run the risk of corrupting
  both the pool contents and the memory managed through it.

  Sharing the same memory pool among several Tasks/Processes can cause the
  number of puddles to grow over time which are almost empty but never get
  memory allocated from them. This is a side-effect of how the layout of the
  puddles is optimized over time. To avoid this problem you should consider
  breaking down a single shared memory pool into separate pools if your
  software architecture permits it.

* While using memory pools will curb overall memory fragmentation, you may
  find that fragmentation issues affect the puddles more strongly. If
  allocations vary greatly in size and do not exceed the threshold value
  given at CreatePool() time you may end up with puddles which are only
  partly filled, wasting memory. If possible, try to match the puddle size
  and the threshold size to the allocation sizes you are most likely to use.

Bugs

Avoid using a puddle size of 0 bytes. It will have the effect of each AllocPooled() call resulting in a separate memory allocation. This defeats the purpose of the memory pools, which is in curbing memory fragmentation and the need to block multitasking when memory has to be allocated from the global pool.

Puddle sizes should not exceed 4294967272 (0xFFFFFFE8) bytes because
this may trigger a side-effect leading to far less memory to be
allocated.

Creating a pool with MEMF_CLEAR set in the memFlags parameter has
a side-effect in slowing down all memory allocations made. The
creation of a new puddle will result in it getting set to zero,
and any allocation made from that puddle will set it to zero
all over again. If you can, avoid using MEMF_CLEAR and set the
memory allocated by AllocPooled() to zero all by yourself.

See also

DeletePool(), AllocPooled(), FreePooled()


Deallocate()

Deallocate -- deallocate a block of memory

Synopsis

Deallocate(memHeader, memoryBlock, byteSize) A0 A1 D0

void Deallocate(MemHeader*,APTR,ULONG);

Function

This function deallocates memory by returning it to the appropriate private free memory pool. This function can be used to free an entire block allocated with the above function, or it can be used to free a sub-block of a previously allocated block. Sub-blocks must be an even multiple of the memory chunk size (currently 8 bytes).

This function can even be used to add a new free region to an
existing MemHeader, however the extent pointers in the MemHeader
will no longer be valid.

If memoryBlock is not on a block boundary (MEM_BLOCKSIZE) then it
will be rounded down in a manner compatible with Allocate().  Note
that this will work correctly with all the memory allocation
functions, but may cause surprises if one is freeing only part of a
region.  The size of the block will be rounded up, so the freed
block will fill to an even memory block boundary.

Inputs

memHeader - points to the memory header this block is part of. memoryBlock - address of memory block to free. byteSize - the size of the block in bytes. If NULL, nothing happens.

See also

Allocate()


Debug()

Debug -- run the system debugger

Synopsis

Debug(flags) D0

void Debug(ULONG);

Function

This function calls the system debugger. By default this debugger is "SAD" in V39 and V40, and "ROM-WACK" otherwise, including V45 and above. Other debuggers are encouraged to take over this entry point (via SetFunction()) so that when an application calls Debug(), the alternative debugger will get control. Currently a zero is passed to allow future expansion.

Note

The Debug() call may be made when the system is in a questionable state; if you have a SetFunction() patch, make few assumptions, be prepared for Supervisor mode, and be aware of differences in the Motorola stack frames on the 68000,'10,'20,'30,'40 (etc.)

Bugs

In ROMWack, calling this function in SUPERVISOR state would have caused the a5 register to be trashed and the user stack pointer to be trashed. exec/Alert() also trashed d7, and the dos.library exception hook trashed all other registers. Also, ROMWack could not recover in case the VBR of the 68010 or beyond moved.

See also

SetFunction()


DeleteIORequest()

DeleteIORequest() - Free a request made by CreateIORequest() (V36)

Synopsis

DeleteIORequest( ioReq ); a0

void DeleteIORequest(APTR);

Function

Frees up an IO request as allocated by CreateIORequest().

Inputs

ioReq - A pointer to the IORequest block to be freed, or NULL. This function uses the io_Message.mn_Length field to determine how much memory to free.

See also

CreateIORequest(), DeleteExtIO()


DeleteMsgPort()

DeleteMsgPort - Free a message port created by CreateMsgPort (V36)

Synopsis

DeleteMsgPort(msgPort) a0

void DeleteMsgPort(MsgPort*);

Function

Frees a message port created by CreateMsgPort(). All messages that may have been attached to this port must have already been replied to.

Inputs

msgPort - A message port. NULL for no action.

See also

CreateMsgPort(), DeletePort()


DeletePool()

DeletePool -- Drain an entire memory pool (V39)

Synopsis

DeletePool(poolHeader) a0

void DeletePool(APTR);

Function

Frees all memory in all pudles of the specified pool header, then deletes the pool header. Individual free calls are not needed.

Inputs

poolHeader - as returned by CreatePool().

See also

CreatePool(), AllocPooled(), FreePooled()


Disable()

Disable -- disable interrupt processing.

Synopsis

Disable();

void Disable(void);

Function

Prevents interrupts from being handled by the system, until a matching Enable() is executed. Disable() implies Forbid().

DO NOT USE THIS CALL WITHOUT GOOD JUSTIFICATION.  THIS CALL IS
VERY DANGEROUS!

Results

All interrupt processing is deferred until the task executing makes a call to Enable() or is placed in a wait state. Normal task rescheduling does not occur while interrupts are disabled. In order to restore normal interrupt processing, the programmer must execute exactly one call to Enable() for every call to Disable().

IMPORTANT REMINDER:

It is important to remember that there is a danger in using
disabled sections.  Disabling interrupts for more than ~250
microseconds will prevent vital system functions (especially serial
I/0) from operating in a normal fashion.

Think twice before using Disable(), then think once more.
After all that, think again.  With enough thought, the need
for a Disable() can often be eliminated.  For the user of many
device drivers, a write to disable *only* the particular interrupt
of interest can replace a Disable().  For example:
        MOVE.W  #INTF_PORTS,_intena
Do not use a macro for Disable(), insist on the real thing.

This call may be made from interrupts, it will have the effect
of locking out all higher-level interrupts (lower-level interrupts
are automatically disabled by the CPU).

    Note: In the event of a task entering a Wait() after disabling
          interrupts, the system "breaks" the disabled state and runs
          normally until the task which called Disable() is rescheduled.

Note

This call is guaranteed to preserve all registers.

See also

Forbid(), Permit(), Enable()


DoIO()

DoIO -- perform an I/O command and wait for completion

Synopsis

error = DoIO(iORequest) D0 A1

BYTE DoIO(IORequest*);

Function

This function requests a device driver to perform the I/O command specified in the I/O request. This function will always wait until the I/O request is fully complete.

DoIO() handles all the details, including Quick I/O, waiting for
the request, and removing the reply message, etc..

IMPLEMENTATION This function first tries to complete the IO via the "Quick I/O" mechanism. The io_Flags field is always set to IOF_QUICK (0x01) before the internal device call.

The io_Message.mn_Node.ln_Type field is used internally to flag
completion.  Active requests have type NT_MESSAGE.  Requests
that have been replied have type NT_REPLYMSG or (rarely) NT_FREEMSG.
It is illegal to start IO using a still active IORequest, or a
request with type NT_REPLYMSG.

Inputs

iORequest - pointer to an IORequest initialized by OpenDevice()

Results

error - a sign-extended copy of the io_Error field of the IORequest. Most device commands require that the error return be checked.

See also

SendIO(), CheckIO(), WaitIO(), AbortIO(), ReplyMsg(), BeginIO()


Enable()

Enable -- permit system interrupts to resume.

Synopsis

Enable();

void Enable(void);

Function

Allow system interrupts to again occur normally, after a matching Disable() has been executed.

Results

Interrupt processing is restored to normal operation. The programmer must execute exactly one call to Enable() for every call to Disable().

Note

This call is guaranteed to preserve all registers.

See also

Forbid(), Permit(), Disable()


Enqueue()

Enqueue -- insert or append node to a system queue

Synopsis

Enqueue(list, node) A0 A1

void Enqueue(List*,Node*);

Function

Insert or append a node into a system queue. The insertion is performed based on the node priority -- it will keep the list properly sorted. New nodes will be inserted in front of the first node with a lower priority. Hence a FIFO queue for nodes of equal priority

Inputs

list - a pointer to the system queue header node - the node to enqueue. This must be a full featured node with type, priority and name fields.

See also

AddHead(), AddTail(), Insert(), Remove(), RemHead(), RemTail()


FindName()

FindName -- find a system list node with a given name

Synopsis

node = FindName(start, name) D0,Z A0 A1

Node*FindName(List*, STRPTR);

Function

Traverse a system list until a node with the given name is found. To find multiple occurrences of a string, this function may be called with a node starting point.

No arbitration is done for access to the list!  If multiple tasks
access the same list, an arbitration mechanism such as
SignalSemaphores must be used.

Inputs

start - a list header or a list node to start the search (if node, this one is skipped) name - a pointer to a name string terminated with NULL

Results

node - a pointer to the node with the same name else zero to indicate that the string was not found.


FindPort()

FindPort -- find a given system message port

Synopsis

port = FindPort(name) D0 A1

MsgPort*FindPort(STRPTR);

Function

This function will search the system message port list for a port with the given name. The first port matching this name will be returned. No arbitration of the port list is done. This function MUST be protected with A Forbid()/Permit() pair!

Example

include

struct MsgPort *FindPort();

ULONG SafePutToPort(message, portname)
struct Message *message;
STRPTR          portname;
{
struct MsgPort *port;

    Forbid();
    port = FindPort(portname);
    if (port != NULL)
        PutMsg(port,message);
    Permit();
    return((ULONG)port); /* If zero, the port has gone away */
}

INPUT name - name of the port to find


FindResident()

FindResident - find a resident module by name

Synopsis

resident = FindResident(name) D0 A1

Resident*FindResident(STRPTR);

Function

Search the system resident tag list for a resident tag ("ROMTag") with the given name. If found return a pointer to the resident tag structure, else return zero.

Resident modules are used by the system to pull all its parts
together at startup.  Resident tags are also found in disk based
devices and libraries.

Inputs

name - pointer to name string

Results

resident - pointer to the resident tag structure or zero if none found.

See also

InitResident()


FindSemaphore()

FindSemaphore -- find a given system signal semaphore

Synopsis

signalSemaphore = FindSemaphore(name) D0 A1

SignalSemaphore*FindSemaphore(STRPTR);

Function

This function will search the system signal semaphore list for a semaphore with the given name. The first semaphore matching this name will be returned.

This function does not arbitrate for access to the semaphore list,
surround the call with a Forbid()/Permit() pair.

INPUT name - name of the semaphore to find

Results

semaphore - a pointer to the signal semaphore, or zero if not found.


FindTask()

FindTask -- find a task with the given name or find oneself

Synopsis

task = FindTask(name) D0 A1

Task*FindTask(STRPTR);

Function

This function will check all task queues for a task with the given name, and return a pointer to its task control block. If a NULL name pointer is given a pointer to the current task will be returned.

Finding oneself with a NULL for the name is very quick.  Finding a
task by name is very system expensive, and will disable interrupts
for a long time.  Since a task may remove itself at any time,
a Forbid()/Permit() pair may be needed to ensure the pointer
returned by FindTask() is still valid when used.

INPUT name - pointer to a name string

Results

task - pointer to the task (or Process)


Forbid()

Forbid -- forbid task rescheduling.

Synopsis

Forbid()

void Forbid(void);

Function

Prevents other tasks from being scheduled to run by the dispatcher, until a matching Permit() is executed, or this task is scheduled to Wait(). Interrupts are NOT disabled.

DO NOT USE THIS CALL WITHOUT GOOD JUSTIFICATION.  THIS CALL IS
DANGEROUS!

Results

The current task will not be rescheduled as long as it is ready to run. In the event that the current task enters a wait state, other tasks may be scheduled. Upon return from the wait state, the original task will continue to run without disturbing the Forbid().

Calls to Forbid() nest. In order to restore normal task rescheduling,
the programmer must execute exactly one call to Permit() for every
call to Forbid().

Note

This call is guaranteed to preserve all registers.

See also

Permit(), Disable(), ObtainSemaphore(), ObtainSemaphoreShared()


FreeEntry()

FreeEntry -- free many regions of memory

Synopsis

FreeEntry(memList) A0 void FreeEntry(MemList*);

Function

This function takes a memList structure (as returned by AllocEntry) and frees all the entries.

Inputs

memList -- pointer to structure filled in with MemEntry structures

See also

AllocEntry()


FreeMem()

FreeMem -- deallocate with knowledge

Synopsis

FreeMem(memoryBlock, byteSize) A1 D0

void FreeMem(void *,ULONG);

Function

Free a region of memory, returning it to the system pool from which it came. Freeing partial blocks back into the system pool is unwise.

Inputs

memoryBlock - pointer to the memory block to free byteSize - the size of the desired block in bytes. (The operating system will automatically round this number to a multiple of the system memory chunk size)

Note

If a block of memory is freed twice, the system will Guru. The Alert is AN_FreeTwice ($01000009). If you pass the wrong pointer, you will probably see AN_MemCorrupt $01000005. Future versions may add more sanity checks to the memory lists.

See also

AllocMem()


FreePooled()

FreePooled -- Free pooled memory (V39)

Synopsis

FreePooled(poolHeader,memory,memSize) a0 a1 d0

void FreePooled(APTR,APTR,ULONG);

Function

Deallocates memory allocated by AllocPooled(). The size of the allocation MUST match the size given to AllocPooled(). The reason the pool functions do not track individual allocation sizes is because many of the uses of pools have small allocation sizes and the tracking of the size would be a large overhead.

Only memory allocated by AllocPooled() may be freed with this
function!

Doing a DeletePool() on the pool will free all of the puddles
and thus all of the allocations done with AllocPooled() in that
pool.  (No need to FreePooled() each allocation)

Inputs

poolHeader - a specific private pool header. memory - pointer to memory allocated by AllocPooled. memSize - the number of bytes allocated by AllocPooled. THIS MUST NEVER BE 0!

Notes

The pool functions do not protect an individual pool from multiple accesses. The reason is that in most cases the pools will be used by a single task. If your pool is going to be used by more than one task you must Semaphore protect the pool from having more than one task trying to allocate within the same pool at the same time. Warning: Forbid() protection will not work in the future. Do NOT assume that we will be able to make it work in the future. FreePooled() may well break a Forbid() and as such can only be protected by a semaphore.

The size of the memory allocation to be freed must match
the size used when AllocPooled() was called. A mismatch may
result in memory corruption or in memory remaining allocated
which not even DeletePool() can release. THE SIZE OF THE MEMORY
ALLOCATION MUST NEVER BE 0, OR INSTANT MEMORY CORRUPTION IS
LIKELY TO FOLLOW!

If the address and allocation size cannot be matched against
a puddle or large allocation which is part of the pool, an
alert of type AN_BadFreeAddr will be triggered.

To track sizes yourself, the following code can be used:
Assumes a6=ExecBase

;
; Function to do AllocVecPooled(Pool,memSize)
;
AllocVecPooled: addq.l  #4,d0       ; Get space for tracking
        move.l  d0,-(sp)    ; Save the size
        jsr _LVOAllocPooled(a6) ; Call pool...
        move.l  (sp)+,d1    ; Get size back...
        tst.l   d0      ; Check for error
        beq.s   avp_fail    ; If NULL, failed!
        move.l  d0,a0       ; Get pointer...
        move.l  d1,(a0)+    ; Store size
        move.l  a0,d0       ; Get result
avp_fail:   rts         ; return

;
; Function to do FreeVecPooled(pool,memory)
;
FreeVecPooled:  move.l  -(a1),d0    ; Get size / ajust pointer
        jmp _LVOFreePooled(a6)

See also

AllocPooled(), CreatePool(), DeletePool()


FreeSignal()

FreeSignal -- free a signal bit

Synopsis

FreeSignal(signalNum) D0

void FreeSignal(BYTE);

Function

This function frees a previously allocated signal bit for reuse. This call must be performed while running in the same task in which the signal was allocated.

Inputs

signalNum - the signal number to free {0..31}.

Note

Starting with V37, an attempt to free signal -1 is harmless.


FreeTrap()

FreeTrap -- free a processor trap

Synopsis

FreeTrap(trapNum) D0

void FreeTrap(ULONG);

Function

This function frees a previously allocated trap number for reuse. This call must be performed while running in the same task in which the trap was allocated.

Inputs

trapNum - the trap number to free {of 0..15}


FreeVec()

FreeVec -- return AllocVec() memory to the system (V36)

Synopsis

FreeVec(memoryBlock) A1

void FreeVec(void *);

Function

Free an allocation made by the AllocVec() call. The memory will be returned to the system pool from which it came.

Inputs

memoryBlock - pointer to the memory block to free, or NULL.

Note

If a block of memory is freed twice, the system will Guru. The Alert is AN_FreeTwice ($01000009). If you pass the wrong pointer, you will probably see AN_MemCorrupt $01000005. Future versions may add more sanity checks to the memory lists.

See also

AllocVec()


GetCC()

GetCC -- get condition codes in a 68010 compatible way.

Synopsis

conditions = GetCC() D0

UWORD GetCC(void);

Function

The 68000 processor has a "MOVE SR," instruction which gets a copy of the processor condition codes.

On the 68010,20 and 30 CPUs, "MOVE SR,<ea>" is privileged.  User
code will trap if it is attempted.  These processors need to use
the "MOVE CCR,<ea>" instruction instead.

This function provides a means of obtaining the CPU condition codes
in a manner that will make upgrades transparent.  This function is
VERY short and quick.

Results

conditions - the 680XX condition codes

Note

This call is guaranteed to preserve all registers. This function may be implemented as code right in the jump table.


GetMsg()

GetMsg -- get next message from a message port

Synopsis

message = GetMsg(port) D0 A0

Message*GetMsg(MsgPort*);

Function

This function receives a message from a given message port. It provides a fast, non-copying message receiving mechanism. The received message is removed from the message port.

This function will not wait.  If a message is not present this
function will return zero.  If a program must wait for a message,
it can Wait() on the signal specified for the port or use the
WaitPort() function.  There can only be one task waiting for any
given port.

Getting a message does not imply to the sender that the message is
free to be reused by the sender.  When the receiver is finished
with the message, it may ReplyMsg() it back to the sender.

Getting a signal does NOT always imply a message is ready.  More
than one message may arrive per signal, and signals may show up
without messages.  Typically you must loop to GetMsg() until it
returns zero, then Wait() or WaitPort().

INPUT port - a pointer to the receiver message port

Results

message - a pointer to the first message available. If there are no messages, return zero. Callers must be prepared for zero at any time.

See also

PutMsg(), ReplyMsg(), WaitPort()


InitCode()

InitCode - initialize resident code modules (internal function)

Synopsis

InitCode(startClass, version) D0 D1

void InitCode(ULONG,ULONG);

Function

(This function may be ignored by application programmers)

Call InitResident() for all resident modules in the ResModules array
with the given startClass and with versions equal or greater than
that specified.  The segList parameter is passed as zero.

Resident modules are used by the system to pull all its parts
together at startup.  Modules are initialized in a prioritized order.

Modules that do not have a startclass should be of priority -120.
RTF_AFTERDOS modules should start at -100 (working down).

Inputs

startClass - the class of code to be initialized: BITDEF RT,COLDSTART,0 BITDEF RT,SINGLETASK,1 ;ExecBase->ThisTask==0 (V36 only) BITDEF RT,AFTERDOS,2 ;(V36 only) version - a major version number


InitResident()

InitResident - initialize resident module

Synopsis

object = InitResident(resident, segList) D0 A1 D1

APTR InitResident(Resident*,ULONG);

Function

Initialize a ROMTag. ROMTags are used to link system modules together. Each disk based device or library must contain a ROMTag structure in the first code hunk.

Once the validity of the ROMTag is verified, the RT_INIT pointer
is jumped to  with the following registers:
    D0 = 0
    A0 = segList
    A6 = ExecBase

Inputs

resident - Pointer to a ROMTag segList - SegList of the loaded object, if loaded from disk. Libraries & Devices will cache this value for later return at close or expunge time. Pass NULL for ROM modules.

Results

object - Return value from the init code, usually the library or device base. NULL for failure.

AUTOINIT FEATURE An automatic method of library/device base and vector table initialization is also provided by InitResident(). The initial code hunk of the library or device should contain "MOVEQ #-1,d0; RTS;". Following that must be an initialized Resident structure with RTF_AUTOINIT set in rt_Flags, and an rt_Init pointer which points to four longwords. These four longwords will be used in a call to MakeLibrary();

    - The size of your library/device base structure including initial
      Library or Device structure.

    - A pointer to a longword table of standard, then library
      specific function offsets, terminated with -1L.
      (short format offsets are also acceptable)

    - Pointer to data table in exec/InitStruct format for
      initialization of Library or Device structure.

    - Pointer to library initialization function, or NULL.
    Calling sequence:
        D0 = library base
        A0 = segList
        A6 = ExecBase
      This function must return in D0 the library/device base to be
      linked into the library/device list.  If the initialization
      function fails, the device memory must be manually deallocated,
      then NULL returned in D0.

See also

FindResident()


InitSemaphore()

InitSemaphore -- initialize a signal semaphore

Synopsis

InitSemaphore(signalSemaphore) A0

void InitSemaphore(SignalSemaphore*);

Function

This function initializes a signal semaphore and prepares it for use. It does not allocate anything, but does initialize list pointers and the semaphore counters.

Semaphores are often used to protect critical data structures
or hardware that can only be accessed by one task at a time.
After initialization, the address of the SignalSemaphore may be
made available to any number of tasks.  Typically a task will
try to ObtainSemaphore(), passing this address in.  If no other
task owns the semaphore, then the call will lock and return
quickly.  If more tasks try to ObtainSemaphore(), they will
be put to sleep.  When the owner of the semaphore releases
it, the next waiter in turn will be woken up.

Semaphores are often preferable to the old-style Forbid()/Permit()
type arbitration.  With Forbid()/Permit() *all* other tasks are
prevented from running.  With semaphores, only those tasks that
need access to whatever the semaphore protects are subject
to waiting.

INPUT signalSemaphore -- a signal semaphore structure (with all fields set to zero before the call)

See also

ObtainSemaphore(), ObtainSemaphoreShared(), AttemptSemaphore(), ReleaseSemaphore(), Procure(), Vacate()


InitStruct()

InitStruct - initialize memory from a table

Synopsis

InitStruct(initTable, memory, size); A1 A2 D0

void InitStruct(struct InitStruct*, APTR, ULONG);

Function

Clear a memory area, then set up default values according to the data and offset values in the initTable. Typically only assembly programs take advantage of this function, and only with the macros defined in "exec/initializers.i".

The initialization table has byte commands to

     |a    ||byte|  |given||byte|         |once     |
load |count||word| into |next ||rptr| offset, |repetitively |
        |long|

Not all combinations are supported.  The offset, when specified, is
relative to the memory pointer provided (Memory), and is initially
zero.  The initialization data (InitTable) contains byte commands
whose 8 bits are interpreted as follows:

ddssnnnn
    dd  the destination type (and size):
    00  no offset, use next destination, nnnn is count
    01  no offset, use next destination, nnnn is repeat
    10  destination offset is in the next byte, nnnn is count
    11  destination offset is in the next 24-bits, nnnn is count
    ss  the size and location of the source:
    00  long, from the next two aligned words
    01  word, from the next aligned word
    10  byte, from the next byte
    11  ERROR - will cause an ALERT (see below)
  nnnn  the count or repeat:
     count  the (number+1) of source items to copy
    repeat  the source is copied (number+1) times.

initTable commands are always read from the next even byte. Given
destination offsets are always relative to the memory pointer (A2).

The command %00000000 ends the InitTable stream: use %00010001 if you
really want to copy one longword without a new offset.

24 bit APTR not supported for 68020 compatibility -- use long.

Inputs

initTable - the beginning of the commands and data to init Memory with. Must be on an even boundary unless only byte initialization is done. End table with "dc.b 0" or "dc.w 0". memory - the beginning of the memory to initialize. Must be on an even boundary if size is specified. size - the size of memory, which is used to clear it before initializing it via the initTable. If Size is zero, memory is not cleared before initializing.

    size must be an even number.

Insert()

Insert -- insert a node into a list

Synopsis

Insert(list, node, listNode) A0 A1 A2

void Insert(List*,Node*,Node*);

Function

Insert a node into a doubly linked list AFTER a given node position. Insertion at the head of a list is possible by passing a zero value for listNode, though the AddHead function is slightly faster for that special case.

Inputs

list - a pointer to the target list header node - the node to insert listNode - the node after which to insert

See also

AddHead(), AddTail(), Enqueue(), RemHead(), Remove(), RemTail()


MakeFunctions()

MakeFunctions -- construct a function jump table

Synopsis

tableSize = MakeFunctions(target, functionArray, funcDispBase) D0 A0 A1 A2

ULONG MakeFunctions(APTR,APTR,APTR);

Function

A low level function used by MakeLibrary to build jump tables of the type used by libraries, devices and resources. It allows the table to be built anywhere in memory, and can be used both for initialization and replacement. This function also supports function pointer compression by expanding relative displacements into absolute pointers.

The processor instruction cache is cleared after the table building.

INPUT destination - the target address for the high memory end of the function jump table. Typically this will be the library base pointer.

functionArray - pointer to an array of function pointers or
    function displacements.  If funcDispBase is zero, the array
    is assumed to contain absolute pointers to functions. If
    funcDispBase is not zero, then the array is assumed to
    contain word displacements to functions.  In both cases,
    the array is terminated by a -1 (of the same size as the
    actual entry.

funcDispBase - pointer to the base about which all function
    displacements are relative.  If zero, then the function
    array contains absolute pointers.

Results

tableSize - size of the new table in bytes (for LIB_NEGSIZE).

See also

MakeLibrary()


MakeLibrary()

MakeLibrary -- construct a library

Synopsis

library = MakeLibrary(vectors, structure, init, dSize, segList) D0 A0 A1 A2 D0 D1

Library*MakeLibrary (APTR,struct InitStruct*,APTR,ULONG,BPTR);

Function

This function is used for constructing a library vector and data area. The same call is used to make devices. Space for the library is allocated from the system's free memory pool. The data portion of the library is initialized. init may point to a library specific entry point.

Inputs

vectors - pointer to an array of function pointers or function displacements. If the first word of the array is -1, then the array contains relative word displacements (based off of vectors); otherwise, the array contains absolute function pointers. The vector list is terminated by a -1 (of the same size as the pointers).

structure - points to an "InitStruct" data region.  If NULL,
    then it will not be used.

init -  If non-NULL, an entry point that will be called before adding
    the library to the system.  Registers are as follows:
        d0 = libAddr    ;Your Library Address
        a0 = segList    ;Your AmigaDOS segment list
        a6 = ExecBase   ;Address of exec.library
    The result of the init function must be the library address,
    or NULL for failure.   If NULL, the init point must manually
    deallocate the library base memory (based on the sizes stored
    in lib_PosSize and lib_NegSize).

dSize - the size of the library data area, including the
    standard library node data.  This must be at leas
    sizeof(struct Library).

   segList - pointer to an AmigaDOS SegList (segment list).
     This is passed to a library's init code, and is used later
     for removing the library from memory.

Results

library - the reference address of the library. This is the address used in references to the library, not the beginning of the memory area allocated. If the library vector table require more system memory than is available, this function will return NULL.

Note

Starting with V36, the library base is longword adjusted. The lib_PosSize and lib_NegSize fields of the library structure are adjusted to match.

See also

InitStruct(), InitResident()


NewMinList()

NewMinList -- prepare a list structure for use (V45)

Synopsis

NewMinList(list)

VOID NewMinList(MinList*);

Function

Perform the magic needed to prepare a MinList header structure for use; the list will be empty and ready to use. You can use this function with a pointer to a 'struct List', too, but you may have to initialize the List->lh_Type as well.

Inputs

list - pointer to a List or MinList.


ObtainQuickVector()

Function to obtain an install a Quick Interrupt vector (V39)

Synopsis

vector=ObtainQuickVector(interruptCode) d0 a0

ULONG ObtainQuickVector(APTR);

Function

This function will install the code pointer into the quick interrupt vector it allocates and returns to you the interrupt vector that your Quick Interrupt system needs to use.

This function may also return 0 if no vectors are available.  Your
hardware should be able to then fall back to using the shared
interrupt server chain should this happen.

The interrupt code is a direct connect to the physical interrupt.
This means that it is the responsibility of your code to do all
of the context saving/restoring required by interrupt code.

Also, due to the performance of the interrupt controller, you may
need to also watch for "false" interrupts.  These are interrupts
that come in just after a DISABLE.  The reason this happens is
because the interrupt may have been posted before the DISABLE
hardware access is completed.  For example:

myInt:      move.l  d0,-(sp)    ; Save d0...
        move.w  _intenar,d0 ; Get interrupt enable state
        btst.l  #INTB_INTEN,d0  ; Check if pending disable
        bne.s   realInt     ; If not, do real one...
exitInt:    move.l  (sp)+,d0    ; Restore d0
        rte         ; Return from int...
;
realInt:    ; Now do your int code...  d0 is already saved
        ; ALL other registers need to be saved if needed
        ; This includes a0/a1/d0/d1 as this is an interrupt
        ; and not a function call...
        ;
        bra.s   exitInt     ; Exit interrupt...

If your interrupt will not play with system (OS) structures and your
own structures are safe to play with you do not need to check for
the disable.  It is only needed for when the system is in disable but
that "one last interrupt" still got through.

Inputs

A pointer to your interrupt code. This code is not an EXEC interrupt but is dirrectly connected to the hardware interrupt. Thus, the interrupt code must not modify any registers and must return via an RTE.

Results

The 8-bit vector number used for Zorro-III Quick Interrupts If it returns 0, no quick interrupt was allocatable. The device should at this point switch to using the shared interrupt server method.

Note

This function was not implemented fully until V39. Due to a mis-cue it is not safe to call in V37 EXEC. (Sorry)


ObtainSemaphore()

ObtainSemaphore -- gain exclusive access to a semaphore

Synopsis

ObtainSemaphore(signalSemaphore) A0

void ObtainSemaphore(SignalSemaphore*);

Function

Signal semaphores are used to gain exclusive access to an object. ObtainSemaphore is the call used to gain this access. If another user currently has the semaphore locked the call will block until the object is available.

If the current task already has locked the semaphore and attempts to
lock it again the call will still succeed.  A "nesting count" is
incremented each time the current owning task of the semaphore calls
ObtainSemaphore().  This counter is decremented each time
ReleaseSemaphore() is called.  When the counter returns to zero the
semaphore is actually released, and the next waiting task is called.

A queue of waiting tasks is maintained on the stacks of the waiting
tasks.  Each will be called in turn as soon as the current task
releases the semaphore.

Signal Semaphores are different than Procure()/Vacate() semaphores.
The former requires less CPU time, especially if the semaphore is
not currently locked.  They require very little set up and user
thought.  The latter flavor of semaphore make no assumptions about
how they are used -- they are completely general.  Unfortunately
they are not as efficient as signal semaphores, and require the
locker to have done some setup before doing the call.

INPUT signalSemaphore -- an initialized signal semaphore structure

Note

This function preserves all registers (see BUGS).

Bugs

Until V37, this function could destroy A0.

See also

ObtainSemaphoreShared(), InitSemaphore(), ReleaseSemaphore(), AttemptSemaphore(), ObtainSemaphoreList(), Procure(), Vacate()


ObtainSemaphoreList()

ObtainSemaphoreList -- get a list of semaphores.

Synopsis

ObtainSemaphoreList(list) A0

void ObtainSemaphoreList(List*);

Function

Signal semaphores may be linked together into a list. This function takes a list of these semaphores and attempts to lock all of them at once. This call is preferable to applying ObtainSemaphore() to each element in the list because it attempts to lock all the elements simultaneously, and won't deadlock if someone is attempting to lock in some other order.

This function assumes that only one task at a time will attempt to
lock the entire list of semaphores.  In other words, there needs to
be a higher level lock (perhaps another signal semaphore...) that is
used before someone attempts to lock the semaphore list via
ObtainSemaphoreList().

Note that deadlocks may result if this call is used AND someone
attempts to use ObtainSemaphore() to lock more than one semaphore on
the list.  If you wish to lock more than semaphore (but not all of
them) then you should obtain the higher level lock (see above)

INPUT list -- a list of signal semaphores

See also

ObtainSemaphoreShared(), InitSemaphore(), ReleaseSemaphore(), AttemptSemaphore(), Procure(), Vacate()


ObtainSemaphoreShared()

ObtainSemaphoreShared -- gain shared access to a semaphore (V36)

Synopsis

ObtainSemaphoreShared(signalSemaphore) a0

void ObtainSemaphoreShared(SignalSemaphore*);

Function

A lock on a signal semaphore may either be exclusive, or shared. Exclusive locks are granted by the ObtainSemaphore() and AttemptSemaphore() functions. Shared locks are granted by ObtainSemaphoreShared(). Calls may be nested.

Any number of tasks may simultaneously hold a shared lock on a
semaphore.  Only one task may hold an exclusive lock.  A typical
application is a list that is often read, but only occasionally
written to.

Any exlusive locker will be held off until all shared lockers
release the semaphore.  Likewise, if an exlusive lock is held,
all potential shared lockers will block until the exclusive lock
is released.  All shared lockers are restarted at the same time.

Note

This call is guaranteed to preserve all registers, starting with V37 exec.

Notes

While this function was added for V36, the feature magically works with all older semaphore structures.

A task owning a shared lock must not attempt to get an exclusive
lock on the same semaphore.

Starting in V39, if the caller already has an exclusive lock on the
semaphore it will return with another nesting of the lock.  Pre-V39
this would cause a deadlock.  For pre-V39 use, you can use the
following workaround:

    \* Try to get the shared semaphore *\
    if (!AttemptSemaphoreShared(ss))
    {
        \* Check if we can get the exclusive version *\
        if (!AttemptSemaphore(ss))
        {
            \* Oh well, wait for the shared lock *\
            ObtainSemaphoreShared(ss));
        }
    }
    :
    :
    ReleaseSemaphore(ss);

INPUT
signalSemaphore -- an initialized signal semaphore structure

Example

ObtainSemaphoreShared(ss); / read data / ReleaseSemaohore(ss);

    ObtainSemaphore(ss);
    /* modify data */
    ReleaseSemaohore(ss);

See also

ObtainSemaphore(), InitSemaphore(), ReleaseSemaphore(), AttemptSemaphore(), ObtainSemaphoreList(), Procure(), Vacate()


OldOpenLibrary()

OldOpenLibrary -- obsolete OpenLibrary

Synopsis

library = OldOpenLibrary(libName) D0 A1

Library*OldOpenLibrary(APTR);

Function

The 1.0 release of the Amiga system had an incorrect version of OpenLibrary that did not check the version number during the library open. This obsolete function is provided so that object code compiled using a 1.0 system will still run.

This exactly the same as "OpenLibrary(libName,0L);"

Inputs

libName - the name of the library to open

Results

library - a library pointer for a successful open, else zero

See also

CloseLibrary()


OpenDevice()

OpenDevice -- gain access to a device

Synopsis

error = OpenDevice(devName, unitNumber, iORequest, flags) D0 A0 D0 A1 D1

BYTE OpenDevice(STRPTR,ULONG,IORequest*,ULONG);

Function

This function opens the named device/unit and initializes the given I/O request block. Specific documentation on opening procedures may come with certain devices.

The device may exist in memory, or on disk; this is transparent to
the OpenDevice caller.

A full path name for the device name is legitimate.  For example
"test:devs/fred.device".  This allows the use of custom devices
without requiring the user to copy the device into the system's
DEVS: directory.

Inputs

devName - requested device name

unitNumber - the unit number to open on that device.  The format of
    the unit number is device specific.  If the device does
    not have separate units, send a zero.

iORequest - the I/O request block to be returned with
    appropriate fields initialized.

flags - additional driver specific information.  This is sometimes
    used to request opening a device with exclusive access.

Results

error - Returns a sign-extended copy of the io_Error field of the IORequest. Zero if successful, else an error code is returned.

Notes

All calls to OpenDevice should have matching calls to CloseDevice!

Devices on disk cannot be opened until after DOS has been
started.

As of V36 tasks can safely call OpenDevice, though DOS may open
system requesters (e.g., asking the user to insert the Workbench
disk if DEVS: is not online).  You must call this function from a
DOS Process if you want to turn off DOS requesters.

Bugs

AmigaDOS file names are not case sensitive, but Exec lists are. If the device name is specified in a different case than it exists on disk, unexpected results may occur. The same holds true if the device exists in memory and the device name is specified in a different case.

Prior to V36, tasks could not make OpenDevice calls requiring disk
access (since tasks are not allowed to make dos.library calls).
Now OpenDevice is protected from tasks.

See also

CloseDevice(), DoIO(), SendIO(), CheckIO(), AbortIO(), WaitIO()


OpenLibrary()

OpenLibrary -- gain access to a library

Synopsis

library = OpenLibrary(libName, version) D0 A1 D0

Library*OpenLibrary(STRPTR, ULONG);

Function

This function returns a pointer to a library that was previously installed into the system. If the requested library is exists, and if the library version is greater than or equal to the requested version, then the open will succeed.

The library may exist in memory, or on disk; this is transparent to
the OpenLibrary caller.  Only Processes are allowed to call
OpenLibrary (since OpenLibrary may in turn call dos.library).

A full path name for the library name is legitimate.  For example
"wp:libs/wp.library".  This allows the use of custom libraries
without requiring the user to copy the library into the system's
LIBS: directory.

Inputs

libName - the name of the library to open

version - the version of the library required.

Results

library - a library pointer for a successful open, else zero

Notes

All calls to OpenLibrary should have matching calls to CloseLibrary!

Libraries on disk cannot be opened until after DOS has been
started.

As of V36 tasks can safely call OpenLibrary, though DOS may open
system requesters (e.g., asking the user to insert the Workbench
disk if LIBS: is not online).  You must call this function from a
DOS Process if you want to turn off DOS requesters.

Bugs

AmigaDOS file names are not case sensitive, but Exec lists are. If the library name is specified in a different case than it exists on disk, unexpected results may occur. The same holds true if the library exists in memory and the library name is specified in a different case.

Prior to V36, tasks could not make OpenLibrary calls requiring disk
access (since tasks are not allowed to make dos.library calls).
Now OpenLibrary is protected from tasks.

The version number of the resident tag in a disk based library must
match the version number of the library, or V36 may fail to load it.

See also

CloseLibrary()


OpenResource()

OpenResource -- gain access to a resource

Synopsis

resource = OpenResource(resName) D0 A1

APTR OpenResource(STRPTR);

Function

This function returns a pointer to a resource that was previously installed into the system.

There is no CloseResource() function.

Inputs

resName - the name of the resource requested.

Results

resource - if successful, a resource pointer, else NULL


Permit()

Permit -- permit task rescheduling.

Synopsis

Permit()

void Permit(void);

Function

Allow other tasks to be scheduled to run by the dispatcher, after a matching Forbid() has been executed.

Results

Other tasks will be rescheduled as they are ready to run. In order to restore normal task rescheduling, the programmer must execute exactly one call to Permit() for every call to Forbid().

Note

This call is guaranteed to preserve all registers.

See also

Forbid(), Disable(), Enable()


Procure()

Procure -- bid for a semaphore (V39)

Synopsis

Procure(semaphore, bidMessage) A0 A1

VOID Procure(SignalSemaphore*,SemaphoreMessage*);

Function

This function is used to obtain a semaphore in an async manner. Like ObtainSemaphore(), it will obtain a SignalSemaphore for you but unlike ObtainSemaphore(), you will not block until you get the semaphore. Procure() will just post a request for the semaphore and will return. When the semaphore is available (which could be at any time) the bidMessage will ReplyMsg() and you will own the semaphore. This lets you wait on multiple semaphores at once and to continue processing while waiting for the semaphore.

NOTE:  Pre-V39, Procure() and Vacate() did not work correctly.
They also did not operate on SignalSemaphore semaphores.
Old (and broken) MessageSemaphore use as of V39 will no longer work.

INPUT semaphore - The SignalSemaphore that you wish to Procure() bidMessage- The SemaphoreMessage that you wish replied when you obtain access to the semaphore. The message's ssm_Semaphore field will point at the semaphore that was obtained. If the ssm_Semaphore field is NULL, the Procure() was aborted via Vacate(). The mn_ReplyPort field of the message must point to a valid message port. To obtain a shared semaphore, the ln_Name field must be set to 1. For an exclusive lock, the ln_Name field must be 0. No other values are valid.

Bugs

Before V39, Procure() and Vacate() used a different semaphore system that was very broken. This new system is only available as of V39 even though the LVOs are the same.

See also

ObtainSemaphoreShared(), InitSemaphore(), ReleaseSemaphore(), AttemptSemaphore(), ObtainSemaphoreList(), Vacate(), ObtainSemaphore()


PutMsg()

PutMsg -- put a message to a message port

Synopsis

PutMsg(port, message) A0 A1

void PutMsg(MsgPort*,Message*);

Function

This function attaches a message to the end of a given message port. It provides a fast, non-copying message sending mechanism.

Messages can be attached to only one port at a time.  The message
body can be of any size or form.  Because messages are not copied,
cooperating tasks share the same message memory.  The sender task
must not recycle the message until it has been replied by the
receiver.  Of course this depends on the message handling conventions
setup by the involved tasks.  If the mn_ReplyPort field is non-zero,
when the message is replied by the receiver through ReplyMsg(), it
will be sent to that port.

Any one of the following actions can be set to occur when a message
is put:

    1. no special action
    2. signal a given task (specified by MP_SIGTASK)
    3. cause a software interrupt (specified by MP_SIGTASK)

The action is selected depending on the value found in the MP_FLAGS
of the destination port.

This function is safe to call from interrupts.

IMPLEMENTATION 1. Sets the mn_Node.ln_Type field of the message to "NT_MESSAGE". 2. Attaches the message to the destination port. 3. Performs the specified arrival action at the destination.

INPUT port - pointer to a message port message - pointer to a message

See also

GetMsg(), ReplyMsg()


RawDoFmt()

RawDoFmt -- format data into a character stream.

Synopsis

NextData = RawDoFmt(FormatString, DataStream, PutChProc, PutChData); d0 a0 a1 a2 a3

APTR RawDoFmt(STRPTR,APTR,void (*)(),APTR);

Function

perform "C"-language-like formatting of a data stream, outputting the result a character at a time. Where % formatting commands are found in the FormatString, they will be replaced with the corresponding element in the DataStream. %% must be used in the string if a % is desired in the output.

Under V36, RawDoFmt() returns a pointer to the end of the DataStream
(The next argument that would have been processed).  This allows
multiple formatting passes to be made using the same data.

Inputs

FormatString - a "C"-language-like NULL terminated format string, with the following supported % options:

 %[flags][width.limit][length]type

flags  - only one allowed. '-' specifies left justification.
width  - field width.  If the first character is a '0', the
     field will be padded with leading 0's.
  .    - must follow the field width, if specified
limit  - maximum number of characters to output from a string.
     (only valid for %s).
length - size of input data defaults to WORD for types d, x,
     and c, 'l' changes this to long (32-bit).
type   - supported types are:
        b - BSTR, data is 32-bit BPTR to byte count followed
            by a byte string, or NULL terminated byte string.
            A NULL BPTR is treated as an empty string.
            (Added in V36 exec)
        d - decimal
        u - unsigned decimal (Added in V37 exec)
        x - hexadecimal
        s - string, a 32-bit pointer to a NULL terminated
            byte string.  In V36, a NULL pointer is treated
            as an empty string
        c - character

DataStream - a stream of data that is interpreted according to
     the format string.  Often this is a pointer into
     the task's stack.
PutChProc  - the procedure to call with each character to be
     output, called as:

PutChProc(Char,  PutChData);
      D0-0:8 A3

    the procedure is called with a NULL Char at the end of
    the format string.
    Starting with V45.1, this pointer may be NULL. In that
    case, the default "stuffChar" procedure shown below is
    used.

PutChData - a value that is passed through to the PutChProc
    procedure.  This is untouched by RawDoFmt, and may be
    modified by the PutChProc.

Example

; ; Simple version of the C "sprintf" function. Assumes C-style ; stack-based function conventions. ; ; long eyecount; ; eyecount=2; ; sprintf(string,"%s have %ld eyes.","Fish",eyecount); ; ; would produce "Fish have 2 eyes." in the string buffer. ; XDEF _sprintf XREF _AbsExecBase XREF _LVORawDoFmt _sprintf: ; ( ostring, format, {values} ) movem.l a2/a3/a6,-(sp)

    move.l  4*4(sp),a3       ;Get the output string pointer
    move.l  5*4(sp),a0       ;Get the FormatString pointer
    lea.l   6*4(sp),a1       ;Get the pointer to the DataStream
    lea.l   stuffChar(pc),a2
    move.l  _AbsExecBase,a6
    jsr _LVORawDoFmt(a6)

    movem.l (sp)+,a2/a3/a6
    rts

;------ PutChProc function used by RawDoFmt -----------
stuffChar:
    move.b  d0,(a3)+        ;Put data to output string
    rts

ReleaseSemaphore()

ReleaseSemaphore -- make signal semaphore available to others

Synopsis

ReleaseSemaphore(signalSemaphore) A0

void ReleaseSemaphore(SignalSemaphore*);

Function

ReleaseSemaphore() is the inverse of ObtainSemaphore(). It makes the semaphore lockable to other users. If tasks are waiting for the semaphore and this this task is done with the semaphore then the next waiting task is signalled.

Each ObtainSemaphore() call must be balanced by exactly one
ReleaseSemaphore() call.  This is because there is a nesting count
maintained in the semaphore of the number of times that the current
task has locked the semaphore. The semaphore is not released to
other tasks until the number of releases matches the number of
obtains.

Needless to say, havoc breaks out if the task releases more times
than it has obtained.

INPUT signalSemaphore -- an initialized signal semaphore structure

Note

This call is guaranteed to preserve all registers.

Bugs

In V39 and V40 Kickstart, there is an error condition that bumps ss_NestCount twice, if multiple Procure() SemaphoreMessages and a ObtainSemaphore() are pending for the same task.

See also

InitSemaphore(), ObtainSemaphore(), ObtainSemaphoreShared()


ReleaseSemaphoreList()

ReleaseSemaphoreList -- make a list of semaphores available

Synopsis

ReleaseSemaphoreList(list) A0

void ReleaseSemaphoreList(List*);

Function

ReleaseSemaphoreList() is the inverse of ObtainSemaphoreList(). It releases each element in the semaphore list.

Needless to say, havoc breaks out if the task releases more times
than it has obtained.

INPUT list -- a list of signal semaphores

See also

ObtainSemaphoreList()


RemDevice()

RemDevice -- remove a device from the system

Synopsis

RemDevice(device) A1

void RemDevice(Device*);

Function

This function calls the device's EXPUNGE vector, which requests that a device delete itself. The device may refuse to do this if it is busy or currently open. This is not typically called by user code.

There are certain, limited circumstances where it may be
appropriate to attempt to specifically flush a certain device.
Example:

 /* Attempts to flush the named device out of memory. */
 #include <exec/types.h>
 #include <exec/execbase.h>

 void FlushDevice(name)
 STRPTR name;
 {
 struct Device *result;

    Forbid();
    result = (struct Device *)FindName(&SysBase->DeviceList, name);
    if (result != NULL)
         RemDevice(result);
    Permit();
 }

Inputs

device - pointer to a device node

See also

AddLibrary()


RemHead()

RemHead -- remove the head node from a list

Synopsis

node = RemHead(list) D0 A0

Node*RemHead(List*);

Function

Get a pointer to the head node and remove it from the list. Assembly programmers may prefer to use the REMHEAD macro from "exec/lists.i".

Inputs

list - a pointer to the target list header

Results

node - the node removed or zero when empty list

See also

AddHead(), AddTail(), Enqueue(), Insert(), Remove(), RemTail()


RemIntServer()

RemIntServer -- remove an interrupt server from a server chain

Synopsis

RemIntServer(intNum, interrupt) D0 A1

void RemIntServer(ULONG,Interrupt*);

Function

This function removes an interrupt server node from the given server chain.

If this server was the last one on this chain, interrupts for this
chain are disabled.

Inputs

intNum - the Paula interrupt bit (0..14) interrupt - pointer to an interrupt server node

Bugs

Before V36 Kickstart, the feature that disables the interrupt would not function. For most server chains this does not cause a problem.

See also

AddIntServer()


RemLibrary()

RemLibrary -- remove a library from the system

Synopsis

RemLibrary(library) A1

void RemLibrary(Library*);

Function

This function calls the library's EXPUNGE vector, which requests that a library delete itself. The library may refuse to do this if it is busy or currently open. This is not typically called by user code.

There are certain, limited circumstances where it may be
appropriate to attempt to specifically flush a certain Library.
Example:

 /* Attempts to flush the named library out of memory. */
 #include <exec/types.h>
 #include <exec/execbase.h>

 void FlushLibrary(name)
 STRPTR name;
 {
 struct Library *result;

    Forbid();
    result = (struct Library *)FindName(&SysBase->LibList, name);
    if (result != NULL)
         RemLibrary(result);
    Permit();
 }

Inputs

library - pointer to a library node structure


RemMemHandler()

RemMemHandler - Remove low memory handler from exec (V39)

Synopsis

RemMemHandler(memHandler) A1

VOID RemMemHandler(Interrupt*);

Function

This function removes the low memory handler from the system. This function can be called from within a handler. If removing oneself, it is important that the handler returns MEM_ALL_DONE.

Inputs

memHandler - Pointer to a handler added with AddMemHandler()

Note

When removing a handler, the handler may be called until this function returns. Thus, the handler must still be valid until then.

See also

AddMemHandler()


Remove()

Remove -- remove a node from a list

Synopsis

Remove(node) A1

void Remove(Node*);

Function

Unlink a node from whatever list it is in. Nodes that are not part of a list must not be passed to this function! Assembly programmers may prefer to use the REMOVE macro from "exec/lists.i".

Inputs

node - the node to remove

See also

AddHead(), AddTail(), Enqueue(), Insert(), RemHead(), RemTail()


RemPort()

RemPort -- remove a message port from the system

Synopsis

RemPort(port) A1

void RemPort(MsgPort*);

Function

This function removes a message port structure from the system's message port list. Subsequent attempts to rendezvous by name with this port will fail.

Inputs

port - pointer to a message port

See also

AddPort(), FindPort()


RemResource()

RemResource -- remove a resource from the system

Synopsis

RemResource(resource) A1

void RemResource(APTR);

Function

This function removes an existing resource from the system resource list. There must be no outstanding users of the resource.

Inputs

resource - pointer to a resource node

See also

AddResource()


RemSemaphore()

RemSemaphore -- remove a signal semaphore from the system

Synopsis

RemSemaphore(signalSemaphore) A1

void RemSemaphore(SignalSemaphore*);

Function

This function removes a signal semaphore structure from the system's signal semaphore list. Subsequent attempts to rendezvous by name with this semaphore will fail.

Inputs

signalSemaphore -- an initialized signal semaphore structure

See also

AddSemaphore(), FindSemaphore()


RemTail()

RemTail -- remove the tail node from a list

Synopsis

node = RemTail(list) D0 A0

Node*RemTail(List*);

Function

Remove the last node from a list, and return a pointer to it. If the list is empty, return zero. Assembly programmers may prefer to use the REMTAIL macro from "exec/lists.i".

Inputs

list - a pointer to the target list header

Results

node - the node removed or zero when empty list

See also

AddHead(), AddTail(), Enqueue(), Insert(), Remove(), RemHead()


RemTask()

RemTask -- remove a task from the system

Synopsis

RemTask(task) A1

void RemTask(Task*);

Function

This function removes a task from the system. Deallocation of resources should have been performed prior to calling this function. Removing some other task is very dangerous. Generally is is best to arrange for tasks to call RemTask(0L) on themselves.

RemTask will automagically free any memory lists attached to the
task's tc_MemEntry list.

Inputs

task - pointer to the task node representing the task to be removed. A zero value indicates self removal, and will cause the next ready task to begin execution.

Bugs

Before V36 if RemTask() was called on a task other than the current task, and that task was created with amiga.lib/CreateTask, there was a slight chance of a crash. The problem can be hidden by bracketing RemTask() with Forbid()/Permit().

See also

AddTask(), AllocEntry(), DeleteTask()


ReplyMsg()

ReplyMsg -- put a message to its reply port

Synopsis

ReplyMsg(message) A1

void ReplyMsg(Message*);

Function

This function sends a message to its reply port. This is usually done when the receiver of a message has finished and wants to return it to the sender (so that it can be re-used or deallocated, whatever).

This call may be made from interrupts.

INPUT message - a pointer to the message

IMPLEMENTATION 1. Places "NT_REPLYMSG" into the mn_Node.ln_Type field. 2. Puts the message to the port specified by mn_ReplyPort. If mn_ReplyPort is NULL, sets mn_Node.ln_Type to "NT_FREEMSG" (use this feature only with extreme care).

See also

GetMsg(), PutMsg()


SendIO()

SendIO -- initiate an I/O command

Synopsis

SendIO(iORequest) A1

void SendIO(IORequest*);

Function

This function requests the device driver start processing the given I/O request. The device will return control without waiting for the I/O to complete.

The io_Flags field of the IORequest will be set to zero before the
request is sent.  See BeginIO() for more details.

Inputs

iORequest - pointer to an I/O request, or a device specific extended IORequest.

See also

DoIO(), CheckIO(), WaitIO(), AbortIO()


SetExcept()

SetExcept -- define certain signals to cause exceptions

Synopsis

oldSignals = SetExcept(newSignals, signalMask) D0 D0 D1

ULONG SetExcept(ULONG,ULONG);

Function

This function defines which of the task's signals will cause a private task exception. When any of the signals occurs the task's exception handler will be dispatched. If the signal occurred prior to calling SetExcept, the exception will happen immediately.

The user function pointed to by the task's tc_ExceptCode gets
called as:

    newExcptSet = <exceptCode>(signals, exceptData),SysBase
    D0                 D0   A1      A6

    signals - The set of signals that caused this exception.  These
    Signals have been disabled from the current set of signals
    that can cause an exception.

    exceptData - A copy of the task structure tc_ExceptData field.

    newExcptSet - The set of signals in NewExceptSet will be re-
    enabled for exception generation.  Usually this will be the
    same as the Signals that caused the exception.

Inputs

newSignals - the new values for the signals specified in signalMask. signalMask - the set of signals to be effected

Results

oldSignals - the prior exception signals

Example

Get the current state of all exception signals: SetExcept(0,0) Change a few exception signals: SetExcept($1374,$1074)

See also

Signal(), SetSignal()


SetFunction()

SetFunction -- change a function vector in a library

Synopsis

oldFunc = SetFunction(library, funcOffset, funcEntry) D0 A1 A0.W D0

APTR SetFunction(Library*,LONG,APTR);

Function

SetFunction is a functional way of changing where vectors in a library point. They are changed in such a way that the checksumming process will never falsely declare a library to be invalid.

Inputs

library - a pointer to the library to be changed funcOffset - the offset of the function to be replaced funcEntry - pointer to new function

Results

oldFunc - pointer to the old function that was just replaced

Note

SetFunction cannot be used on non-standard libraries like pre-V36 dos.library. Here you must manually Forbid(), preserve all 6 original bytes, set the new vector, SumLibrary(), then Permit().


SetIntVector()

SetIntVector -- set a new handler for a system interrupt vector

Synopsis

oldInterrupt = SetIntVector(intNumber, interrupt) D0 D0 A1

Interrupt*SetIntVector(ULONG,Interrupt*);

Function

This function provides a mechanism for setting the system interrupt vectors. These are non-sharable; setting a new interrupt handler disconnects the old one. Installed handlers are responsible for processing, enabling and clearing the interrupt. Note that interrupts may have been left in any state by the previous code.

The IS_CODE and IS_DATA pointers of the Interrupt structure will
be copied into a private place by Exec.  A pointer to the previously
installed Interrupt structure is returned.

When the system calls the specified interrupt code, the registers are
setup as follows:

    D0 - scratch
    D1 - scratch (on entry: active
          interrupts -> equals INTENA & INTREQ)

    A0 - scratch (on entry: pointer to base of custom chips
          for fast indexing)
    A1 - scratch (on entry: Interrupt's IS_DATA pointer)

    A5 - jump vector register (scratch on call)
    A6 - Exec library base pointer (scratch on call)

    all other registers must be preserved

Inputs

intNum - the Paula interrupt bit number (0..14). Only non-chained interrupts should be set. Use AddIntServer() for server chains. interrupt - a pointer to an Interrupt structure containing the handler's entry point and data segment pointer. A NULL interrupt pointer will remove the current interrupt and set illegal values for IS_CODE and IS_DATA.

     By convention, the LN_NAME of the interrupt structure must
     point a descriptive string so that other users may
     identify who currently has control of the interrupt.

Results

A pointer to the prior interrupt structure which had control of this interrupt.

See also

AddIntServer()


SetSignal()

SetSignal -- define the state of this task's signals

Synopsis

oldSignals = SetSignal(newSignals, signalMask) D0 D0 D1

ULONG SetSignal(ULONG,ULONG);

Function

This function can query or modify the state of the current task's received signal mask. Setting the state of signals is considered dangerous. Reading the state of signals is safe.

Inputs

newSignals - the new values for the signals specified in signalSet. signalMask - the set of signals to be affected.

Results

oldSignals - the prior values for all signals

Examples

Get the current state of all signals: SetSignal(0L, 0L); Clear the CTRL-C signal: SetSignal(0L, SIGBREAKF_CTRL_C);

Check if the CTRL-C signal was pressed:

    #include <dos/dos.h>

    /* Check & clear CTRL_C signal */
    if (SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
        printf("CTRL-C pressed!\n");

See also

Signal()


SetSR()

SetSR -- get and/or set processor status register

Synopsis

oldSR = SetSR(newSR, mask) D0 D0 D1

ULONG SetSR(ULONG, ULONG);

Function

This function provides a means of modifying the CPU status register in a "safe" way (well, how safe can a function like this be anyway?). This function will only affect the status register bits specified in the mask parameter. The prior content of the entire status register is returned.

Inputs

newSR - new values for bits specified in the mask. All other bits are not effected. mask - bits to be changed

Results

oldSR - the entire status register before new bits

Examples

To get the current SR: currentSR = SetSR(0,0); To change the processor interrupt level to 3: oldSR = SetSR($0300,$0700); Set processor interrupts back to prior level: SetSR(oldSR,$0700);


SetTaskPri()

SetTaskPri -- get and set the priority of a task

Synopsis

oldPriority = SetTaskPri(task, priority) D0-0:8 A1 D0-0:8

BYTE SetTaskPri(Task*,BYTE);

Function

This function changes the priority of a task regardless of its state. The old priority of the task is returned. A reschedule is performed, and a context switch may result.

To change the priority of the currently running task, pass the
result of FindTask(0); as the task pointer.

Inputs

task - task to be affected priority - the new priority for the task

Results

oldPriority - the tasks previous priority


Signal()

Signal -- signal a task

Synopsis

Signal(task, signals) A1 D0

void Signal(Task*,ULONG);

Function

This function signals a task with the given signals. If the task is currently waiting for one or more of these signals, it will be made ready and a reschedule will occur. If the task is not waiting for any of these signals, the signals will be posted to the task for possible later use. A signal may be sent to a task regardless of whether it is running, ready, or waiting.

This function is considered "low level".  Its main purpose is to
support multiple higher level functions like PutMsg.

This function is safe to call from interrupts.

INPUT task - the task to be signalled signals - the signals to be sent

See also

SetSignal()


StackSwap()

StackSwap - EXEC supported method of replacing task's stack (V37)

Synopsis

StackSwap(newStack) A0

VOID StackSwap(StackSwapStruct*);

Function

This function will, in an EXEC supported manner, swap the stack of your task with the given values in StackSwap. The StackSwapStruct structure will then contain the values of the old stack such that the old stack can be restored. This function is new in V37.

Inputs

newStack - A structure that contains the values for the new upper and lower stack bounds and the new stack pointer. This structure will have its values replaced by those in you task such that you can restore the stack later.

Results

newStack - The structure will now contain the old stack. This means that StackSwap(foo); StackSwap(foo); will effectively do nothing.

Note

If you do a stack swap, only the new stack is set up. This function does not copy the stack or do anything else other than set up the new stack for the task. It is generally required that you restore your stack before exiting.

See also

AddTask(), RemTask()


SumKickData()

SumKickData -- compute the checksum for the Kickstart delta list

Synopsis

checksum = SumKickData() D0

ULONG SumKickData(void);

Function

The Amiga system has some ROM (or Kickstart) resident code that provides the basic functions for the machine. This code is unchangeable by the system software. This function is part of a support system to modify parts of the ROM.

The ROM code is linked together at run time via ROMTags (also known
as Resident structures, defined in exec/resident.h).  These tags tell
Exec's low level boot code what subsystems exist in which regions of
memory.  The current list of ROMTags is contained in the ResModules
field of ExecBase.  By default this list contains any ROMTags found
in the address ranges $F80000-$FFFFFF and $F00000-$F7FFFF.

There is also a facility to selectively add or replace modules to the
ROMTag list.  These modules can exist in RAM, and the memory they
occupy will be deleted from the memory free list during the boot
process.  SumKickData() plays an important role in this run-time
modification of the ROMTag array.

Three variables in ExecBase are used in changing the ROMTag array:
KickMemPtr, KickTagPtr, and KickCheckSum. KickMemPtr points to a
linked list of MemEntry structures. The memory that these MemEntry
structures reference will be allocated (via AllocAbs) at boot time.
The MemEntry structure itself must also be in the list.

KickTagPtr points to a long-word array of the same format as the
ResModules array.  The array has a series of pointers to ROMTag
structures.  The array is either NULL terminated, or will have an
entry with the most significant bit (bit 31) set.  The most
significant bit being set says that this is a link to another
long-word array of ROMTag entries.  This new array's address can be
found by clearing bit 31.

KickCheckSum has the result of SumKickData().  It is the checksum of
both the KickMemPtr structure and the KickTagPtr arrays.  If the
checksum does not compute correctly then both KickMemPtr and
KickTagPtr will be ignored.

If all the memory referenced by KickMemPtr can't be allocated then
KickTagPtr will be ignored.

There is one more important caveat about adding ROMTags. All this
ROMTag magic is run very early on in the system -- before expansion
memory is added to the system. Therefore any memory in this
additional ROMTag area must be addressable at this time. This means
that your ROMTag code, MemEntry structures, and resident arrays
cannot be in expansion memory.  There are two regions of memory that
are acceptable:  one is chip memory, and the other is "Ranger" memory
(memory in the range between $C00000-$D80000).

Remember that changing an existing ROMTag entry falls into the
"heavy magic" category -- be very careful when doing it.  The odd are
that you will blow yourself out of the water.

Results

Value to be stuffed into ExecBase->KickCheckSum.

Note

SumKickData was introduced in the 1.2 release

See also

InitResident(), FindResident()


SumLibrary()

SumLibrary -- compute and check the checksum on a library

Synopsis

SumLibrary(library) A1

void SumLibrary(Library*);

Function

SumLibrary computes a new checksum on a library. It can also be used to check an old checksum. If an old checksum does not match, and the library has not been marked as changed, then the system will call Alert().

This call could also be periodically made by some future
system-checking task.

Inputs

library - a pointer to the library to be changed

Note

An alert will occur if the checksum fails.

See also

SetFunction()


SuperState()

SuperState -- enter supervisor state with user stack

Synopsis

oldSysStack = SuperState() D0

APTR SuperState(void);

Function

Enter supervisor mode while running on the user's stack. The user still has access to user stack variables. Be careful though, the user stack must be large enough to accommodate space for all interrupt data -- this includes all possible nesting of interrupts. This function does nothing when called from supervisor state.

Results

oldSysStack - system stack pointer; save this. It will come in handy when you return to user state. If the system is already in supervisor mode, oldSysStack is zero.

See also

Supervisor()


Supervisor()

Supervisor -- trap to a short supervisor mode function

Synopsis

result = Supervisor(userFunc) Rx A5

ULONG Supervisor(void *);

Function

Allow a normal user-mode program to execute a short assembly language function in the supervisor mode of the processor. Supervisor() does not modify or save registers; the user function has full access to the register set. All rules that apply to interrupt code must be followed. In addition, no system calls are permitted. The function must end with an RTE instruction.

Inputs

userFunc - A pointer to a short assembly language function ending in RTE. The function has full access to the register set.

Results

result - Whatever values the userFunc left in the registers.

Example

;Obtain the Exception Vector base. 68010 or greater only! MOVECtrap: movec.l VBR,d0 ;$4e7a,$0801 rte

See also

SuperState(), UserState()


TypeOfMem()

TypeOfMem -- determine attributes of a given memory address

Synopsis

attributes = TypeOfMem(address) D0 A1

ULONG TypeOfMem(void *);

Function

Given a RAM memory address, search the system memory lists and return its memory attributes. The memory attributes are similar to those specified when the memory was first allocated: (eg. MEMF_CHIP and MEMF_FAST).

This function is usually used to determine if a particular block of
memory is within CHIP space.

If the address is not in known-space, a zero will be returned.
(Anything that is not RAM, like the ROM or expansion area, will
return zero.  Also the first few bytes of a memory area are used up
by the MemHeader.)

INPUT address - a memory address

Results

attributes - a long word of memory attribute flags. If the address is not in known RAM, zero is returned.

See also

AllocMem()


UserState()

UserState -- return to user state with user stack

Synopsis

UserState(sysStack) D0

void UserState(APTR);

Function

Return to user state with user stack, from supervisor state with user stack. This function is normally used in conjunction with the SuperState function above.

This function must not be called from the user state.

INPUT sysStack - supervisor stack pointer

Bugs

This function is broken in V33/34 Kickstart. Fixed in V1.31 setpatch.

See also

Supervisor()


Vacate()

Vacate -- release a bitMessage from Procure() (V39)

Synopsis

Vacate(semaphore, bidMessage) A0 A1

void Vacate(SignalSemaphore*,SemaphoreMessage*);

Function

This function can be used to release a semaphore obtained via Procure(). However, the main purpose for this call is to be able to remove a bid for a semaphore that has not yet responded. This is required when a Procure() was issued and the program no longer needs to get the semaphore and wishes to cancel the Procure() request. The canceled request will be replied with the ssm_Semaphore field set to NULL. If you own the semaphore, the message was already replied and only the ssm_Semaphore field will be cleared.

NOTE:  Pre-V39, Procure() and Vacate() did not work correctly.
They also did not operate on SignalSemaphore semaphores.
Old (and broken) MessageSemaphore use as of V39 will no longer work.

INPUT semaphore - The SignalSemaphore that you wish to Vacate() bidMessage- The SemaphoreMessage that you wish to abort. The message's ssm_Semaphore field will be cleared. The message will be replied if it is still on the waiting list. If it is not on the waiting list, it is assumed that the semaphore is owned and it will be released.

Bugs

Before V39, Procure() and Vacate() used a different semaphore system that was very broken. This new system is only available as of V39 even though the LVOs are the same.

See also

ObtainSemaphoreShared(), InitSemaphore(), ReleaseSemaphore(), AttemptSemaphore(), ObtainSemaphoreList(), Procure(), ObtainSemaphore()


Wait()

Wait -- wait for one or more signals

Synopsis

signals = Wait(signalSet) D0 D0

ULONG Wait(ULONG);

Function

This function will cause the current task to suspend waiting for one or more signals. When one or more of the specified signals occurs, the task will return to the ready state, and those signals will be cleared.

If a signal occurred prior to calling Wait(), the wait condition will
be immediately satisfied, and the task will continue to run without
delay.

CAUTION This function cannot be called while in supervisor mode or interrupts! This function will break the action of a Forbid() or Disable() call.

INPUT signalSet - The set of signals for which to wait. Each bit represents a particular signal.

Results

signals - the set of signals that were active


WaitIO()

WaitIO -- wait for completion of an I/O request

Synopsis

error = WaitIO(iORequest) D0 A1

BYTE WaitIO(IORequest*);

Function

This function waits for the specified I/O request to complete, then removes it from the replyport. If the I/O has already completed, this function will return immediately.

This function should be used with care, as it does not return until
the I/O request completes; if the I/O never completes, this
function will never return, and your task will hang.  If this
situation is a possibility, it is safer to use the Wait() function.
Wait() will return return when any of a specified set of signal is
received.  This is how I/O timeouts can be properly handled.

Inputs

iORequest - pointer to an I/O request block

Results

error - zero if successful, else an error is returned (a sign extended copy of io_Error).

See also

DoIO(), SendIO(), CheckIO(), AbortIO()


WaitPort()

WaitPort -- wait for a given port to be non-empty

Synopsis

message = WaitPort(port) D0 A0

Message*WaitPort(MsgPort*);

Function

This function waits for the given port to become non-empty. If necessary, the Wait() function will be called to wait for the port signal. If a message is already present at the port, this function will return immediately. The return value is always a pointer to the first message queued (but it is not removed from the queue).

CAUTION More than one message may be at the port when this returns. It is proper to call the GetMsg() function in a loop until all messages have been handled, then wait for more to arrive.

To wait for more than one port, combine the signal bits from each
port into one call to the Wait() function, then use a GetMsg() loop
to collect any and all messages.  It is possible to get a signal
for a port WITHOUT a message showing up.  Plan for this.

WaitPort() can only be used with message ports whose mp_Flags
port arrival action is PA_SIGNAL and if the calling task is the
same as given in the mp_SigTask field.

INPUT port - a pointer to the message port

See also

GetMsg()