Here we describe how to implement objects handling IO.
The example is a concurrent object, keyboard, that reads characters from a keyboard, but without blocking. The keyboard object may be used as in the following example
KBprocess: obj LIB.BasicSystemLib.BasicSystem
P1: obj BasicProcess("P1")
loop: do
ch: var char
ch := keyboard.get(P1)
"P1 read: ".print;
put(ch)
newline
restart(loop)
"P1 started\n".print
P1.suspend
P2: obj BasicProcess("P2")
loop: do
i := i + 1
if ((i /% 1000) = 0) :then
"P2 here\n".print
P2.suspend
restart(loop)
"KBprocess started\n".print
cycle
Keyboard.resume
P1.resume
P2.resume
The object KBprocess is subclassed from BasicSystem – part of the qBeta library.
It defines two active object, P1 and P2.
P1 constantly reads a character on the keyboard using ch := keyboard.get(P1). If a character has been typed, keyboard.getreturns with that character. If no character has been typed, P1 is suspended. The next time P1 is resumed, keyboard.get again test if a character has been typed, etc.
The object P2 constantly writes a message on the console and then suspends.
The KBprocess constantly – using cycle – resumes the object keyboard, P1, and P2. In this example the three object are cooperatively scheduled – they might as well bee scheduled pre-emptively using e.g. P1.attach(100), etc.
The important property of this example is that P1 does not block if there is no input on the keyboard.
The output from a an execution may look as follows:
KBprocess started
P2 here
P2 here
P1 read: a
P2 here
P2 here
P1 read: b
P2 here
P1 read: c
P1 read: d
P2 here
P2 here
P2 here
P1 read: e
P2 here
P2 constantly writes the text P2 here – when a character has been typed, P1 writes a text like P1 read: a, where a is the character that has been typed.
The keyboard object
The keyboard object may be defined as follows:
keyboard: obj BasicProcess("Keyboard")
B: = Indexed(100,integer)
next: var integer
top: var integer
scan:
loop: obj
if (_kbhit) :then
top := top + 1
B.put(_iget):at[top]
keyboard.suspend
restart(loop)
get(caller: ref BasicProcess) -> ch: var char:
waitForChar: obj
if (next < top) :then
next := next + 1
ch := B.get[next]
:else
caller.suspend
restart(waitForChar)
scan
The keyboard object is subclassed from BasicProcess as is P1 and P2.
It defines an Indexed object B with index variables next and top. B is used to buffer input from the keyboard until read by get. Note that the example does not handle more than 100 chars – the program will simply fail with an index error if more than 100 chars have been typed – this is, however easy to fix.
The scan pattern, constantly checks if a character has been typed – using the primitive operation _kbhit. If a character has been typed it is read – using _iget and inserted into B. Then the keyboard suspends.
The get operation checks if there is a character in the buffer B, and if so, returns the next one. If B is empty, then it suspends the caller – using caller.suspend.
Note that in this version of qBeta, the called of get is passed as a parameter in order to be suspended. This is needed since it is to possible to suspend the active coroutine without having a reference to it. This is possible in Beta and SIMULA and may bed added to qBeta. The first versions of SIMULA and Beta did not have the R.suspend operation – but this was later added to SIMULA and Beta.
IO in general
The example example may be generalized – at least we think so – to handle input from other sources like ports, but also hardware devices om embedded platfroms (boards). But only for devices/ports where it is necessary to scan memory locations in order to detect if there is new data. An example of non-blocking sockets is described here.
For devices controlled by interrupts, something else has to be done. The plan is to support this.