This page is "http://www.cs.tut.fi/~albert/BOAR/exec.html".

exec.library functions


Section Index


Interrupts

void Disable( void );

Disables interrupts for this task. Interrupts should not be disabled for long periods of time. Wait() will break out of Disable state, but interrupts will be disabled again when the task resumes execution. Each call to Disable() will increase the interrupt disable count.

void Enable( void );

Will decrease interrupt disable count. When the count reaches zero, enables interrupts. Subsequent calls to Enable() do nothing, disable nesting count will remain zero.

void Forbid( void );

Will increase task switching disable count. Wait() will break out of Forbid state but task switching is disabled again when the task resumes execution. Basically Forbid() disables task switching. Use only if you can't use semaphores !

void Permit( void );

Will decrease task switching disable count. When the count reaches zero, switches are again enabled. Subsequent calls to Permit() do nothing.

void AddIntServer( long vector (D0), struct Interrupt *server (A0) );

Will add a global interrupt server to a given exception vector. All interrupt servers in the chain will be called in order. The interrupt server is called as:
	

is_Code( ULONG is_Data (D0), UWORD *StackFrame (A1) );

The parameters are both in registers and in stack for C-language handlers. StackFrame contains a longword with the exception number and then the 'normal' 68000 stack frame.

Private (task-specific) exception handler can be installed using tc_ExceptData and tc_ExceptCode. If there is no global handler installed for an exception, the task-specific handler is called. If there is no task-specific handler either (tc_ExceptCode = NULL), the task is suspended.

void RemIntServer( long vector (D0), struct Interrupt *server (A0) );

Will remove the specified interrupt server from the interrupt server chain. Remember that the source that generates interrupts for the handler must first be disabled.

void Cause( long vector (D0) );

Calls an interrupt server in supervisor mode. Will behave just like a real interrupt. If there is no global handler installed for that exception and no task-specific handler installed, the task will be suspended.

Cause() is used by the message passing system to implement message ports that create soft-interrupts whenever a message arrives.


Memory Allocation

void *AllocMem( ULONG size (D0), ULONG flags (D1) );

Allocates a block of memory of the requested size. Returns a pointer to the memory block, which is at least long word aligned. flags can be set to MEMF_CLEAR to initialize the allocated memory to all zeros.

The allocation method used is 'first fit'. The first block in the free memory list that is big enough is returned.

void FreeMem( void *block (A0), ULONG size (D0) );

Will free a block of memory. Size must be the size used in the corresponding allocation and block should be the value returned by the allocation.

If the block being freed is adjacent to other free memory blocks, they are merged.

ULONG AvailMem( ULONG flags (D0) );

Will return size of the free memory left. Due to free memory fragmentation it might be impossible to allocate all of it. The flag MEMF_LARGEST can be used to find out the size of the largest contiguous free block of memory.

void AllocRemember( struct List *memlist (A0), ULONG size (D0), ULONG flags(D1) );

Allocates a minimum of requested sized block of memory, and adds accounting information to the list specified (memlist) so that all allocated blocks in that list can be deallocated at the same time. AllocRemember() returns a pointer to the memory block, which is at least long word aligned. Size and flags are the same as for AllocMem().

NULL memlist causes the allocations to be added to the task's allocation list and the allocations will be automatically freed when the task exits if they haven't been freed earlier.

Because programs run from the shell are run synchronously in the same task/process context, it is not usually wise to use the task's memory list. Use your own list, NewList(memlist) before usage and use FreeRememberAll(memlist) at the end.

void FreeRemember( void *block (A0) );

Frees memory which was previously allocated by AllocRemember() . The memory is removed from the allocation list and is returned back to the system.

Do NOT use FreeRemember() on a memory block that is not allocated with AllocRemember()!

void FreeRememberAll( struct List *memlist (A0) );

Frees all allocations that have been associated to the memlist. After FreeRememberAll() the list will be empty and can be reused without NewList().

List Routines

The list header must be initialized (NewList()) before anything is added to the list.

A node can only exist in one list at a time. A node MUST be removed from the current list before adding it into another. Also, a node MUST NOT be removed if it isn't currently in a list.

void Insert( struct List *list (A0), struct Node *node (A1), struct Node *pred (A2) );

Adds the node after the pred node in the list. If pred is NULL, adds to the head of the list.

void AddHead( struct List *list (A0), struct Node *node (A1));

