Make your own free website on Tripod.com

EuOS Kernel API

By Jeffrey Fielding

August 20, 1999

This document defines EuOS's kernel API for programs. In addition to these public API calls, there are many internal kernel routines that are documented in the source documentation, as well as a few "distribution" APIs which are available only to the parent "distribution" and are defined in the distribution documentation.

The inner workings are not described here either, since I haven't actually written the code yet. Everything that an application programmer needs to write a program for EuOS is defined here, however, and in enough detail that I think most people won't need the full kernel documentation.

The API documentation assumes that the programmer understands the basics of the operating system. In case you are not familiar with the basic design of EuOS, I will cover it briefly here. You might also want to read The EuOS Kernel.

If you have anything to add to this document, or find any errors in it, please e-mail me and I'll update it.

Basic Kernel Concepts

First of all, the kernel uses a lot of neat tricks with include files. The kernel is an include file which is included by the "distribution", or the parent program. The way Linux is distributed is an analogy. With Linux, there are many distributions (Red Hat, for example), but they all use the same kernel.

Programs are in include files which are included in the kernel at just the right place to give the distribution access to some of the routines while keeping them hidden from the programs. All programs are made up of one or more routines and some startup code. The startup code calls the addProgram routine, which is documented below. Startup code is outside any routine, so it is run when the program is loaded.

To implement multitasking, the program is divided into several functions. These functions take no arguments and return the routine_id of the next routine to call (after other tasks get a chance to run), or -1 to terminate the thread (and the program if this is the last thread). There are also event handler procedures, which accept a sequence as an argument. These are very short procedures which are run when an event is generated. They can create threads if they take a long time to run.

addProgram

One of the most important API calls is addProgram. This procedure announces a program to the kernel. Every program is defined in an include file which is included by programs.e, which is included by the kernel. This allows the kernel to include programs.e at just the right place in the program to give the programs access to what they need, and hide what they don't (and can't have access to). The kernel can also add and remove programs from programs.e very easily to solve conflicts etc.

