incremental development of an hdlc entity in esterel

15
Computer Networks and ISDN Systems 22 (1991) 35-49 35 North-Holland Incremental development of an HDLC entity in Esterel Grrard Berry CMA-ENSMP and INRIA, Sophia-Antipolis, 06565 Valbonne, France Georges Gonthier * A T&T Bell Laboratories, Murray Hill NJ 07974, USA Abstract Berry, G. and G. Gonthier, Incremental development of an HDLC entity in Esterel, Computer Networks and ISDN Systems 22 (1991) 35-49. Esterel is a new parallel programming language based on a model of perfectly synchronous parallelism and communication. Because this model is naturally deterministic, it provides an excellent framework for the modular decomposition of programs that engage in complex patterns of deterministic interaction, such as protocol entities. Furthermore, because the Esterel compiler performs all the scheduling and synchronization at compile-time, modular programs with lots of subprocesses and internal communication can be just as efficient as monolithic sequential state machines. A restricted model of an HDLC entity is used to illustrate the new programming style that is made possible by these features. An Esterel program is developed in several steps, starting from a simple restricted case, and then adding features and complexity. The emphasis is first on design as we develop a program architecture that captures the basic procedures of the protocol in independent modules; then it shifts to maintenance as we add new features into the initial architecture by plugging new modules into the base program. Keywords: protocol, specification, Esterel, modularity, communication, synchrony, reactive systems, program development, HDLC, automata, compiling techniques. 1. Introduction The Esterel language [3] was designed for writ- ing reactive programs, i.e., communicating pro- grams whose correct operation depend on the exact ordering of input and output events. Com- munication protocol entities are good examples of reactive systems: they must realize precise and often complex exchanges of messages and must deal with multiple priorities and timeouts. On the other hand, computer operating systems are not reactive, as they can arbitrarily defer calls. The object of this paper is to show how the special features of Esterel can be used to derive a clean and modular description of an HDLC entity. * Current address: INRIA Rocquencourt, BP 105, 78153 Le Chesnay Cedex, France. The main Esterel feature is perfect synchrony: Esterel processes communicate as if their basic control and data operations took no time. The second main Esterel feature is broadcasting: an emitted signal can be received by any number of receivers in scope. Together these features imply that the timing of any action or subtask of a given program depends only on the timing of the exter- nal inputs of the program. Hence parallel com- position of two subtasks is deterministic in Esterel since the subtasks.have the same timing. Interrupt- ing a task at any given time t has a precise, deterministic meaning: the task is allowed to per- form actions exactly up to t (or strictly before, both forms are available). Instantaneous control flow is therefore atomic, so most correctness argu- ments still hold even in the presence of interrupts. Finally, since every action is pinned down to an 0169-7552/91/$03.50 © 1991 - Elsevier Science Publishers B.V. All fights reserved

Upload: gerard-berry

Post on 21-Jun-2016

213 views

Category:

Documents


0 download

TRANSCRIPT

Computer Networks and ISDN Systems 22 (1991) 35-49 35 North-Holland

Incremental development of an HDLC entity in Esterel

Grrard Berry CMA-ENSMP and INRIA, Sophia-Antipolis, 06565 Valbonne, France

Georges Gonthier *

A T&T Bell Laboratories, Murray Hill NJ 07974, USA

Abstract

Berry, G. and G. Gonthier, Incremental development of an H D L C entity in Esterel, Computer Networks and ISDN Systems 22 (1991) 35-49.

Esterel is a new parallel programming language based on a model of perfectly synchronous parallelism and communicat ion. Because this model is naturally deterministic, it provides an excellent framework for the modular decomposit ion of programs that engage in complex patterns of deterministic interaction, such as protocol entities. Furthermore, because the Esterel compiler performs all the scheduling and synchronization at compile-time, modular programs with lots of subprocesses and internal communicat ion can be just as efficient as monolithic sequential state machines.

A restricted model of an HDL C entity is used to illustrate the new programming style that is made possible by these features. An Esterel program is developed in several steps, starting from a simple restricted case, and then adding features and complexity. The emphasis is first on design as we develop a program architecture that captures the basic procedures of the protocol in independent modules; then it shifts to maintenance as we add new features into the initial architecture by plugging new modules into the base program.

Keywords: protocol, specification, Esterel, modularity, communication, synchrony, reactive systems, program development, HDLC, automata, compiling techniques.

1. Introduction

The Esterel language [3] was designed for writ- ing reactive programs, i.e., communicating pro- grams whose correct operation depend on the exact ordering of input and output events. Com- munication protocol entities are good examples of reactive systems: they must realize precise and often complex exchanges of messages and must deal with multiple priorities and timeouts. On the other hand, computer operating systems are not reactive, as they can arbitrarily defer calls. The object of this paper is to show how the special features of Esterel can be used to derive a clean and modular description of an H D L C entity.