Adds the node to the head of the list.

void AddTail( struct List *list (A0), struct Node *node (A1) );

Adds the node to the tail of the list.

void Remove( struct Node *node (A1) );

Removes the node from the list it is in. DO NOT USE if the node is not in a list or you will trash memory!!

struct Node *RemHead( struct List *list (A0) );

Removes the first node from the list. Returns NULL if the list is empty.

struct Node *RemTail( struct List *list (A0) );

Removes the last node from the list. Returns NULL if the list is empty.

void Enqueue( struct List *list (A0), struct Node *node (A1) );

Adds the node to the list according to the ln_Pri field. Smaller number means lower priority. Higher priority nodes end up to the head of the list, but after all of those nodes with an equal priority. This also means that RemHead()/ Enqueue() will round-robin the nodes that have the highest priority.

struct Node *FindName( struct List *list (A0), UBYTE *name (A1) );

Locates a node in the list by name. If no node with the specified name is found, NULL is returned. DO NOT use if the ln_Name fields are not initialized !!

Remember that node names may not be unique. Because of the way FindName() operates, you can pass it a node structure also. You can use the following construct to find all entries in a list with a name.

	struct List *mylist;
	struct Node *node;

	node = (struct Node *)mylist;
	while((node = FindName((struct List *)node, name)))
	{
		/* Do something with the node. */
	}

void NewList( struct List *list (A0) );

Initializes the list header to the state of an empty list.

struct Node *HeadNode( struct List *list (A0) );

Returns the first node from a list or NULL if the list is empty.

struct Node *NextNode( struct Node *list (A0) );

Returns the next node or NULL if the node was the last one.

struct Node *TailNode( struct List *list (A0) );

Returns the last node from a list or NULL if the list is empty.

struct Node *PrevNode( struct Node *list (A0) );

Returns the next node or NULL if the node was the first one.


Task Manipulation

void AddTask( struct Task *task (A1), long InitialPC (D0), long FinalPC (D1) );

Adds a task to the system. Execution will start from InitialPC and when the task exits, execution will jump to FinalPC. If FinalPC is NULL, a default Expunge routine is used instead (recommended). Task structure should contain tc_StackSize and tc_Stack initialized. Other members of the structure are initialized by AddTask(). The new task gets its parent task's Task pointer as an argument.

struct Task *FindTask( char *name (A1) );

Will find a task by the name. If name is NULL, the task structure pointer of the current task will be returned. Returns NULL if no task matching the name is found.

Remember that task names are not unique and many tasks with the same name may be present in the task lists.

WORD SetTaskPri( struct Task *task (A0), WORD priority (D1) );

Set the priority of a task. The higher value, the better priority. This call will return the old priority. Actually priority is only a BYTE value. Priority of -128 is the lowest, 127 is the highest.

OBSERVE:
Currently the new priority will take effect the next time the task gets the CPU. This can be considered a misfeature, but because priority changes are not very often done to other tasks, this predictable delay was considered acceptable.

ULONG SetSignal( ULONG newsigs (D0), ULONG sigmask (D1) );

Will set and reset signals. Only signal bits set in the sigmask are changed. Newsigs contain new signal states for signals defined in the sigmask. The old state of the signals are returned.

SetSignal(0, 0) can be used to read the current signal state without affecting the signals.

ULONG Wait( ULONG mask (D0) );

Waits for any of the signals defined in mask. If none of the signals are not active, suspends the task until any of the signals in the mask have been received. This call will return the signals that caused the wakeup. If a signal defined in the mask is already set, no waiting is done. Signals defined in the mask are cleared before returning.

void Signal( struct Task *task (A0), ULONG sigmask (D0) );

Sends a signal or signals to a specified task. If the task is waiting for signals, it is awakened.

Signal() may be called from an interrupt.

ULONG AllocSignal( void );

Allocates a signal bit for the task. Will return the NUMBER of a bit. To get a signal mask, you have to do (1L<<bitnumber).

VOID FreeSignal( ULONG sigbitnum (D0) );

Frees a previously allocated signal bit. Uses the NUMBER of a bit. Parameter should be a bit number returned by the AllocSignal() call.

'Resident' programs

void AddProgram( struct Program *program (A1) );

Will add a program to the system. The program struct includes all information needed for relocation of the program. When a program is added to the system, multiple copies of it may be started. The memory allocated for the struct Program will become owned by the system, thus it must be allocated with AllocMem().

