📄 rfc809.txt
字号:
been established. Data flows in both directions are permitted, though the operations are quite different. The interface provides two primitives for data transfer -- read and write. To transfer some data to the 'slave', the 'master' signals it with a CSB containing the write function and a buffer filled with the data to be transferred. Having consumed the data, the 'slave' returns the CSB to report the result status of the transmission. On the other hand, in order to receive some data from the 'slave', the 'master' uses a read CSB with an empty buffer. Having received the CSB, the 'slave' fills the buffer with the data requested and, then, returns the CSB. - 22 -UCL FACSIMILE SYSTEM INDRA Note 1185 3.4 Control and Organisation of the Tasks Another important aspect of the multi-process architecture of the UCL facsimile system, is the need to systematise the control and organisation of the tasks. This activity is the function of the task controller, whose operations are discussed in this section. 3.4.1 Command Language As mentioned earlier, the task controller supports a procedure-oriented language by means of which the user or the routines of the upper layers can define the jobs requested. A command should contain the following information: 1. the names of the task processes which are involved in the job. 2. the open parameters for these task processes. 3. the order in which the tasks are to be linked. The last item is quite important, though, usually, the same order as that given in the command is used. A command in this language is presented as a zero- ended character string. In the task name strings and the attribute strings of the open parameters, '|', '"', and ',' must be excluded as they will be treated as separators. The definition is shown below, where '|', which is the separator of the command strings in the language, does not mean 'OR'. <command_string> ::= <task_string> <command_string> ::= <task_string>|<command_string> <task_string> ::= <task_name> <task_string> ::= <task_name>"<open_parameter> <open_parameter> ::= <attribute> <open_parameter> ::= <attribute>,<open_parameter> 3.4.2 Task Controller In our experimental work, the task controller module is called fitter. This name which is borrowed from UNIX hints how the module works. According to the command string, it links the specified tasks into a chain, along which the data is processed to fulfil the - 23 -UCL FACSIMILE SYSTEM INDRA Note 1185 job requested (Fig. 8). tasks +-----+ +-----+ +-----+ ! a ! -> ! b ! -> ! c ! +-----+ +-----+ +-----+ Fig. 8 The task chain Since all modules, including fitter itself, are implemented as processes, the connections between modules should be via the Clean and Simple interfaces. Upon receiving the command string, the fitter parses the string to find each task process involved and opens a connection to it. Formally, the task processes are chained directly, but, logically, there is no direct connection between them. All of them are connected to the fitter (Fig. 9). fitter +-------------+ +-- ! ! --+ | +-------------+ | | | | V V V +-----+ +-----+ +-----+ ! a ! ! b ! ! c ! +-----+ +-----+ +-----+ Fig. 9 The connection initiated by the fitter For each of the processes it connects, the fitter keeps a table called pipe. When the command string is parsed, the pipe tables are double-linked to represent the specified order of data flow. So far as one process is concerned, its pipe table contains two pointers: a forward one pointing to its destination and a backward one pointing to its sources. Besides the pointers, it also maintains the information to identify the task process and the corresponding connection. - 24 -UCL FACSIMILE SYSTEM INDRA Note 1185 Fig. 10 illustrates the chain of the pipe tables for the job "a|b|c". Note that the forward (output) chain ends at the sink, while the backward (input) chain ends at the source. In this sense, the task processes are chained in the specified order via the fitter (Fig. 11). The data transfer along the chain is initiated and controlled by the fitter, each process getting the input from its source and putting the output to its destination. +-----+ +-----+ +-----+ ! * -+--> ! * -+--> ! 0 ! +-----+ +-----+ +-----+ ! 0 ! <--+- * ! <--+- * ! +-----+ +-----+ +-----+ ! a ! ! b ! ! c ! +-----+ +-----+ +-----+ ! ! ! ! ! ! ! ! ! ! ! ! +-----+ +-----+ +-----+ Fig. 10 The pipe chain fitter +-------------+ +-> ! * -> * -> * ! --+ | +-------------+ | | | A | | V | V +-----+ +-----+ +-----+ ! a ! ! b ! ! c ! +-----+ +-----+ +-----+ Fig. 11 The data flow This strategy makes the task organisation so flexible that only the links have to be changed when a new task chain is to be built up. In such an environment, each task process can be implemented independently, provided the Clean and Simple interface is supported. This also makes the system extension quite easy. - 25 -UCL FACSIMILE SYSTEM INDRA Note 1185 The fitter manipulates one job at a time. But it must maintain a command queue to cope with the requests, which come simultaneously from either the upper level processes or other hosts on the network. 3.5 Interface Routines In a modular, multi-process system such as the UCL facsimile system, the structure of the interface routines is very important. The CSI of section 3.3 is fundamental to the modular interface; a common control structure is also essential. This section gives some details both about the sharable control structure and the buffer management. 3.5.1 Sharable Control Structure Though the CSI specification is straightforward, the implementation of the inter-process communication interface may be rather tedious, especially in our system, where there are many task processes to be written. Not only does each process have to implement the same control structure for signal handling, but also the buffer management routines must be included in all the processes. For the sake of simplicity and efficiency, a package of standard interface routines is provided which are shared by the task processes in the system. These routines are re-entrant, so that they can be shared by all processes. The 'csinit' primitive is called for a task process to check in. An information table is allocated and the pointer to the table is returned to the caller as the task identifier, which is to be used for each call of these interface routines. Then, each task process waits by invoking the 'csopen' primitive which does not return until the calling process is scheduled. When the connection between the process and the fitter is established, the call returns the pointer to the open parameter string of the task, the corresponding task being started. A typical structure of the task process (written in c) is shown below. After the task program is executed, the process calls the 'csopen' and waits again. It can be seen that the portability of the task routines is improved to a great extent. Only the interface routines - 26 -UCL FACSIMILE SYSTEM INDRA Note 1185 should be changed if the system were to run in a different operating environment. static int mytid; /* task identifier */ task() { char *op; /* open parameter */ mytid = csinit(); for(;;) { op = csopen(mytid); ... /* the body of the task */ } } 3.5.2 Buffer Management The package of the interface routines also provides a universal buffer management, so that the task processes are freed from this burden. The allocation of the data buffers is the responsibility of the higher level process, the fitter. If the task processes allocated their own buffers, some redundant copying would have to be done. Thus, the primitives for data transfer, 'csread' and 'cswrite', are designed as: char *csread(tid, need); char *cswrite(tid, need); where 'tid' is the identifier of the task and 'need' is the number of data bytes to be transferred. The primitives return the pointer to the area satisfying the caller's requirement. The 'csread' returns an area containing the data required by the caller. The 'cswrite' returns an area into which the caller can copy the data to be transferred. The copied data will be written to its destination at a proper time without the caller's interference. Obviously the unnecessary copy operations can be avoided. It is recommended that the data buffer returned by the primitives be used directly to attain higher performance. - 27 -UCL FACSIMILE SYSTEM INDRA Note 1185 In order to implement this strategy, each time a piece of data is required, the size of the buffer needed is compared with that of the unused buffer area in the current CSB. If the latter is not less than the former, the current buffer pointer is returned. Otherwise, a temporary buffer has to be employed. The data is copied into the buffer until the requested size is reached. In this case, instead of a part of the current buffer, the temporary buffer will be returned. A 'cswrite' call with the 'need' field set to zero tells the interface routine that no more data will be sent. It causes a 'close' CSB to be sent to the destination routine. If there is not enough data available, 'csread' returns zero to indicate the end of data. 4. UCL FACSIMILE SYSTEM Now we discuss the implementation of the computerised facsimile system developed in the Department of Computer Science at UCL. This system has several components. Since the total system is a modular and multi-process one, a specific system must be built up for a specific application. The way that this is done is discussed in section 4.1. The specific devices and their drivers are described in section 4.2. The system can be attached to a number of networks. In the UCL configuration, the network interface can be direct to SATNET [22], SERC NET [23], PSS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -