Inter-Task Communication

Top  Previous  Next

Now let's consider the code for the two user tasks, and look in particular at the way they communicate.

 

// driver.c file I/O for upper-casing example

#include <chan.h>

#include <stdio.h>

main(int argc, char *argv[], char *envp[],

     CHAN * in_ports[], int ins,

     CHAN *out_ports[], int outs) {

   int c;

   for (;;) {

      c = getchar();

      chan_out_word(c, out_ports[0]);

      if (c == EOF) break;

      chan_in_word(&c, in_ports[0]);

      putchar(c);

   }

}

 

Coding the driver task in C is easy. Instead of using the toupper function from ctype.h as before, it now converts characters to upper case by sending a message containing the ASCII character code to the 'computation' task and waiting for a reply message containing the result.

 

C tasks send messages using the channel I/O functions. The chan.h package provides functions to send and receive messages of any multiple of words; a word is the same size as an int. In our program, we use chan_in_word and chan_out_word to handle word-sized messages. The statement in driver.c, which sends character codes to the processing task, is:

 

chan_out_word(c, out_ports[0]);

 

The word (int) value to be sent is passed as the first argument in the function call. The second argument to chan_out_word identifies the channel to which the message is to be sent. In this case, it's the channel associated with the driver task's output port 0, out_ports[0]. The CONNECT statement in the configuration file above which refers to driver[0] specifies which input port is connected to the other end of the channel. Here it is input port 0 of the processing task, upc. out_ports is a vector of pointers to channels, passed into the task via the argument list of its C main function.

 

This vector is declared as:

 

CHAN *out_ports[];

 

CHAN is the channel data type defined in the library header file chan.h, which must be included by C files that use the channel I/O functions. Each port (i.e., each element in the vector) has type 'pointer to channel'.

 

The number of output ports in the vector is defined by the OUTS attribute of the TASK statement used to declare the task in the configuration file. Our driver task has outs=1, so there is only one element in its output port vector, numbered 0. The value of OUTS is passed into the task as an argument to main along with the port vector. It is declared (int outs) in driver.c but this simple example assumes it has the value 1. It can be used to write tasks that handle an arbitrary number of ports, like the multiplexor task described later on in this section.

 

The main function's argument list also provides access to the input port vector in a similar way. In the driver example, the input port vector is given the name in_ports and has ins elements. The driver task will keep reading characters from the standard input stream (getchar), sending them to the processing task and writing the reply messages (the translated characters) to the standard output stream until EOF is read.

 

The next thing to look at is the processing task. It is logically a 'black box' with one input port and one output port:

UpcTask

 

 

The processing task uses the same channel I/O functions as the driver to send and receive messages. It terminates when it receives an EOF from the driver.

 

// upc.c stand-alone processing task; communicates with driver.c

#include <chan.h>

#include <ctype.h>

#include <stdio.h> // for EOF

main(int argc, char *argv[], char *envp[],

     CHAN * in_ports[], int ins,

     CHAN *out_ports[], int outs) {

   int c;

   for (;;) {

      chan_in_word(&c, in_ports[0]);

      if (c == EOF) break;                    // terminate task

      chan_out_word(toupper(c), out_ports[0]);

   }

}

Dragons003Beware when using the channel I/O functions that sending and receiving tasks must always agree on the size of messages. For example, if a task sends a five-word message, the receiving task must read it as one five-word unit; it is not possible for the receiving task to read five separate one-word messages. Trying to do so may cause the processor to lock up or behave unpredictably.