Programs added with AddProgram() can be loaded and relocated by the dos.library call ROMLoadSeg() .

struct Program *RemProgram( char *name (A1) );

Removes a program from the system. This call does not free the memory allocated for the program. The task that used the call becomes the owner of the data and should free the memory before exiting.

Ports, Messages, Devices

void AddPort( struct MsgPort *port (A1) );

Adds a public port to the system. The port should be initialized correctly and NOT be a public port already. See CreatePort().

void RemPort( struct MsgPort *port (A1) );

Removes a public port from the system. Use this call ONLY if the port IS a public port. See DeletePort().

OBSERVE:
It is not safe to remove a public port, because there is no record of the tasks holding a reference to the port. A semi-safe solution is to 1) remove the port from the public port list 2) wait some time for any messages to the port and only if no messages arrive, 3) delete the port. This assumes that if a task gets a reference to a public port, it supposedly will use that reference in the near future to send a message into that port.

If you need public ports that may be safely removed, use public semaphores, because they have reference counts.

struct MsgPort *CreatePort( char *name (A1) );

Allocates and initializes a message port. If name is not NULL, the port is added to the system public port list. If the name is NULL, the port becomes private and can later be added to the public port list if so desired. (In this case mp_Node.ln_Name MUST be initialized before AddPort() is called.)

void DeletePort( struct MsgPort *port (A1) );

Frees the message port created by CreatePort(). If the port is a public port, it is also removed from the system list.

Remember that removing a public port is not totally safe. See the description under RemPort().

struct MsgPort *FindPort( char *name (A1) );

Searches the port list for the specified port name. If the port is not found, NULL is returned.

Remember that port names are not unique.

void WaitPort( struct MsgPort *port (A0) );

Waits until there is a message in the port. Does NOT remove the message from the port. Use GetMsg() to get the message. If there already is a message waiting, no waiting is done.

void PutMsg( struct MsgPort *port (A0), struct Message *message (A1) );

Puts a message to the specified message port. After this call the message becomes the property of the receiver and should not be tampered with until it is received back through the replyport. mn_Node.ln_Type becomes NT_MESSAGE.

One-way communication is also possible. In this case the receiver does not reply to the message and must free or reuse the message received. This is only possible between tasks that are written like this.

struct Message *GetMsg( struct MsgPort *port (A0) );

Gets a message from the message port. If no messages are waiting, returns NULL.

Remember that several messages may have been arrived at the message port and you only get one signal. Use while() to process all the messages before waiting again. If you use WaitPort(), it takes care of this for you (checks the port before waiting). Also, special care must be taken to ensure that the message port is empty before exiting.

void ReplyMsg( struct Message *message (A1) );

Will return a message to it's reply port. mn_Node.ln_Type becomes NT_REPLYMSG.

