AROS Application Development Manual -- The Exec Library
Varování
This document is not finished! It is highly likely that many parts are out-of-date, contain incorrect information, or are simply missing altogether. If you want to help rectify this, please contact us.
Obsah
Types
In exec/types.h the following short-cuts are typedef'd. They are used often in AROS, so you should nearly always include exec/types.h.
- APTR
- A generic pointer for multiple purposes.
- STRPTR
- A pointer to a null-terminated string.
- UQUAD
- Unsigned 64-bit integer variable.
- QUAD
- Signed 64-bit integer variable.
- DOUBLE
- 64bit IEEE floating-point variable.
- ULONG
- Unsigned 32-bit integer variable (longword).
- LONG
- Signed 32-bit integer variable (longword).
- FLOAT
- 32 bit IEEE floating-point variable.
- UWORD
- Unsigned 16-bit integer variable (word).
- WORD
- Signed 16-bit integer variable (word).
- UBYTE
- Unsigned 8-bit integer variable (byte).
- BYTE
- Signed 8-bit integer variable (byte).
- BOOL
- Boolean variable, TRUE and FALSE are also defined in exec/types.h.
- VOID
- Void.
IPTR
There is another important typedef, IPTR. It is really important in AROS, as it the only way to declare a field that can contain both an integer and a pointer.
Poznámka
AmigaOS does not know this typedef. If you are porting a program from AmigaOS to AROS, you have to search your source for occurrences of ULONG that can also contain pointers, and change them into IPTR. If you don't do this, your program will not work on systems which have pointers with more than 32 bits (for example DEC Alphas that have 64-bit pointers).
BPTR
The so-called BPTR`s were always a problem in AmigaOS and this problem was inherited by AROS. In binary-compatible AROS versions a `BPTR is in fact the fourth of the real pointer. If, for example, a pointer points to address $80000 the BPTR pointing to the same address would contain $20000. On systems without binary-compatibility, a BPTR is equal to an APTR.
To convert between a normal pointer and a BPTR use the macros:
#include <dos/bptr.h> APTR BADDR( BPTR bptr ); BPTR MKBADDR( APTR ptr );
There also exists something called BSTR which is a special kind of string. We will not discuss this here, though, because it is used only very rarely.
History
When the development of the Amiga started, it was designed as a pure module-based games-console. As such, it didn't need any means of file system handling. The OS was created without a file system in mind. But Commodore, who bought the Amiga, wanted a full-fletched home-computer instead of another games-platform. So, a short time before the Amiga's initial presentation, a file system was needed. Instead of wasting time in developing a custom one, the file system of an operating system called TRIPOS was ported to the Amiga. Unfortunately TRIPOS was written in BCPL, a programming language with a quite eccentric pointer handling. This pointer handling was inherited by the AmigaDOS and later by AROS (even though later versions of AmigaOS and also AROS are written in C).
Exec lists and memory management
Exec lists
AROS implements a system of linked lists, so-called exec lists. A linked-list consists of a number of nodes that link to each other. Two types of nodes are defined in exec/nodes.h:
- struct MinNode
- is the basic node. You don't need to know about its structure, since every possible action on them is handled by some library function.
- struct Node
extends the simple struct MinNode. It provides some additional fields:
- ln_Name
- Each Node contains a pointer to a string, describing that node.
- ln_Type
- A list of types is defined in exec/nodes.h.
- ln_Pri
- A priority, used for sorting the list.
Both structures can be embedded into other structures. For example, struct Library (defined in exec/libraries.h) contains a struct Node at the beginning. This way all libraries can be contained in a list. The field ln_Name points to the name of the library, ln_Type is set to NT_LIBRARY to show that this node is a library and ln_Pri reflects the importance of a library.
Of course, we need node containers: lists. These are defined in exec/lists.h. Like nodes, we have two different kind of lists:
- struct MinList
- is the minimal list. You do not need to know about its members; look at it as a black-box.
- struct List
- contains an additional field lh_Type, which corresponds to ln_Type of struct Node.
MinList's take MinNode's as members, while List's use Node's; they are not interchangeable. While it's technically possible to use`Node`'s in MinList's, you loose all their advantages.
FIXME: Macros
List Manipulating Functions
exec.library and the link-library amiga.lib contain some functions for manipulating exec lists. Before a list can be used, it must be initialized. This can be done using this amiga.lib function:
#include <proto/alib.h> void NewList( struct List *list );
Nodes can be added to lists with these exec.library functions:
#include <proto/exec.h> void AddHead( struct List *list, struct Node *node ); void AddTail( struct List *list, struct Node *node ); void Enqueue( struct List *list, struct Node *node ); void Insert( struct List *list, struct Node *node, struct Node *pred );
With AddHead() and AddTail() node is inserted at the beginning or the end of list respectively. Enqueue() inserts node according to its ln_Pri field. A node can be inserted after another by using Insert(). A pointer to the node to insert node after, must be provided as pred.
Nodes can be removed using these exec.library functions:
#include <proto/exec.h> void Remove( struct Node *node ); struct Node *RemHead( struct List *list ); struct Node *RemTail( struct List *list );
While RemHead() and RemTail() remove the first or last node of a list respectively and return a pointer to it, Remove() removes node from whatever list it is in.
Of course, apart from Enqueue(), all list functions can process struct MinList and struct MinNode's, as well.
A list can be searched for a named node, using:
#include <proto/exec.h> struct Node *FindName( struct List *list, STRPTR name );
name is a pointer to a string that is to be compared with the ln_Name of the nodes in list. The comparison is case-sensitive! If name matches any ln_Name field, a pointer to the corresponding node is returned. If no field matches, NULL is returned.
Poznámka
A list used with FindName() must not contain any struct MinList entries. If it does, memory could get corrupted!
In the following example, we create a list, add three nodes to it, search a named node and then remove it:
#include <proto/alib.h> #include <proto/exec.h> #include <exec/types.h> #include <exec/lists.h> #include <exec/nodes.h> #include <dos/dos.h> /* For RETURN_OK */ struct List list; /* Our nodes */ struct Node node1 = { NULL, NULL, /* No predecessor and successor, yet */ NT_UNKNOWN, 0, /* Unknown type, priority ignored */ "First node" /* Name of the node */ }; struct Node node2 = { NULL, NULL, NT_UNKNOWN, 0, "Second node" }; struct Node node3 = { NULL, NULL, NT_UNKNOWN, 0, "Third node" }; int main(int argc, char *argv[]) { struct Node *node; /* Prepare the list for use. */ NewList(&list); /* Add the first two nodes at the end of the list. */ AddTail(&list, &node1); AddTail(&list, &node2); /* Insert the third node after the first node. */ Insert(&list, &node3, &node1); /* Find the second node */ node = FindName(&list, "Second node"); /* If the node was found (which is always the case in this example), remove it. */ if (node) Remove(&node); return RETURN_OK; }
Macros
AROS defines a couple of macros in various header files. All macros cast their parameters to the correct type, so you must provide a valid input but can safe the casts (macros are meant to make life simpler).
- NEWLIST(list)
Compatible: Yes Location: exec/lists.h Initializes a list. You should not use any list before you have initialized it.
- GetHead(list)
Compatible: Yes Location: exec/lists.h Returns a pointer to the first node of a list, or NULL if the list is empty.
- GetTail(list)
Compatible: Yes Location: exec/lists.h Returns a pointer to the last node of a list, or NULL if the list is empty.
- GetSucc(node)
Compatible: Yes Location: exec/lists.h Returns a pointer to the next node of a list, or NULL if there is none.
- GetPred(list)
Compatible: Yes Location: exec/lists.h Returns a pointer to the previous node of a list, or NULL if there is none.
- ForeachNode(list,node)
Compatible: Yes Location: exec/lists.h Iterates through a list. A block of code must follow this macro. The block doesn't get executed if the list is empty. When the list terminates node doesn't contain NULL but node->ln_Succ will be NULL. This macro can't be used if you want to delete the nodes in the list (i.e.. you must not call Remove() inside the block of code following the macro). Use ForeachNodeSafe() if you have to delete nodes.
Example:
/* Iterate through a list with complete nodes and print their names */ t = 1; ForeachNode(list,node) { if (node->ln_Name) { printf ("Node %d: %s\n", t++, node->ln_Name); if (!strcmp (node->ln_Name, "end")) break; } } if (node->ln_Succ) printf ("Not all nodes have been processed\n"); else printf ("The list doesn't contain a node with the name \"end\"\n");
- ForeachNodeSafe(list,node,tmpNode)
Compatible: Yes Location: exec/lists.h Iterates through a list. A block of code must follow this macro. The block doesn't get executed if the list is empty. When the list terminates node doesn't contain NULL but node->ln_Succ will be NULL. This macro can be used with code that deletes nodes in the list.
- SetNodeName(node,name)
Compatible: Yes Location: exec/lists.h Sets a new name for a node. The name is not copied, the macro will just make ln_Name point to name. The macro casts node to struct Node * so you better make sure that node is a full featured node.
- GetNodeName(node)
Compatible: Yes Location: exec/lists.h Return the current name of a node. The macro casts node to struct Node * so you better make sure that node is a full featured node.
- ListLength(list,count)
Compatible: Yes Location: exec/lists.h This puts the number of nodes in list into count.
Memory Handling
You need memory for nearly everything in a program. Many things can be done using the stack, but often you need larger chunks of memory or don't want to use the stack for some reason. In these cases you have to allocate memory by yourself. The exec.library provides several methods for allocating memory. The two most important functions are:
#include <proto/exec.h> APTR AllocMem( ULONG size, ULONG flags ); APTR AllocVec( ULONG size, ULONG flags );
Both functions return a pointer to a memory area of the requested size provided as argument. If not enough memory was available, NULL is returned, instead. You must check for this condition, before using the memory. If the memory was successfully allocated, you can do with it whatever you want to.
You can provide additional flags to get a special kind of memory. The following flags are defined in exec/memory.h:
- MEMF_CLEAR
- The allocated memory area is initialized with zeros.
- MEMF_LOCAL
- Get memory that will not be flushed, if the computer is reset.
- MEMF_CHIP
- Get memory that is accessible by graphics and sound chips. Some functions require this type of memory.
- MEMF_FAST
- Get memory that is not accessible by graphics and sound chips. You should normally not set this flag! It is needed only for some very esoteric functions. Many systems don't have this kind of memory.
- MEMF_PUBLIC
- This flag must be set, if the memory you allocate is to be accessible by other tasks. If you do not set it, the allocated memory is private to your task. This issue will be discussed in detail in the chapter about .. FIXME:: inter-task communication.
- MEMF_REVERSE
- If this flag is set, the order of the search for empty memory blocks is reversed. Blocks that are at the end of the list of empty memory will be found first.
- MEMF_NO_EXPUNGE
- Normally, if not enough free memory of the requested size is found, AROS tries to free unused memory, for example by flushing unused libraries out of the memory. If this flag is set, this behavior is turned off.
Memory allocated with these functions must be freed after use with one of the following functions. Note well that you should never access memory after it has been freed.:
#include <proto/exec.h> void FreeMem( APTR memory, ULONG size ); void FreeVec( APTR memory );
Of course, FreeMem() must be used for memory allocated with AllocMem() and FreeVec() for memory allocated with AllocVec(). The synopsis for these two functions shows the difference between AllocMem() and AllocVec(): AllocVec() remembers the size of the chunk of memory it allocated. So, if you use AllocVec(), you don't have to store the requested size, while you have to if you use AllocMem().
Allocating Multiple Regions of Memory at once
Sometimes you may want to make multiple memory allocations at once. The usual way to do this is calling AllocVec() with the size of all memory-blocks added together and then making pointers relative to the returned pointer. But what do you do, if you need memory of different kinds, with different MEMF_ flags set? You could make multiple allocations or simply use this function:
#include <proto/exec.h> struct MemList *AllocEntry( struct MemList *oldlist );
As you will have noticed, AllocEntry() uses a pointer to a struct MemList as only argument and as result. We find the definition of this structure in exec/memory.h:
struct MemEntry { union { ULONG meu_Reqs; APTR meu_Addr; } me_Un; ULONG me_Length; }; struct MemList { struct Node ml_Node; UWORD ml_NumEntries; struct MemEntry ml_ME[1]; };
The array ml_ME of struct MemList has a variable number of elements. The number of its elements is set in ml_NumEntries. The struct MemEntry describes one memory-entry. Stored are its size (me_Length), its requirements (i.e. the MEMF_, set in me_Un.meu_Reqs) and possibly a pointer to the memory-block (me_Un.meu_Addr). The struct MemList, you pass in as oldlist, must have set the field ml_NumEntries to the actual number of struct MemEntry's contained in ml_ME. The struct MemEntry's must have set the fields me_Length and me_Un.meu_Reqs. The other fields are ignored. The function returns a pointer to a copy of the struct MemEntry, passed in as oldlist, with all the relevant fields set (especially me_Un.meu_Addr). An error is indicated by setting the most significant bit of the pointer returned. So you always have to check it, before using the pointer returned. Memory allocated with AllocEntry() too must be freed using FreeMem().
Memory Pools
AROS manages several so-called memory-pools. Each memory-pool contains a list of memory-areas. Of these, the most important memory-pool is the pool that contains all free memory in the system. But you also can create memory-pools yourself. This has some advantages:
- Every time you allocate some memory, the memory in the system becomes more fragmented. This fragmentation causes the available memory chunks to become smaller. This way larger allocations may fail. To prevent this problem, memory-pools were introduced. Instead of allocating many small chunks of memory, the pool-management routines allocate large chunks and then return small chunks out of it, when memory-requests are made.
- Private memory-pools have the ability to keep track of all the allocations you made so that all memory in a pool can be freed with one simple function-call (but you can also free memory individually).
Before a memory-pool can be used, it must be created. This is done with the function:
#include <proto/exec.h> APTR CreatePool( ULONG flags, ULONG puddleSize, ULONG threshSize );
The flags specifies the type of memory you want to get from the AllocPooled() function . All MEMF_ definitions as described above are allowed here.
The puddleSize is the size of the chunks of memory that are allocated by the pool functions. Usually a size about ten times bigger than the average memory-size, you need to allocate, is a good guess. But on the other hand the puddleSize should not be too large. Normally you should limit it to about 50kb. Note well, though, that these are only suggestions and no real limitations.
Finally, the threshSize specifies how large the requested chunk of memory must be to be allocated automatically, rather than after checking the pool. If, for example, the threshSize is set to 25kb and you want to allocate a piece of memory with the size of 30kb, the internal lists of chunks of that memory-pool is not searched at all. Instead, the memory is allocated directly. If the memory to be allocated was only 20kb, first the chunk-list would have been searched for a piece of free memory of that size. Of course, the threshSize shouldn't be larger than the puddleSize and it should not be too small, either. Half the puddleSize is a good guess here.
CreatePool() returns a private pointer to a pool-structure that must be saved for further use. NULL is returned if no memory for the pool-structure was available. You have to check for this condition.
After use, all memory-pools must be destroyed by calling:
#include <proto/exec.h> void DeletePool( APTR pool );
This function deletes the pool passed in. Additionally all memory that was allocated in this pool is freed. This way, you don't need to remember every single piece of memory, you allocated in a pool. Just call DeletePool() at the end. Note that you should be careful not to access pooled memory after its pool was deleted!
If you want to allocate memory from a pool, you need to call:
#include <proto/exec.h> void *AllocPooled( APTR pool, ULONG size );
Besides the pool to allocate memory from, the size of the memory to be allocated must be passed in. Returned is a pointer to a block of memory of the requested size or NULL to indicate that not enough memory was available.
Memory allocated with AllocPooled() can be freed by either destroying the whole pool with DeletePool() or individually by calling:
#include <proto/exec.h> void FreePooled( APTR pool, void *memory, ULONG size );
This function frees exactly one piece of memory that was previously allocated with AllocPooled(). The pointer to the memory pointer, returned by AllocPooled(), its size and the pool it is in, have to be supplied as arguments.
Poznámka
You may ask yourself: "If DeletePool() deletes all the memory of a pool, why should I ever use FreePooled()?" The answer is easy: to save memory. Normally it's good style to free memory as soon as you don't need it any more. But sometimes it is easier just to free a memory-pool after a bunch of allocations. Nevertheless, you should not use this feature if you are not sure when the memory-pool will be deleted. Imagine a program like this (do not try to compile it; it won't):
#define <exec/types.h> #define <exec/memory.h> #define <dos/dos.h> int main(int argc, char *argv[]) { APTR pool; APTR mem; /* Create our memory pool and test, if it was successful. */ pool = CreatePool(MEMF_ANY, 50*1024, 25*1024); if (pool) { /* Just a dummy function. Image that this function will open a window, with two buttons "Do Action" and "Quit". */ open_our_window(); for(;;) { /* Another dummy function that returns one of the definitions below. */ switch(get_action()) { /* This is returned, if the button "Do Action" was released. */ case DOACTION: mem = AllocPooled(pool, 10*1024); if (mem) { /* Another dummy function that uses our memory. */ silly_function(mem); } break; /* This is returned, if the button "Quit" was released. */ case QUIT: return RETURN_OK; } } /* Close the window, we have opened above. */ close_our_window(); /* Delete our pool. */ DeletePool(pool); } }
Each time the button Do Action is released, some memory is allocated. This memory is freed at the end of the program, when DeletePool() is called. Of course, the longer the program is used, the more memory will be in use. That is why it would be much better to free the memory after use. This is done by replacing the part between case DOACTION: and case QUIT: by:
mem = AllocPooled(pool, 10*1024); if (mem) { silly_function(mem); FreePooled(pool, mem, 10*1024); } break;
Obsolete Memory Pool Functions
Memory-pools are managed with struct MemHeader's. If you have a pointer to such a structure, you may try to allocate some memory from its pool:
#include <proto/exec.h> void *Allocate( struct MemHeader *mh, ULONG size );
Apart from the pointer to the struct MemHeader passed in as mh, you have to supply the size of the memory-block you want to allocate. This function returns either a pointer to the first memory-block found or NULL if no matching block was found.
You must free every memory-block allocated with Allocate() with:
#include <proto/exec.h> void Deallocate( struct MemHeader *mh, APTR mem, ULONG size );
You have to pass the same mh and size to Deallocate() that you passed to Allocate() and additionally the pointer it returned.
intuition.library provides another way to handle memory pools with the functions AllocRemember() and FreeRemember(). Note, though, that these are obsolete. You should use the normal pool-functions of exec.library, instead.
Allocating a specific memory address
Under very rare circumstances you may need to allocate memory at a specific memory address. This performed by using:
#include <proto/exec.h> void *AllocAbs( ULONG size, APTR address );
This function tries to allocate size bytes at address. If this is successful, a pointer to the requested address is returned. If some memory of the requested block is already allocated or is not available in the system, NULL is returned, instead.
Varování
You should not write to the beginning of the memory-block! The beginning of the returned memory block will have been used by exec to store its node-data (the exact size is calculated by (2*sizeof (void *)) ). Therefore, this area will not be available to you. Either don't write there, or if there's memory before the address you need, request a slightly larger block, starting far enough before the intended start-address to make room for exec's data. Because of these obstacles, you should not use AllocAbs(), except in case you really need it.
Memory allocated with AllocAbs() must also be freed using FreeMem().
Querying memory size and available memory
To get the size of available memory, use the function:
#include <proto/exec.h> ULONG AvailMem( ULONG type );
The type parameter consists of some of the following flags (or-ed), as defined in exec/memory.h:
- MEMF_ANY
- Return the size of all free memory in the system.
- MEMF_CHIP
- Return the size of memory, which is accessible by graphics and sound chips.
- MEMF_FAST
- Return the size of memory that is not accessible by graphics and sound chips.
- MEMF_LARGEST
- Return only the largest block, instead of all memory of the type specified.
You may also specify other MEMF_ flags, however, they will simply be ignored.
Poznámka
Note well that the returned memory-size need not reflect the real size of the memory available, as in a multitasking system this may change at any moment, even while AvailMem() is being executed.
A program to list memory available in the system:
#include <stdio.h> #include <exec/memory.h> int main(int argc, char *argv[]) { printf("Total free memory: %h, largest block: %h\n", AvailMem(MEMF_ANY), AvailMem(MEMF_ANY|MEMF_LARGEST)); printf("Free chip memory: %h, largest block: %h\n", AvailMem(MEMF_CHIP), AvailMem(MEMF_CHIP|MEMF_LARGEST)); printf("Free fast memory: %h, largest block: %h\n", AvailMem(MEMF_FAST), AvailMem(MEMF_FAST|MEMF_LARGEST)); }
Adding memory to the system
This chapter is only of concern to you, if you want to write a hardware-driver for a piece of hardware which adds memory to the system. This exec function adds memory to the list of free memory in the system:
#include <proto/exec.h> void AddMemList ( ULONG size, ULONG type, LONG priority, APTR address, STRPTR name );
You have supply the address and the size of the memory to add. The type has to be set to at least one of the MEMF_ flags, which are defined in exec/memory.h:
- MEMF_FAST
- Your memory must not be accessed by graphics or sound chips.
- MEMF_CHIP
- Your memory is reachable for graphics and sound chips.
You can provide a priority with which your memory will be added to the memory list. The general rule is: The quicker your memory, the higher the priority should be. If you don't know, what to supply here, supply 0. Finally, you can provide a name, with which your memory can be identified by the system and its users. You may provide NULL instead of a name, but giving your memory a name is recommended.
Once your memory is added to the list of free memory, it can't be removed again.
Low memory situations
FIXME: AddMemHandler()/RemMemHandler()
AllocMem() | Allocate some memory |
FreeMem() | Free memory allocated by AllocMem() |
AllocVec() | Allocate block of memory and remember its size |
FreeVec() | Free memory allocated by AllocVec() |
AllocEntry() | Allocate a number of blocks |
NewAllocEntry() | Improved version of AllocEntry() |
FreeEntry() | Free AllocEntry()/NewAllocEntry() memory |
AddMemList() | Add memory to the public list of memory |
AllocAbs() | Allocate memory at a given address |
Allocate() | Allocate memory from a specific MemHeader |
Deallocate() | Free memory allocated by Allocate() |
AllocPooled() | Allocate memory in a pool |
FreePooled() | Free memory allocated by AllocPooled() |
AllocVecPooled() | Allocate pool memory and remember its size |
FreeVecPooled() | Free memory allocated by AllocVecPooled() |
CreatePool() | Create a memory pool |
DeletePool() | Delete a memory pool including all its memory |
AvailMem() | Indicate how much memory is available |
CopyMem() | Copy memory |
CopyMemQuick() | Copy aligned memory |
TypeOfMem() | Examine memory |
AddMemHandler() | Add a low memory handler |
RemMemHandler() | Remove a memory handler |
Lists
AddHead() | Add a node to the head of a list |
AddTail() | Add a node at the end of a list |
Enqueue() | Add a node into a sorted list |
FindName() | Search for a node by name |
Insert() | Insert a node into a list |
NEWLIST() | Initialize a list |
RemHead() | Remove the first node of a list |
RemTail() | Remove the last node of a list |
Remove() | Remove a node from a list |
Balanced Binary Search Trees
AVL_AddNode() | Add a new node to an AVL tree |
AVL_FindFirstNode() | Find the smallest node in an AVL tree |
AVL_FindLastNode() | Find the largest node in an AVL tree |
AVL_FindNextNodeByAddress() | Perform an in-order traversal to the next node |
AVL_FindNextNodeByKey() | Find the next node matching the key |
AVL_FindNode() | Find an entry in the AVL tree by key |
AVL_FindPrevNodeByAddress() | Inverse-order traversal to the previous node |
AVL_FindPrevNodeByKey() | Find the previous node matching the key |
AVL_RemNodeByAddress() | Remove a given node from the tree |
AVL_RemNodeByKey() | Find a node in the tree by key and remove it |
Signals
AllocSignal() | Allocate a signal |
FreeSignal() | Free a signal |
SetSignal() | Examine and/or modify the signals of a task |
Signal() | Send some signal to a given task |
Wait() | Wait for some signal |
WaitPort() | Wait for a message on a port |
Messages and Ports
AddPort() | Add a port to the public list of ports |
RemPort() | Removes a port from the list of public ports |
CreateMsgPort() | Create a new message port |
DeleteMsgPort() | Free a message port |
FindPort() | Search a port by name |
GetMsg() | Get a message from a message port |
PutMsg() | Send a message to a port |
ReplyMsg() | Reply a message |
Semaphores
AddSemaphore() | Add a semaphore to the public semaphore list |
AttemptSemaphore() | Try to lock a semaphore |
AttemptSemaphoreShared() | Try to lock a semaphore shared |
FindSemaphore() | Search a semaphore by name |
InitSemaphore() | Initialize a signal semaphore |
ObtainSemaphore() | Lock a semaphore |
ObtainSemaphoreList() | Lock all semaphores in a list at once |
ObtainSemaphoreShared() | Get a shared lock on a semaphore |
ReleaseSemaphore() | Release a semaphore |
ReleaseSemaphoreList() | Release all semaphores in a list |
RemSemaphore() | Remove a semaphore from public semaphores list |
Procure() | Try to lock a semaphore |
Vacate() | Release a lock obtained with Procure() |
Tasks
Task Handling
AddTask() | Add a task |
NewAddTask() | Add a task |
RemTask() | Remove a task |
CreateTask() | amiga.lib function for creation of tasks |
DeleteTask() | amiga.lib function for deletion of tasks |
AllocTrap() | Allocate a trap |
FreeTrap() | Free a trap |
FindTask() | Search a task by name |
Forbid() | Prevent tasks switches from taking place |
Permit() | Allow tasks switches to occur |
SetExcept() | Examine/modify signals causing an exception |
SetTaskPri() | Change the priority of a task |
StackSwap() | Swap the stack of a task |
CacheClearE() | Clear the caches with extended control |
CacheClearU() | Simple way of clearing the caches |
CacheControl() | Global control of the system caches |
CachePostDMA() | Do what is necessary for DMA |
CachePreDMA() | Do what is necessary for DMA |
GetCC() | Read the CPU condition codes in an easy way |
SetSR() | Modify the CPU status register |
SuperState() | Switch the processor into a higher plane |
Supervisor() | Execute some code in a privileged environment |
UserState() | Return to normal mode after changing things |
Switch() | Switch to the next available task |
ChildFree() | Free child task information on a dead child |
ChildOrphan() | Make any children of this task orphans |
ChildStatus() | Find out the status of a child task |
ChildWait() | Wait for a task to finish its processing |
Task Storage
An AROS-specific feature for tasks is that each Task gets an array of IPTRs that can be used for Task-specific data. It can, for example, be used by shared libraries to easily associate data with a task or by compilers to make a program pure.
Slots can be allocated with AllocTaskStorageSlot() and freed with FreeTaskStorageSlot(). After a slot has been allocated the data associated with the slot can be manipulated by accessing tc_UnionETask.tc_TaskStorage[slot] from a struct Task.
Generally, when a new task is run, the contents of all the slots of the parent Task are copied into the new task. This holds for AddTask(), NewAddTask() and CreateNewProc(). When RunCommand() is used, however, the parent TaskStorage is reused in the child; changes made in the child to TaskStorage will be visible in parent after the child has exited. If these default behavior is not acceptable, user code has to implement checks and override it.
Functions:
AllocTaskStorageSlot() | Allocate a TaskStorage slot |
FreeTaskStorageSlot() | Free a TaskStorage slot |
Devices
AddDevice() | Add a device to the public list of devices |
RemDevice() | Remove a device from public list of devices |
CreateIORequest() | Create an I/O request |
DeleteIORequest() | Free an I/O request |
OpenDevice() | Open a device |
CloseDevice() | Close a device |
DoIO() | Start an IO request and wait till it completes |
SendIO() | Start an asynchronous I/O request |
CheckIO() | Check if an I/O request is completed |
WaitIO() | Wait until IO request completes |
AbortIO() | Abort an I/O request |
BeginIO() | amiga.lib: Call a device's BeginIO() function |
CreateExtIO() | amiga.lib: Create extended IORequest structure |
DeleteExtIO() | amiga.lib: Free an I/O request |
Libraries
AddLibrary() | Add a library to the public list of libraries |
RemLibrary() | Remove a library from list of public libraries |
MakeLibrary() | Make a library ready for use |
OpenLibrary() | Open a library |
CloseLibrary() | Close a library |
SetFunction() | Patch a library or device function |
SumLibrary() | Build checksum for a library |
FindResident() | Search a resident module by name |
InitResident() | Build library / device from resident structure |
InitCode() | Initialize resident modules |
InitStruct() | Initialize a structure |
MakeFunctions() | Create the jump table for shared library/device |
Resources
AddResource() | Add a resource to the public list of resources |
RemResource() | Remove a resource from public resources list |
OpenResource() | Open a resource |
Interrupts
AddIntServer() | Add interrupt client to interrupt server chain |
RemIntServer() | Remove an interrupt handler |
Cause() | Cause a software interrupt |
Disable() | Stop interrupts from occurring |
Enable() | Allow interrupts to occur after Disable() |
SetIntVector() | Install an interrupt handler |
ObtainQuickVector() | Obtain and install a Quick Interrupt vector |
I/O
RawDoFmt() | Format a string |
VNewRawDoFmt() | Format a string (va_list) |
Alert() | Display an alert |
Miscellaneous
ColdReboot() | Reboot the computer |
Debug() | Start the internal debugger |
SumKickData() | Calculate the checksum for the kickstart |