DPS Technical Brief

 1. Introduction
 DPS is the multi-task OS, which comes with our computer products.
It supports multiple windows with various graphic functions, has an
object access system, as well as external type learning conventions,
and feels comfortable even on small systems (the Nukeman 226 has 1 Mbyte
of RAM).

 The DPS file system allows 32-bit file sizes, can work with non-file 
mode devices, and can transparently (though somewhat slower) access
Microsoft formatted disks. Files are accessed via the registered file
access functions in nearly all cases; that is, DPS keeps a list
of files which are open and prevents reservation conficts (making
a file publically avaiable, i.e. r/w accessible for multiple tasks,
is also possible - this is how, for example, directories are accessed).

 Because its initial application  was for measurement and control
purposes, DPS has well defined hardware access standards and offers
many readily available objects (e.g. "device", "device_parameter",
"nukebus_module" etc), thus minimizing the programming overhead for
incorporating new hardware into the system. 

 Task switch is done using rotating priority with increment every
time a task loses the arbitration; this guarantees it will eventually
win. Once a task wins the arbitration, its priority is preset back to
its basic level (as spawned or set by other means in the task
 The time slice can be set as low as 2 milliseconds; beyond that, 
all tasks waiting for some event can ask the scheduler to give control
to another task immediately.

 System memory is dynamically allocated/deallocated (using worst-fit
strategy) in clusters (cluster size in DPS 1.1 is 1 kbyte).
 Applications are given a mechanism to declare allocated memory blocks
for swapping while not accessing them (this works even on systems
without an MMU).

 Disk space is also allocated using worst fit strategy, which yields
(of all known) the least medium fragmentation (a lot less than with
the most widely spread first fit strategy). Medium space is described
by a bit-per-cluster, the file layout being stored separately
from the CAT (Cluster Allocation Table), which allows 32 times shorter
cluster under the same circumstances as a system using 32 bit FAT
would allow.

 The script language allows access to DPS external objects and recursive
calls (a script can call itself), and also allows retry and resume
from the point/level of abort. The script processor is available as
an external object to any application which wants to use it.

 All programs written so far are reentrant/position independent, which
allows running multiple copies of the same program code as multiple
tasks, which is automatically done by DPS.

 System programmers who will need access to exception vectors are
given the convenience not to think how many times and by which task
a vector has been swapped - they can just use the registered swap
and restore function, which takes care of restoring the right value
to the vector at the right moment, optionally automatically upon
killing a task which has swapped vector(s).

 Device driver programmers are given means to find their way to
the device descriptor from the related interrupt handler (i.e. device
drivers are also completely position independent).

 2. Operation

 Upon system start, DPS goes through the following steps (of user

 - processes the setup.syst file, which is used to set certain
   system parameters (e.g. the time slice) and to load as densely
   as possible selected device drivers,

 - spawns the "win.com", which is the task dealing with mouse actions,
   manual window limits change/signalling, keyboard polling, input (from
   mouse and keyboard) distribution to the input owning task etc.,

 - spawns the "shell.com", which, in turn, executes the "turnon.bat"
   command script, upon whiches termination waits for user commands.

 DPS applications run as independent tasks. The shell program is the
program which starts other tasks as applications (either from a command
line input or as a result of a menu selection); in order to start a
new task, it does the following:

 - calls the "xload$" function, which checks if the respective 
   program module is resident in memory and loads it if it is not, 

 - calls the "spawnn$" function, which:
   - allocates the user level data memory (also called user DSCT),
   - allocates the task's system DSCT, at the top of which 
     it places certain task unique variables and sets the system 
     stack pointer just below this area,
   - connects the task to the parent's (i.e. the shell's) common DSCT, 

 - prepares the standard input, standard output and standard error
   (stdi, stdo and stderr) I/O nexuses (an I/O nexus is a more 
   general form of a file) for the new task and registers it for
   access into each;

 - calls the "start$" function, which places the new task among those 
   which are given control from the scheduler and waits the task 
   to exit or be aborted (from another shell using the "kill" command or 
   killed because it did some illegal access etc) unless having been told 
   to start the task in background, in which case it comes back immediately.

 A task, after having been spawned, can choose to allocate for itself
another common DSCT and spawn other tasks (this is how the nuvi
program operates, for example); the new group of tasks, connected to the
same common DSCT - which (except for its header) is used as the tasks
wish - is sometimes refered to as a "process".

 Not all the code a task needs to execute must be in the program module
it was started with. A task may call named functions from specified
files (default suffix being .plm). When such a function is called, the
respective file is loaded as a program module (if not already there),
and control is given to the location specified by the function name
the way a subroutine is called. Upon return from the function, if there
are no more tasks connected to this module, it is discarded. 
(Many such functions are readily avaialble in \syslib\ - like "menu",
"dpsfsrch" - file search from a window etc.)

 One way for the tasks to communicate with each other is by sending
signals/messages. (This is how, for example, the mouse actions are
distributed from the "win" task to other tasks). To send a signal,
a task calls the "sign$" or "signto$" function; then, with some more 
system created data being passed, a predefined point of the target
program module of the task being signalled to is called. How the
signal is received then is up to the code of the receiving task; if
it is our "qstd" code, for example, it will place the signal on a
queue in the receving task's user DSCT and return; the receiving task
will eventually find it there and process it.

 When a task exits (either alone or being killed by another), the 
following is done:

 - the resources taken by the task and denoted so in its history
   record are released, possibly one or more exit subroutines
   are called, if declared (at least one if the task owns open

 - all I/O nexuses to which the task was registered are "left" - that
   is, the task is unregistered and, if the nexus (file) has no more
   tasks registered to it, it is closed,

 - the history record is processed on a second pass,

 - the task's user DSCT is deallocated,

 - the task is unregistered from its common DSCT, which is deallocated,
   if no more tasks are connected to it,

 - the task is unregistered from its program module, which is removed
   (deallocated) if no oter task is connected to it,

 - the task's system DSCT is deallocated and the task is removed from
   those being given control by the scheduler (i.e., the task descriptor
   is released) - the task is dead.

 3. DPS External Objects 

 The DPS external object access system is simple and straight forward
-  an object is something with which certain actions can be done -
how they are done  depends on the object. When a program wants to
do something with an object, it points to it, indicates the action
and calls the "do$" or the "qact$". Every object is of some type 
- that is, it is a kind of some other, known at the point of learning,
object; the basic type of object is "something". Doing an action 
with some object is done the same it was done with its "prototype"
object unless declared differently. 

 External object designation follows a standard format - 16 bytes 
(usually used as ASCII text) designate the type. The actions are designated
by 8 bytes each (again, usually used as text); object descriptors are
kept on a linked list, where search links are different from the type
links; this allows the most frequently used objects to be checked 
first, regardless of their type or moment of learning.

 To teach DPS what a new object is, a program has merely to attempt an
action (possible or not) with such an object. As it is not found on the
linked list, a file (with a name made of the first 8 alphanumeric characters
of the object type) with a .type suffix is searched first in the 
calling task's spawn directory (the directory where the program module
was loaded from), then in \wwdir\, and the object descriptor(s) found
in this file is (are) put on the list; then, the "install" action is done
with the object which initiated the search (the "something" type "install"
action returns without doing anything), and finally, the requested
action is attempted. Type search is recursive; that is, if a type
found in a file is not known at this point, another search is initiated
before installing the new type.
 On boot time, DPS 1.1 always installs the following types:

 - "something", with the following actions defined:
   - "install" - does nothing,
   - "create" - create such an object in memory,
   - "remove" - remove such an object from memory,
   - "readobj" - read (learn) a new object - see the paragraph above,
   - "getsize1" - used by "create" to determine the size of the
     object being created,

 - "memory_block" , which is "something", and is used by DPS to keep
   object descriptors into.

 If the "create" action is done with "something" (e.g. by using the
"make" statement from a command script), the "object_segment" type is
learned; it is a kind of memory block with some more encapsulation
data, and makes sure that the created object, which is inside this
"object_segment", can be locked for access, properly removed and/or
located during garbage collection procedures etc.

 The "show" action is reserved for DPS usage - it is done with
objects in a sequence being processed by the "xwseq$" function,
which allows displaying of a sequence of both DPS internal
and external (the latter were discussed above) objects.

[Contact us] [Home]