Limitation:
The ReplyPort should never be a softinterrupt-port. (But you can't create one with CreatePort() anyway:-)

void SendTimerReq( struct TimerReq *request (A1) );

Sends a timer request to the system.

void AddDevice( struct Device *device (A1) );

Adds a device to the system. Device structure should be initialized and be ready to accept Open() calls.

struct Device *RemDevice( struct Device *device (A1) );

Removes a device from the system. If the device is opened by anyone, the call returns NULL.

LONG OpenDevice( char *name (A1), ULONG unit (D0), struct StdIOReq *req (A0), ULONG flags (D1));

Opens a specified device. Struct StdIOReq is filled in by the OpenDevice() call and the internal device Open() call. The device itself maintains lib_OpenCnt. If the open was successfull, 0 is returned.

unit, req and flags are pushed into stack for C-language Open() handlers.

void CloseDevice( struct StdIOReq *req (A1) );

Closes the device opened by OpenDevice() (makes an internal call to the device's Close() entry). Device itself maintains lib_OpenCnt.

req is pushed into stack for C-language Close() handlers.

LONG DoIO( struct StdIOReq *req (A1) );

Starts and waits for the completion of the IO request. (Internally calls SendIO()/ WaitIO().)

LONG SendIO( struct StdIOReq *req (A1) );

Sends a request to the device without waiting for a reply. Internally calls the device's BeginIO() entry.

req is pushed into stack for C-language BeginIO() handlers.

struct StdIOReq *CheckIO( struct StdIOReq *req (A1) );

Checks if the request has been returned. Only checks if mn_Node.ln_Type == NT_REPLYMSG.

LONG WaitIO( struct StdIOReq *req (A1) );

Waits for the completion of the request and removes it from the replyport. DO NOT call WaitIO() on a request that has not been sent!

void AbortIO( struct StdIOReq *req (A1) );

Tries to abort the handling of a request by internally calling the device's AbortIO() entry. The device is required to implement this feature. You should call WaitIO() after AbortIO().

req is pushed into stack for C-language AbortIO() handlers.

Libraries

void AddLibrary( struct Library *library (A1) );

Will add a library to the system. The library should be initialized correctly and be ready to receive Open() calls.

struct Library *RemLibrary( struct Library *library (A1) );

Will remove a library from the system. If the library is currently opened by anyone, the call returns NULL.

void InitLibFuncs( struct Library *lib (A0), ULONG *funcs (A1), ULONG num (D0) );

Initializes the library call vectors to the addresses specified in the array funcs. The first element of the array becomes the address of the jump in offset -6, the next in offset -12 and so on. The library structure should have negative size of at least 6*num so that this call will not overwrite anything.

struct Library *OpenLibrary( char *name (A1) );

Will open a specified library. If the library does not exist, or can't be opened, NULL is returned. Otherwise the library base of the library is returned. Internally the library's Open() entry is called and the return value checked to determine if the open was successful. The library itself maintains lib_OpenCnt.

void CloseLibrary( struct Library *library (A1) );

Will close a previously opened library. Internally the library's Close() entry is called. The library itself maintains lib_OpenCnt.

ULONG SetFunction( struct Library *library (A1), LONG offset (D0), ULONG val (D1) );

Will change the specified library call vector to point to the new routine. The old value of the vector is returned. offset is the negative call offset used when calling the library.

DO NOT try to patch Disable()/Enable() nor Forbid()/Permit() .


Other

The BOAR clock runs UTC (GMT) time. The shell variable TIMEZONE should be used to do the adjustment to get the local time.

void DateStamp( struct DateStamp *date (A0) );

Will return the current system time. This is an atomic operation, interrupts are not needed to be disabled.

void SetDate( struct DateStamp *date (A0) );

Will set a new system time. This is an atomic operation, interrupts do not need to be disabled.

Semaphores

Semaphore functions use C-language calling conventions (parameters in stack).

void InitSemaphore( struct SignalSemaphore *sem );

Initializes a private semaphore for usage.

void AddSemaphore( struct SignalSemaphore *sem, const char *name, BYTE pri );

Adds a semaphore to the system's Public Semaphores list. All initialization is done by AddSemaphore().

void RemSemaphore( struct SignalSemaphore *sem );

Removes a semaphore from the system's Public Semaphores list.

OBSERVE:
There may still be locks held on the semaphore and maybe also requests pending. To remove a public semaphore use the reference count as follows:
	Forbid();
	while(1)
	{
		if(sem->ss_Public == 0)
		{
			RemSemaphore(sem);
			break;
		}
		/* Delay() breaks Forbid() state */
		Delay(100);
	}
	Permit();

struct SignalSemaphore *FindSemaphore( const char *name );

Searches the system's Public Semaphores list for a semaphore. Returns NULL if the named semaphore can't be found. Use FreeSemaphore() to relinquish the obtained semaphore handle.

Remember that public semaphore names are not guaranteed to be unique by the system.

void FreeSemaphore( struct SignalSemaphore *reference );

Ends the usage of a public semaphore obtained by FindSemaphore().

LONG AttemptSemaphore( struct SignalSemaphore *sem );

Tries to get an exclusive lock on the semaphore without blocking. Returns zero for failure, non-zero for success.

LONG AttemptSemaphoreShared( struct SignalSemaphore *sem );

Tries to get a shared lock on the semaphore without blocking. Returns zero for failure, non-zero for success.

void ObtainSemaphore( struct SignalSemaphore *sem );

Gets an exclusive (write) lock on the semaphore. Blocks (waits) until the lock is obtained.

void ObtainSemaphoreShared( struct SignalSemaphore *sem );

Gets a shared (read) lock on the semaphore. Blocks (waits) until the lock is obtained.

void ReleaseSemaphore( struct SignalSemaphore *sem );

Releases an obtained lock on the semaphore, whether shared or exclusive.

Function Index