In fact, the only thing that a program can do when it runs its initial code (the code that's not in any routine) is to call addProgram and initialize any variables.

addProgram checks for conflicts between your program and other programs to make sure the operating system runs cleanly. If a conflict is found, it notifies the user and gives the user advice on what to do. A conflict occurs when your program has the same name as another program. Because of this, I highly suggest that any program distributed for any reason other than testing be registered in the EuOS programs database online (see EuOS Online) so that conflicts can be found before distributing any program.

Usage: addProgram(name,version,stability,type,main,restore)

name The name of the program. This should be unique to each program, but the same between versions. It should be a string containing printable characters.
version The version of the program. This is an atom, so the integer part is the major version and the fractional part is the minor version.
stability This is the stability index of the program. Generally, an alpha-test would be UNSTABLE, a beta-test would be LOW_STABILITY, a new program would be MEDIUM_STABILITY, a program that has been around for a while and well tested would be HIGH_STABILITY, and programs that are pretty much crash proof are ULTRA_STABLE. An example of an ultra-stable program is one that displays 5+5.
type This is the type of the program. It can be PROGRAM, DRIVER, DAEMON, LIBRARY, or SHELL.
main This is the routine_id of the main routine. For libraries, it's -1.
restore This is the routine_id of a restore routine that is called instead of main to restore a backup. It can be -1 if no restore routine is available. This is only applicable to programs.

Both the main routine and the restore routine are called without any arguments. When restore is called, any data that was stored by the kernel is restored.

The type is important. All the types are explained in the following table.

Type Description Job of main routine
PROGRAM A usual program. Started by the user, receives input, sends output through shell. Initialize the program, start any threads, register any event handlers, and return routine_id of next function in the main thread.
DRIVER A driver is run once for each device. The driver can receive arguments describing what device to control with its command line arguments. It registers driver routines with the kernel, and can optionally add threads to poll the device and generate events. Register the driver with the kernel. The kernel then calls the initialize routine when it wants to use the device, and the close routine when it's finished. Note that opening the device is not the job of the main routine, but the initialize routine. Also, the main routine is called once, not once for each instance. The initialize routine handles instance-specific initialization. The main routine must return -1.
DAEMON A daemon is a program that only runs when an event occurs. It can have multiple instances. The main routine registers any event handlers and returns -1. It can also initialize variables etc.
LIBRARY A library provides a set of routines that other programs can run. They have only one instance, but they can store data with the program that calls it. In fact, library routines are run as if they were a routine in the program that calls it. The main routine is responsible for initializing the library's instance-independent variables and registering its routines with the OS.
SHELL A shell is a mix of a program, a driver, and a daemon. It is responsible for re-directing the input and output of programs to a user interface. Shells can be text based or graphical. The main routine initializes a new instance of the shell.

getInstance

Returns the instance of the current program.

Usage: instance = getInstance()

instance: The instance of this program.

getProgramId

Returns the id of this instance of the program.

Usage: id = getProgramId()



id: The id of the current instance of the program.

runProgram

Runs a program and returns its id.

Usage: id = runProgram(program, arguments)

id: The id of the program, or 0 on error.

program: The name of the program.

arguments: The arguments the program takes.

getThreadId

Returns the current thread id.

Usage: id = getThreadId()



id: The id of the current thread.

createThread

The createThread routine creates a new thread for the current task and returns its thread id. Thread ids start at 1 and are unique until you use destroyThread. Then they are reused.

Usage: threadid = createThread(startroutine)

startroutine: the routine_id of the first function

threaded: the id of the new thread

destroyThread

The destroyThread routine ends the specified thread.

Usage: destroyThread(threadid)

threadid: the threadid returned by createThread

setThreadPriority

Sets the specified thread's priority.

Usage: setThreadPriority(thread, priority)

thread: The id of the thread.

priority: The priority (SLEEP, LOW, or HIGH). Threads in SLEEP mode are suspended. LOW priority threads are run once for every time that all threads HIGH priority threads are run.

getThreadPriority

Gets the specified thread's priority.

Usage: priority = getThreadPriority(thread)

thread: The id of the thread.

priority: The priority (SLEEP, LOW, or HIGH). Threads in SLEEP mode are suspended. LOW priority threads are run once for every time that all threads HIGH priority threads are run.

abort

Abort ends the current program with an error code (or 0 if there's no error).

Usage: abort(error)

error: The error code, or 0 for no error.

createEvent

The createEvent routine creates a new event that can be handled by any of the programs listed, or all of the programs.

Usage: eventid = createEvent(programs)

programs: a list of programs, or 0 to let all programs access the event. Programs are either in the form {name} to specify that all instances of that program can access it, or in the form {name,instance} where instance is an integer to specify that only that instance can access it.

eventid: The integer id of the event, starting at 1. Event numbers are reused when they are removed.

removeEvent

The removeEvent routine removes an event. All handlers are also removed.

Usage: removeEvent(event)

event: the event id of the event

getAllowedEventHandlers

This routine returns the list of programs allowed to access the specified event in the same form as the programs argument to createEvent.

Usage: programs = getAllowedEventHandlers(event)

event: the event id of the event

programs: the programs allowed to access this event in the same form as the programs argument to createEvent, or -1 if this event is not accessible to the current program.

setAllowedEventHandlers

This routine sets the list of programs allowed to access the specified event in the same form as the programs argument to createEvent.

Usage: setAllowedEventHandlers(event, programs)

event: the event id of the event

programs: the programs allowed to access this event in the same form as the programs argument to createEvent, or -1 if this event is not accessible to the current program.

fireEvent

This runs all the event handlers for the specified event with the specified arguments.

Usage: fireEvent(event, arguments)

event: the event id of the event to fire

arguments: a sequence of arguments to pass to the handlers (passed as a sequence, not each element as an argument).

storeTaskData

This stores data for the current task.

Usage: storeTaskData(id, data)

id: any Euphoria object which is used as the index into the data table.

data: The data to store (any Euphoria object)

getTaskData

This retrieves data from the current task.

Usage: data = getTaskData(id)

id: any Euphoria object which is used as the index into the data table.



data: The data retrieved, or -1 if there is no element with that name. Note: since -1 might be used as a value, you should check the last error instead of relying on -1.

storeThreadData

Stores thread-specific data for this task.

Usage: storeThreadData(thread, id, data)

thread: the thread to store the data for

id: any Euphoria object which is used as the index into the data table.

data: The data to store (any Euphoria object).

getThreadData

Retrieves thread-specific data from this task.

Usage: data = getThreadData(thread, id)

thread: the thread to retrieve the data from

id: any Euphoria object which is used as the index into the data table.

data: The data retrieved, or -1 if there is no element with that name. Note: since -1 might be used as a value, you should check the last error instead of relying on -1.

getLastError

This returns the last error.

Usage: error = getLastError()

error: The error code, or 0 if no error.

registerLibrary

Registers a library with the kernel. This is run in the main routine of a library.

Usage: registerLibrary(routines)

routines: A sequence of all the global routines provided by the library. Each element is in the form {name, routine_id}.

registerDriver

Registers a driver with the kernel. This is run in the main routine of a library.

Usage: registerDriver(extends, init, close, routines)

extends: The name of the driver which this extends. This allows this driver to be used in place of the other driver. extends can also be 0, in which case this a new type of driver and does not extend an existing driver.

init: A routine which is called to initialize a new instance of the device. init must be a valid routine. The init routine is a procedure with one argument, which is the init routine of the driver which it extends (or 0 if it doesn't extend anything).

close: A routine which is called to close a the device. close must be a valid routine. The close routine is a procedure with one argument, which is the close routine of the driver which it extends (or 0 if it doesn't extend anything).

routines: A sequence of routines provided by this driver. Each element is in one of the following formats:

-1 Indicates that this routine is not supported and must be supported by another driver which extends it.
routine The routine_id of the routine to call. Routines are functions which accept two arguments: the routine_id of the same function in its parent driver, and a sequence containing arguments. The return value is whatever you want it to be, and it is returned to the caller.

getDriver

This call returns the specified driver for the current task.

Usage: driver = getDriver(name)

driver: The id of the driver.

name: The name of the driver.

getActualDriver

This call returns the actual (not referenced) specified driver for the specified task.

Usage: driver = getActualDriver(program, name)

driver: The id of the driver.

name: The name of the driver.

program: The id of the program to get the driver from.

setDriver

The setDriver changes the driver a program uses. This allows shells to re-direct the output of a program, for example.

Usage: setDriver(program, driver, newdriver)

program: The id of the program to set the driver for.

driver: The name of the driver to set.

newdriver: The driver to set it to.

createDriver

This creates a new instance of the specified driver.

Usage: driver = createDriver(name, arguments)

driver: The id of the driver.

name: The name of the driver.

arguments: The arguments (passed as command-line arguments) to the driver.

initDriver

This calls the init routine of the specified driver.

Usage: initDriver(driver)

driver: The id of the driver.

closeDriver

This calls the close routine of the specified driver.

Usage: closeDriver(driver)

driver: The id of the driver.

callDriver

This calls the specified routine of the specified driver.

Usage: returnvalue = callDriver(driver, routine, arguments)

driver: The id of the driver.

routine: The routine to call (integer >= 1).

arguments: The arguments to pass to the driver.

returnvalue: The value returned by the driver.

openLibrary

Returns the id of the specified library.

Usage: id = openLibrary(library)

id: The id of the library, or 0 if there was an error.

library: The name of the library.

defineLibraryProc

Returns the id of a procedure in a library.

Usage: id = defineLibraryProc(library, routine)

id: The id of the procedure.

library: The id of the library.

routine: The name of the routine.

defineLibraryFunc

Returns the id of a function in a library.

Usage: id = defineLibraryFunc(library, routine)

id: The id of the function.

library: The id of the library.

routine: The name of the routine.

libraryProc

Calls the specified library procedure.

Usage: libraryProc(id, arguments)

id: The id of the procedure.

arguments: The arguments to pass to the procedure.

libraryFunc

Calls the specified library function.

Usage: returnvalue = libraryFunc(id, arguments)

id: The id of the function.

arguments: The arguments to pass to the function.

returnvalue: The return value of the function.

generateError

Generates an error, which the program can check using getLastError.

Usage: generateError(error)

error: An integer error code

generateFatalError

Generates a fatal error, which crashes the program.

Usage: generateFaralError(error, message)

error: An integer error code.

message: An error message to display when the program crashes.