6.4 Handling I/O

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 keyboardP1, 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.

Hello world