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: = LIB.BasicSystem.BasicSystem  
   P1: = BasicProcess("P1")
          ch: ?char
          ch := keyboard.get(P1)
          "P1 read: ".print;
          %restart loop
      "P1 started\n".print
   P2: = BasicProcess("P2")
       loop: =
           i := i + 1
           %if (i /% 1000) = 0 %then%
              "P2 here\n".print
           %restart loop
   "KBprocess started\n".print

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.get returns 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: = BasicProcess("Keyboard")
    B: = Indexed(100,integer)
    next: ?integer
    top: ?integer
       loop: =
          %if _kbhit %then%
              top := top + 1
              B.%put _iget %at% top
          %restart loop
    get(caller: ?BasicProcess) -> ch: ?char:
        waitForChar: =  
            %if next  < top %then%
                next := next + 1
                ch := B.%get next
                %restart waitForChar

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.