* Current address: INRIA Rocquencourt, BP 105, 78153 Le Chesnay Cedex, France.

The main Esterel feature is perfect synchrony: Esterel processes communicate as i f their basic control and data operations took no time. The second main Esterel feature is broadcasting: an emitted signal can be received by any number of receivers in scope. Together these features imply that the timing of any action or subtask of a given program depends only on the timing of the exter- nal inputs of the program. Hence parallel com- position of two subtasks is deterministic in Esterel since the subtasks.have the same timing. Interrupt- ing a task at any given time t has a precise, deterministic meaning: the task is allowed to per- form actions exactly up to t (or strictly before, both forms are available). Instantaneous control flow is therefore atomic, so most correctness argu- ments still hold even in the presence of interrupts. Finally, since every action is pinned down to an

0169-7552/91/$03.50 © 1991 - Elsevier Science Publishers B.V. All fights reserved

36 G. Berry, G. Gonthier / Incremental development

i npu t event, rea l - t ime clocks can be mode led fai th- fully by s imple events.

Our goal is to deve lop a parallel, modular, and

incremental p r o g r a m for an H D L C enti ty, using the synchronous para l le l i sm and c o m m u n i c a t i o n p rov ided by Esterel. N o w m o d u l a r p r o g r a m m i n g does not s imply reduce to carving up a p r o g r a m into small pieces. Care must be taken that each m o d u l e have a def in i te function: a clear, s tand- a lone behavior . The in te rconnec t ion of modu les should also follow the same rule: every subassem- b ly should pe r fo rm a clear funct ion; large unst ruc- tu red nets should be avoided. Thus the true goal of m o d u l a r design is to f ind an architecture that cap tures the true s t ructure of the system. The true test of a design is its extensibility: modi fy ing any one feature should on ly in t roduce local changes in the archi tec ture and modules , and add ing features should only involve add i t ions to the archi tec ture wi th l i t t le o r no change to the base modules .

Esterel suppor t s modu la r i t y in a n u m b e r of ways. Because any set of s imul taneous ac t ions is a tomic , m o d u l a r decompos i t i on is not cons t ra ined by a tomic i ty . Hence it is poss ib le to very precisely i sola te in a modu le the ac t ions tha t are par t of its funct ion, and then use the language ' s synchroniza- t ion facil i t ies to make sure that s imul tane i ty is preserved. Fu r the rmore , because all the synchroni - za t ion can be resolved at compi le - t ime, no ef-

f iciency is lost; in fact qui te of ten a m o d u l a r p r o g r a m will p roduce the same code as a mono- l i thic one. The ha l lmark of all this is that Esterel p rog rams are genera l ly free of code duplication:

the dup l i ca t ion is done by the compi le r when it extracts the under ly ing finite s ta te mach ine f rom the p rogram. F ina l ly , because signals are b r o a d - cast, the behav ior of a modu le can be closely mon i to r ed s imply by spying on its outputs . Con- versely, since this behav io r is ent i re ly de t e rmine d by the modu le inputs , it can be con t ro l l ed s imply by f i l ter ing them. Al l of this can be done wi thout any change to the m o d u l e itself.

The mul t iway synchron iza t ion of L O T O S [5] a l lows cont ro l over the ex te rna l behav io r or a modu le in a somewha t s imi lar way. However , be-

cause of the pervas ive a synch rony and nonde - t e rmin i sm in LOTOS, this con t ro l does not ex tend to the in te rna l behavior . N o n d e t e r m i n i s t i c con- structs can on ly be con t ro l l ed by cons t ra in ing their ou tputs ; thus con t ro l can be lost if there is h idden in terna l communica t ion . Also, i t is gener- al ly not poss ib le to preserve a tomic i ty across m o d - ule boundar ies , since cons t ruc t s such as enab le or d i sab le prevent synchron iza t ion be tween their op- erands .

In this p a p e r we focus on the cod ing of a p ro toco l en t i ty for a small set of H D L C proce- dures (the BAC 2,8 procedures) , which we de-

G6rard Berry received the engineering degrees from ~ole Polytechnique in 1970 and from F_cole des Mines de Paris in 1973; he received the degree of Docteur 6s-Sciences from University Paris VII in 1979.

He is currently responsible for a joint project between INRIA and Ecole des Mines in Sophia-Antipolis (France), called "Parallelism, Synchronization, and Real-Time". His present research interests include mathematical semantics of programming languages and process algebras, synchronous programming lan- guages design and implementation, and high-level hardware generation.

G. Berry belongs to the editorial board of the journals "Information and Computation'; "'Mathematical Structures in Computer Science ", and "Science of Computer Programming ".

Georges Gonthier is a graduate of the l~cole Normale Sup6rieure in Paris. He received his Malse d'Informa- tique from Universit6 Paris VII in 1983, and his Doctorat from Universit~ Paris-Sud in 1988.

After spending three years as a Member of Technical Staff at AT&T Bell Laboratories, he is now a researcher at INRIA in Paris. His current research interest include mathematical semantics for programming languages, compiling techniques, compiling techniques, and algorithm and protocol design.

G. Berry, G. Gonthier / Incremental development 37

scribe in Section 2. We start by describing the program for a basic entity with no support for error recovery in Section 4 (Section 3 describes the interface of the program). This allows us to con- centrate on the basic structure of the program without undue attention to the details of specific features. Then in Section 5 we show how each missing feature can be coded as a separate module that can be independently plugged into the initial architecture. Finally we will briefly review the quality of the code generated for our programs by the Esterel v3 compiler.

Esterel is an imperative language derived from the familiar Pascal syntax, and we will be explain- ing in some detail its more unusual synchroniza- tion properties; however, a full introduction to Esterel would take us out the scope of this paper, for which we refer the reader to [3]. Also, a detailed analysis of the mathematical model and implementation of the language can be found in

[21.

2. A short description of the HDLC protocol

H D L C is a complex full-fledged protocol that specifies the data exchanges right down to the bit encoding schemes. We will not go into such detail, concentrating on the logical aspects instead. We will only implement the procedures for asynch- ronous balanced (ABM) data transfer, thus put- ting aside the connect ion/disconnect ion proce- dures and the other transfer modes. A complete description of the H D L C protocol can be found in [4]; [6,7] contain more accessible descriptions.

In the set-up we consider, the protocol is to ensure reliable full-duplex transmission of data between two users A and B through an estab- lished, but unreliable full-duplex line. This is done by inserting a protocol entity between each end- user and the line, as shown in Fig. 1. The two entities will exchange control information along with user messages, so that reliable transmission is achieved. Although the line and users are asynch- ronous the entities are reactive, and it is one of these entities that we shall be programming.

Fig. 1. Protocol Net-Up

H D L C is a typical sliding-window protocol. Let us describe how it operates in a transmission from A to B: • Entity A attributes a sequence number N(S) to

each message that user A hands it, packages each message and its N(S) in a data frame (an Information-frame), and transmits that to B.

• Entity B accepts / - frames from A in ascending N(S) order, and forwards their data contents to user B.

• Entity B also periodically echoes back to A the next message number it is expecting, N(R). Thus when A receives an N ( R ) value, it knows that a// messages with an N ( S ) ~< N ( R ) have been received correctly by B (they are acknowl- edged).

• To cater to finite frame formats, message num- bers are actually counted mod 8 (or 128 in some variants). To avoid number confusion, A keeps all pending message numbers within an emission window whose length is less than the modulus. Thus when there are too many unacknowledged messages entity A performs flow control to stop intput from user A. When messages finally are acknowledged, the window can be moved and new input will be accepted.

Transmission from B to A works exactly the same, and both will be running concurrently. There are two ways B can send N ( R ) acknowledgements to A: • either in an RR-type S-frame (Receive Ready

Supervisory frame), • or as a piggyback, as part of an / - f rame that it

is sending to A. Thus in normal full-duplex operation there is very little need to exchange S-frames for acknowledge- ments. Their use is mostly confined to error re- covery: • A REJ (REJect) frame from B indicates that B

has received an out-of-sequence frame from A, so that A should retransmit all unacknowledged frames since a frame has been lost (a go-back- to-N discipline).

• A command frame from B (see below) with the P (Polling) bit set is an enquiry into A's recep- tion status. It requires a preemptive response by A: a response frame with the F (Final) bit set. This checkpointing mechanism is typically used after a t imeout or abnormal event.

There are other H D L C features and related frame types that we will not consider here: connec t ion /

38 G. Berry, G. Gonthier / Incremental development

[ B f I N ( S ) N(R) [ P I message

s

A S [ RR N(R) I F

A S IREJ N(R) F I Fig. 2. HDLC Frame Types.

I frame

RR command frame

RR response flame

RE/frame

disconnection procedures and unnumbered frames, output flow control and RNR (Not Ready) frames, SREJ (Selective REJect) frames. All could be added to our basic design, but the additional complexity would get beyond the scope of this paper.

The different frame types we will be using are summed up in Fig. 2. All frames bear an address. If it is the address of the recipient, the frame is a command, otherwise it is the address of the emitter, and the frame is a response (Figure 2 shows frames sent by A). Only commands have a P bit, and only responses have an F bit. All frames carry an N(R) value and a P or F bit. /-frames carry a message and N ( S ) value, and S-frames carry only their type (RR or RE./, in our case). There are additional restrictions on commands and responses: REJ frames can only be responses, and I frames can only be commands (this is option 8 of the BAC 2,8 procedures we are cod- ing; option 2 is the use of REJ frames).

3. The program interface

An Esterel program interacts with its environ- ment through an abstract interface consisting of a set of input and output signals. The environment emits input signals when some external event has to be processed (e.g., an incoming frame, a time- out, user data to send), and the Esterel program reacts instantly by emitting some output signals that operate on the environment (e.g., by emitting a frame, delivering data, toggling flow control).

Given this "logical" interface, it is possible to write and compile Esterel programs independently of the actual representation of events. The v3 compiler simply produces a set of sequential pro-

cedures that emit and process input signals; these call back external procedures to emit output sig- nals. The burden of gathering events and manag- ing asynchronous hardware and software is placed with the operating system, where it belongs.

Similarly, the only data definitions in Esterel are external abstract data type declarations, and predefined types are kept to a minimum (booleans, integers), so that programs are independent of data structure considerations. The actual defini- tions of these data types have to be linked to the procedures produced by the compiler, along with the output procedures. The set of all these declara- tions constitutes the data interface of the program.

Our general modularity principles apply to the design of the signal and data interfaces. Specifi- cally, we should be careful to place functions where they can be most naturally implemented.

3.1. The signal interface

The H D LC entity accepts and delivers data messages from and to the user process, exchanges S- and /-frames with the distant entity through the unreliable line, and depends on real time for timeouts. Figure 3 illustrates the Esterel signal interface that implements these connections.

The interface to the user process is obvious: a USER_INPUT input signal to receive date from the user, two outputs X_0N and X_0 F F to provide flow control of this input, and a USER_OUTPUT to

gS tit

1

ENTITY

~ \ TTT FRAk~ I_li~ P.IJ_line

N_S_line RR_line N-P,_IiAe P_line E N D ~ ~ line

Fig. 3. The HDLC Entity Interface.

40 G. Berry, G. Gonthier / Incremental development

transmission and reception, the latter including the handling of S-frames. This yields very poor modularity, because the two tasks interact heavily as they compete for the shared output line. The standard solution is to push down the problem to the next lower level by introducing some kind of F IFO with priority. This is not only not modular

but also fairly inefficient: much of the sequential progression in the transmission module is dupli- cated in the FIFO, and messages may be sent needlessly before retransmission because of the lack of synchronization.

A better approach is to tackle the problem head-on, include the F I F O functionality in the

I WINDOW

EMPTY

X_ON X_OFF

11 WINDOW

~ ' ~ A G E R

I i i N_A N_U BUFFER

~ 1 1 ~ EMISSION

MANAGER

1 l FRAME I~D_FRI~IE

USER_INPUT USER_OUTPUT

, - -N_R

HDLC ENTITY

I FRAME

RECEIVER

I ]

I_line N_S_line N_B_line

X_ON X_OFF USER_INPUT

USER INPUT

HANDLER k WINDOW MANAGER

I 1 T N_U BUFFER N_A

WINDOW

EMPTY N_A N_U BUFFER EMISSION MANAGER

1 1 ' !

I r ! I w •

I FRAME -- TEST_LINE "--'4 LINE

EMITTER ~ LINE_FREE -- MANAGER

N...R.~INE

N_R

FRAME END..FladUflg

Fig. 4. The Basic HDLC Entity Architecture.

G. Berry, G. Gonthier /Incremental development 41

entity, and look for another modular decomposi- tion. Clearly the reception of /-frames (without responses) does not depend on transmission, so it is a natural module. Now the /-frame emission process must get its data from a buffer, since emission may lag behind user input because of sending delays or retransmission. The entire 1- frame emission process is bounded by the buffer range, (i.e., the emission window), which has to be computed from inputs and acknowledgements. This computation does not depend on emission, nor does input flow control, and since the two are tightly coupled they naturally belong to a separate module. The remaining functions all pertain to frame emission, and do not depend directly on user input, so they also form a natural module, and there we have our decomposition.

4.2. The local signals

Since parallelism is internalized in Esterel, the main module will consist of three modules I_FRAME_RECEIVERp WINDOW_MANAGER and EMISSION_MANAGER, together with the declara- tion of the local signals through which they com- municate, e.g., we need a BU F FER signal to convey the buffer contents to the EMISSION_MANAGER.

Valued signals are the only means of communi- cation between parallel modules in Esterel. The value ?BUFFER of the BUFFER signal is precisely defined at each instant t as the value B of the last emi t BUFFER (B) that was executed on or be- fore t (multiple simultaneous emissions are disal- lowed here). The perfect synchrony ensures that this defines the same value everywhere in the program, so that the value of BUFFER is always available, and always up to date!

The down side of this is that e m i t BUFFER (APPEND ( ?USER_ INPUT. ?BU F FER) )

is nonsense in Esterel: according to the above definition, ?BUFFER should be equal to APPEND (?USER_INPUT.?BUFFER) on the instant the emi t is executed. Thus we have to maintain the value of the buffer in a local shadow variable BU F FER which has the usual imperative behavior and cannot be shared (variables and signals have separate name spaces). Every update must be broadcast by reemitting the BUFFER signal. This local inconvenience is a small price to pay for the strong global properties of perfect synchrony.

Now it may seem a little extreme to send an entire buffer on a signal, but with the Esterel compiling scheme valued signals have the same efficiency as shared variables (because they are compiled into them!), and the local variable is easily optimized out by copy-elimination [1].

4.3. Protocol counters

We also need three signals to convey to EMIS- SION_MANAGER the sequence numbers for the piggybacked acknowledgement and the buffer boundaries (the window): • N_R: the sequence number of the next message

the entity expects to receive from the line. • N_A: the greatest N ( R ) value received as yet,

that is, the sequence number of the next mes- sage the remote entity expects, as far as this entity knows.

• N_U: the sequence number to be attributed to the next user-input message.

The window is the half-open interval [?N_A,?N_U[, and ?BUF F ER contains exactly the messages with sequence numbers in the window. Since all se- quence number signals hold future values (they always represent the next value of something), they all initially have the same value ZERO.

The computation of N_R is a natural part of I_FRAME_RECEIVER. The other three signals suggest dividing window management into three concurrent subtasks: receiving and validating acknowledgements, controlling user input, and buffering user messages, which will naturally han- dle the respective computations of N_A,N_U, and BUFFER.

Now Esterel valued signals also carry control information, just as unvalued ones. A process can thus wait for the emission of a valued signal, or even test for it. Signals N_R, N_A, and N_U are really counters that are never reset. We make the further commitment that they should only be emitted when their value actually increases. Thus the emission will coincide exactly with respec- tively the successful reception of a new message the acceptance of new user input, and the acknowledgement of a pending message. This way BUFFER_MANGER and EMISSION_MANAGER can simply synchronize on these signals to determine when new input or acknowledgements arrive.

42 G. Berry, G. Gonthier / Incremental development

4.4. The idle state

It is most usual to single out the "idle" state of an entity in a specification, because of the markedly different behavior of almost all trans- mission functions in that state, especially error recovery. Thus we should take the idle state into account if we want our basic architecture to be easily extensible, even though we have little need for this distinction here since we have no error recovery.

Here transmission is idle exactly when the window is empty (?N_A=?N_U). This condition can be tested anywhere in the program, but for good modularity it should be checked in just one place, and the ACKNOWLEDGEMENT_HANDLER module is the most natural spot. Therefore we include in that module's interface a WINDOW_ EMPTY output that broadcasts the onset of the idle condition. Clearly we leave the idle state when new input arrives, i.e., when N_O is emitted.

Since we don' t care about acknowledgements in the idle state, we can test for WINDOW_EMPTY inside ACKNOWLEDGEMENT_HANDLER itself, and wait for new input before processing the next N _ R _ l i n e occurrence, as is done in the annex code. The p r e s e n t WINDOW_EMPTY test is true if the signal is emitted at the same instant the test is executed. Since control transfers instantly from both e m i t WINDOW_EMPTY statements to the p r e s e n t , the test is therefore true whenever the window is emptied.

Now consider/-frame emission. Initially we are in the idle state so we must wait for new input before we can do anything, and we return to the idle state whenever the window is emptied. In between, we are sending /-frames for all the mes- sages in the window, starting from the first. This is a clearly defined function that we will be able to reuse easily in more elaborate emission proce- dures, so it belongs in a separate BASIC_I_ FRAME_SENDER module. Therefore/ - f rame emis- sion is implemented by the four lines of the I_FRAME_EMITTER module in the annex. The loop e a c h construct preempts and interrupts the SENDER when the window is emptied, return- ing the EMITTER to its initial idle state. It ensures that the SENDER will not perform any actions on the instant this happens, a very strong property that will be used several times in the next section.

4.5. The line state

All that is left now is the SENDER module. Let us start with a naive specification: start sending the first frame (emit FRAME), wait for END_FRAME, if this is the last frame wait for new input, and finally start over with the next frame. This is easily coded, using a local variable N_S to track the sequence number of the next frame to send.

Alas, this specification is wrong, because it is based on the assumption that the SENDER is the only module sending frames. Clearly this is incor- rect in the presence of polling or response fea- tures, and even in this simple case it is false because the EMITTER module creates several in- stances of the SENDER. Because sending a frame takes time two consecutive instances may conflict even though they cannot exist simultaneously. The proper conclusion is that managing the line state is a distinct function requiring a distinct module, and that emission management is really a combi- nation of this and o f / - f r a m e emission.

We need a LINE_FREE signal to convey the line status to the sender, and a TEST_LINE signal to allow the sender to probe the line status asynchronously. With this architecture, which is really a little bus accesss protocol, the sender specification becomes: probe the line, if free send the next frame, wait for the line to clear, wait for new input if need be, and start over. The code in the annex also makes sure that N_A does not overtake N_S while waiting for a free line.

The line module must emit LINE_FREE in its "free" state, initially and on every probe. This is readily accomplished by a l o o p e a c h , but the "free" state must be carefully defined because the sender reacts instantly to L I N E_ F R E E. The line is free from the instant END_FRAME occurs up to and including the instant a frame is sent. There- fore the line may be free for just one instant, and control may traverse instantly the free state. The precision of the Esterel control structures can nat- urally express these fine details: leaving the free state through a t r a p allows the parallel Loop e a c h code to execute at the very instant this occurs, and the i m m e d i a t e keyword allows this to happen on the very instant the state is entered.

Note that control will bounce back and forth instantly between the line and sender modules.

G. Berry, G. Gonthier / Incremental development 43

This justifies the use of the p r e s e n t test in the sender, and ensures that no atomicity is lost. Moreover, because the Esterel compiler traces all control paths during its code generation, it can completely resolve these kinds of instantaneous dialogues, which are thus optimally efficient since they generate no code at all!

5. The other features

In this section we show how we incorporate three error recovery features into our basic design: S-frame responses, retransmission on RE J-frames, and recovery on timeouts. We implement these features in separate modules that can be simply "plugged" independently into the basic architec- ture, even though they can have quite subtle com- bined behaviors.

5.1. Responses

The most delicate point in implementing re- sponses is that they need to have priority over normal /-frames, but fortunately this is easy to realize in our EMISSION_MANAGER architecture. All we need to do is filter the L I N E F R E E input of I_FRAME_EMITTER. This is done by renaming the output of LINE_MANAGER into a new signal SHARED_LINEFREE, and letting RESPONSE EMITTER generate LINE_FREE by echoing SHARED_LINE_FREE while it does not have a frame to send.

Also, we implement two kinds of H D L C re- sponses: REJ frames that signal out-of-order I- frames, and F-bit responses to P-bit polling com- mands. We allow a single frame to carry both responses (when possible) by using valued signals to store the frame fields; this removes the need for an output queue for responses. Exiting and restart- ing the local signal declaration after the frame has been sent allows the fields to be reinitialized in- stantly, since different instances of a signal can have different values simultaneously.

Finally, note that the test for sending rejects does not require any change to I FRAME_RE- CEIVER. It is based on the simple remark that a f rame is out of sequence if and only if I_FRAME_RECEIVER does not emit N_R in- stantly when N_S_ l i ne is received, and that this is testable is synchronous Esterel!

5.2. Retransmission on reject

A retransmitting sender is clearly an extension of the normal sender; therefore to add retransmis- sion to our basic architecture all we need to do is change the call to a BASIC_I_FRAME_SENDER to a call to a more elaborate I_FRARE_SENDER_ W I T H_ R E J E C T module. Moreover we can directly reuse the functionality of the basic module: to force the basic sender to retransmit, we can simply interrupt it and restart it afresh.

Retransmission is generally triggered by REJ_Line, but we must be cautious to avoid retransmission if the sequence number is invalid or the REJ is a duplicate (the latter can cause livelock). This is done with a boolean variable NOTREJECTED which is true when no rejects with a sequence number in this window have been received. Note that we need not care about rejects that acknowledge the entire window: these are na tura l ly handled by the p r e e m p t i o n in I_FRAME_EMITTER.

5.3. Timeout recovery

Rejects provide some form of error recovery, but some timeout mechanism is always necessary to ensure reliability. Timeouts are handled here by interrupting the normal transmission, repeatedly polling the remote entity with RR-commands whose P-bit is set until an F _ l i n e response is received, and then retransmitting any unacknowl- edged frames.

T h e in se r t i on of the R E L I A B L E _ I FRAME_SENDER module that accomplishes this is entirely similar to that of I F R A M E S E N D E R _WITH_REJECT, and the coding of the module is straightforward, since the polling cannot conflict with the emission. As above, we don' t have to worry about the case where the polling response acknowledges the entire window, thanks to the preemption by W I N DOW_ EM PT Y.

The only point worth noting is the interaction between this module and the reject management. Since resynchronization clears the entire round-trip path, the first reject after resynchronization can- not be a duplicate. This is taken into account here simply by the fact that restarting I_FRAME_SEN- DER_WITH_REJECT reinitializes the NOT_RE- J E C T E D variable.

44 G. Berry, G. Gonthier / Incremental development

6. The compiled code

The Esterel v3 compiler will transform this concurrent modular program into a sequential un- structured automaton by tracing all possible con- trol paths and identifying all possible input states. The main advantage of this technique is that the transitions of this automaton are time-optimal, since they only contain unavoidable data manipu- lation statements. Indeed, all the constructions that we introduced by our modular decomposition (local signals, shadow variables, instantaneous di- alogues) produce no code whatsoever.

On the other hand the final code contains a large amount of replication: the bluntness of the automated process compounds the inherent prob- lem of finite-state implementation. Thus the ef- ficiency of the compiler is truly measured by the size of the automaton. Using the Esterel v3r4 compiler, we got the following sizes for our pro- gram:

Version States Actions Calls

basic 7 35 298 + response 14 41 1403 + rejects 14 46 1597 + timeouts 24 53 3125

calls can be removed. A much more important improvement can be obtained by noticing that the three topmost submodules are simply run in paral- lel and have an acyclic interconnection. This in- sures that they can be implemented by compiling separate procedures for each of them, and then calling these procedures in topological order. This requires that topmost local signals become exter- nal, therefore their emission will generate some code, so this is a tradeoff between code size and speed. This technique can be applied automati- cally by passing the " - c a s c a d e " option to the v3r4 compiler. Doing this for the largest, "reliable" program, we get

Module Actions Calis

WINDOW MANAGER 24 81 RECEPTION_HANDLER I0 14 EMISSION_MANAGER 31 833 Total: 65 928

Unfortunately, the technique cannot be extended to the other "glue" modules: communications be- tween respectively USER_INPUT_HANDLER and ACKNOWLEDGEHANDLER, and all submodules of EMISSION_MANAGER are cyclic.

The different versions are obtained by successively adding the features to the basic program.

Note that the number of states stays small: because of the synchrony, they are only generated by external communication, and therefore we do not get the rapid combinatorial explosion so fre- quent in asynchronous systems. Indeed the Esterel compilation tends to produce state-minimal au- tomata.

The "Actions" column contains the number of actions in the source code for each version, while the "Calls" column holds the number of actions in the object code (the automaton). Obviously there is a large duplication factor that grows with pro- gram complexity. However, because no "glue" code is introduced by modularity, the total size of the program remains moderate. Also note that it is functionality, not modularity, that costs: the basic module contains most of the code and actions of the reliable one, yet has less than a tenth of the calls.

The sizes can be improved; by running a copy analysis algorithm on the "reliable" version, 564

7. Conclusion

We have shown how the perfect synchrony of Esterel can be used to write an elegant, modular, and safe program for the H D LC data transfer. However, the final program which we presented here is only part of the story. The development of the program was considerably more complex than its final code or even the detailed comment in this paper might suggest; indeed this version is quite different from the one described in the original version of this paper. This complexity seems to be inherent to Esterel programming, for several rea- sons: • The reactive systems that Esterel is meant to

describe are generally both intricate and poorly (sometimes inconsistently) specified. Thus they are never easy to program, in any language whatsoever.

• Esterel has powerful control and communica- tion structures that are used not only to imple- ment the external behavior of the system, but also to express the logic of the algorithm that

G. Berry, G. Gonthier / Incremental development 45

generates it. Of ten two construct ions will gener- ate exactly the same code but have completely different structures. Such flexibility is unthinka- ble in most other languages, where one has to be content with implement ing as simply as pos- sible the specified behavior. It adds complexi ty to p rogram development, since one has con- stantly to determine the true structure of the underlying algorithm.

• Once a p rogram structure has finally been de- cided on, it has to be revised to take into account efficiency considerat ions such as code and state size. Thus, even though Esterel pro- grams do not involve explicit states, the states of the program have to be identified to check the efficiency of the compil ing process. This is still very different f rom the more classical state-table specification method: here states are determined by the algorithm, not the basis for describing it.

In conclusion, Esterel trades some programming complexi ty to get better readabili ty and safety. For applications such as protocols where reliabil- ity is at such a high premium, this is certainly an excellent tradeoff.

References

[1] A.V. Aho, R. Sethi and J.D. Ullman, Compilers--Princi- ples, Techniques, and Tools (Addison-Wesley, Reading, MA).

[2] G. Berry and G. Gonthicr, The synchronous programming language ESTEREL: design, semantics, implementation, INRIA report 842, Sophia-Antipolis, France (1988).

[3] G. Berry, P. Couronne, and G. Gonthier, Synchronous programming of reactive systems: an introduction to ESTEREL, in: K. Fuchi and M. Nivat, eds., Programming of Future Generation Computers (North-Holland, Amster- dam, 1988).

[4] International Organization for Standardization, Data Com- munication, High Level Data Link Control, IS 7809: Con- solidation of Classes of Procedures (1984).

[5] International Organization for Standardization, Informa- tion Processing Systems, Open Systems Interconnection, IS 8807: LOTOS: A Formal Description Technique Based on the Temporal Ordering of Observational Behavior (1988).

[6] M. Schwartz, Telecommunication Networks: Protocols, Mod- elin~ and Analysis (Addison-Wesley, Reading, MA, 1987).

[7] A. Tannebaum, Computer Networks (Prentice-Hall, En- glewood Cliffs, N J, 1988).

46

Annex: The Esterel Code

G. Berry, G. Gonthier / Incremental development

To shorten this annex, we omit interface declarations of the modules, and we omit the "glue" modules HDLC_ENTITY, WINDOW_MANAGER, and EMISSION_MANAGER, which simply consist of the parallel composition of their submodules.

module I_FRAME_RECEIVER:

var N_R:=ZERO : NUMBER in emit N_R (N_R); every I_line do

if ?N_S_line=N_R then emit USER_OUTPUT (?I_line); call INCREMENT (N_R)(); emit N_R (N_R)

end end

end.

module USER_INPUT_HANDLER: . ° .

var N_U:=?N_A : NUMBER in emit N_U (N_U); emit X_ON; loop

await USER_INPUT; call INCREMENT (N_U) (); emit N_U (N_U); if SPAN(?N_A,?N_U)=WINDOW_SIZE then

emit X_OFF; await N_A; emit X ON

end end

end.

moduLe BUFFER_MANAGER: . . .

va r BUFFER:=EMPTY_BUFFER(WINDOW_SIZE) : BUFFER i n loop

emi t BUFFER (BUFFER); await

case N_U do call ENQUEUE (BUFFER) (?USER_INPUT) case N_A do call PURGE (BUFFER) (SPAN (?N_A,?N_U))

end end

end.

G. Berry, (7, Gonthier / Incremental deoelopment 47

module ACKNOWLEDGE_HANDLER:

v a r N_A:=ZERO : NUMBER i n emit N_A (N_A); emit WINDOW_EMPTY; loop

present WINDOW_EMPTY then await N_U end; await N_R_line; if SPAN (?N_R_Iine,?N_U)<SPAN(N_A,?N_U) then

N_A:=?N_R_line; emit N_A (N_A); if N_A=?N_U then emit WINDOW_EMPTY end

end end

end.

module I_FRAME_EMITTER:

loop await N_U; copymodule BASIC_I_FRANE_SENDER

each WINDOW_EMPTY.

module BASIC_I_FRAME_SENDER:

vat N_S:=?N_A : NUMBER in loop

emit TEST_LINE; present LINE_FREE then

emit FRAME (I_FRANE (N_S, ?N_R, ACCESS (?BUFFER, SPAN (N_S,?N_U)))); call INCREMENT (N_S) ()

end; do

every N_A do call GUARD_UNDERFLOW (N_S) (?N_A,?N_U) end upto LINE-FREE; if N_S = ?N_U then await N_U end

end end.

module LINE-MANAGER: , . .

loop trap LINE_BUSY in

await immediate FRAME do exit LINE_BUSY end

II loop emit LINE_FREE each TEST_LINE

handle LINE BUSY do await END_FRAME

end end.

48 G. Berry, G. Gonthier / Incremental development

moduLe RESPONSE_EMITTER: , . .

Loop signaL RESPOND, FRAME_TYPE (S_FRAME_TYPE), F_BIT (boo lean) in

emit FRAME_TYPE (MR_RESPONSE); emit FRAME_TYPE (RR_RESPONSE(; emit F_BIT (faLse); trap RESPONSE_SENT in

every P_Line do emit F_BIT (true); emit RESPOND end II

II

every N_S_Line do present N_R else emit FRAME_TYPE (REJ); emit RESPOND end

end

do every SHARED_LINE_FREE do emit LINE_FREE end

upto RESPOND; emit TEST_LINE; awai t immediate SHARED_LINE_FREE; emit FRAME (S_FRAME (?FRAME_TYPE, ?N_R, ?F_BIT)) ; e x i t RESPONSE_SENT

end end

end.

module I_FRAME_SENDER_WITH_REJECT: var NOT_REJECTED:=true : boolean in

loop t rap RETRANSMIT in

copymoduLe BASIC_I_FRAME_SENDER I I

Loop do

every N_A do NOT_REJECTED := t rue end upto REJ_l ine; p resent N_A then e x i t RETRANSMIT end; i f NOT_REJECTED and ?N_R_line=?N_A then e x i t RETRANSMIT end

end handle RETRANSMIT do NOT_REJECTED := f a l se end

end end.

G. Berry, G. Gonthier / Incremental development 49

module RELIABLE_I_FRAME_SENDER: . , ,

Loop t rap RESYNCHRONIZE in

copymodule I_FRAME_SENDER_WITH_REJECT

II Loop

do awai t N_A ~ wa i t f o r a new acknowledgement

watching ACKNOWLEDGE_TIME_LIMIT MS t imeout e x i t RESYNCHRONIZE end

end handle RESYNCHRONIZE do

do loop

emit TEST_LINE; await immediate LINE_FREE; emit FRAME (S_FRAME (RR_COMMANDp ?N_R, true));

each RESYNCH_TIME_LIMIT MS upto F_line

end end.