107
Action Systems with Synchronous Communication
R.J.R. Back a and K. Sere b a Abo Akademi University, Department of Computer Science, FIN-20520 Turku, Finland, e-mail:
[email protected] b University of Kuopio, Department of Computer Science and Applied Mathematics, P.O.Box 1611, FIN-70211 Kuopio, Finland, e-mail:
[email protected] The action system framework for modelling parallel and reactive programs is extended by adding procedure declarations to action systems. This permits remote procedure calls to be modelled within the framework. Synchronous message passing communication, being a special case of remote procedure calls, can therefore also be handled within this framework. This extension is done almost at no extra cost in the logical treatment of programs. The renement calculus within which the renement of action systems is formalized can be used with a minor extension to reason about action systems with procedures, as the methods are already there. The treatment of procedures was originally designed with sequential programs in mind, but is applicable to the remote procedure mechanism proposed here. Keyword Codes: F.3.1; D.1.3 Keywords: Specifying and Verifying and Reasoning about Programs; Concurrent Programming
1. INTRODUCTION An action system is a parallel or distributed program where parallel activity is described in terms of events, so called actions. The actions are atomic: if an action is chosen for execution, it is executed to completion without any interference from the other actions in the system. Several actions can be executed in parallel, as long as the actions do not share any variables. Atomicity guarantees that a parallel execution of an action system gives the same results as a sequential and nondeterministic execution. The use of action systems permits the design of the logical behaviour of a system to be separated from the issue of how the system is to be implemented. The decision whether the action system is to be executed in a sequential or parallel fashion can be postponed to a later stage, when the logical behaviour of the action system has been designed. The construction of the program is thus done within a single unifying framework. The action systems formalism was proposed by Back and Kurki-Suonio [?]. Later similar event-based formalisms have been put forward by several other researcher, see for example the work of Chandy and Misra [?], who describe their UNITY framework and
108 Francez [?], who develops his IP-language. We will in this paper show that a simple extension of the action systems framework, adding procedure declarations to action systems, will give us a very general mechanism for synchronized communication between action systems. Both actions and procedure bodies are guarded commands. When an action in one action system calls a procedure in another action system, the eect is that of a remote procedure call. The calling action and the procedure body involved in the call are executed as a single atomic entity. We still have the possibility of shared variable communication also. As far as we know, procedures are not treated as communication mechanisms, as we do here, in any of the related frameworks. The action systems approach supports the stepwise renement paradigm for the construction of parallel and distributed systems. The renement calculus is a formalization of the stepwise renement method of program construction. It was originally proposed by Back [?] and it has been later studied and extended by several researchers, see [?, ?] among others. In recent years data renement within the renement calculus has been a topic for extensive research [?]. Originally, the renement calculus was designed as a framework for systematic derivation of sequential programs only. Back and Sere [?] extended the renement calculus for the design of action systems and hence, it was possible to handle parallel algorithms within the calculus. Back [?] made yet another extension to the calculus showing how reactive programs could be derived in a stepwise manner within it relying heavily on the work done in data renement. In both cases parallel and concurrent activity is modelled within a purely sequential framework. We shall here concentrate on reactive programs. Procedures were added to the renement calculus independently by Back [?] and Morgan [?], with slightly dierent ways in which parameter passing is handled. The basic idea in both cases is that essentially a procedure call is handled by substituting the procedure body for the call, after having made some necessary adaptions to account for parameter passing. By putting suitable constraints on the parameter passing mechanisms, procedure calls can be shown to be monotonic with respect to the renement relation. We show how data renement of reactive action systems as described in [?] is done in the presence of procedures. The advantage of a very general communication mechanism, like the one proposed here, is that it provides us with a high level way of describing the intended behavior of a parallel system. A concrete implementation can then be derived from the high level description by a sequence of correctness preserving renements within the renement calculus using the methods for renement of action systems with procedures developed in this paper. However, a general communication mechanism is not necessarily eciently implementable, but it is rened to some special case that can be implemented eciently. We proceed as follows. In section 2, we describe the action systems formalism together with the new extension of action systems that uses procedures. In section 3, we describe how action systems are composed into parallel systems. We also discuss here some implementation issues. In section 4, we show how action systems with procedures can be treated within the renement calculus. As a case study we have chosen to stepwise derive a sender-receiver system among a set of processes. This will be treated in section 5. We end in section 6 with some concluding remarks.
109
2. ACTION SYSTEMS FORMALISM 2.1. Action systems
An action system (with procedures) is a statement of the form A :: var v ; proc w j[ 1 xh := x1 0 xh 0; proc p1 = P1; ; pn = Pn ; do A1 [] Am od ]j: z The identiers x1 xh are the variables declared in A and initialized to x1 0 xh 0, p1 pn are the procedure headers, and Pi is the procedure body of pi , i = 1 n. Within the loop, A1 Am are the actions of A. Finally, z v and w are pairwise distinct lists of identiers. The list z is the import list, indicating which variables and procedures are referenced, but not declared in A. The lists v and w are the export lists, indicating which variables and procedures declared in A are accessible from other action systems. Procedure bodies and actions are arbitrary statements, and may contain procedure calls. The guard of a program statement S is the condition gS , dened by ;:::;
;:::; :::
:::
;:::;
;:::;
;:::;
;:::;
;:::;
;
gS = :wp(S ; false )
where wp is the weakest precondition predicate transformer of Dijkstra [?]. The statement S is said to be enabled in a given state when the guard is true in that state. The statement S is said to be always enabled, if wp(S false ) = false (i.e., gS = true ), and always terminating, if wp(S true ) = true Both procedure bodies and actions will in general be guarded commands, i.e., statements of the form C =g !S where g is a boolean condition and S is a program statement. In this case, the guard of C is g ^ :wp(S false ). If the body of each action of an arbitrary action system is always enabled, action systems coincide with the language of guarded commands. The body sC of C is dened by sC = if gC ! C [] :gC ! abort The local variables (procedures) of A are those variables xi (procedures pi ) that are not listed in the export list. The global variables (procedures) of A are the variables (procedures) listed in the import and export lists. The local and global variables (procedures) are assumed to be distinct. Hence, x \ z = ;, where x denotes the list of variables declared in A (no redeclaration of variables is thus permitted). Each variable may be associated with an explicit type. The state variables of A consist of the local variables and the global variables. A statement or an action is said to be local to an action system if it only refers to local variables of the action system. The procedures and actions are allowed to refer to all the state variables of an action system. Furthermore, each procedure and action may have local variables of its own. We consider three dierent parameter passing mechanisms for procedures, call-by-value, call-by-result and call-by-value-result. The parameter passing mechanism. Call-by-value ;
;
;
;
110 is denoted with p (val f ), where f stands for the formal parameters, call-by-result with p (res f ), and call-by-value-result with p (valres f ). For simplicity, we will here assume that the procedures are not recursive. The behaviour of a single action system is that of the guarded iteration statement Êx := x 0; do A1 [] Am od on the state variables [?]. The initialization statement is executed rst. After this, some enabled action is executed, and the loop statement is repeated. The do-loop terminates when there are no more enabled actions. The action system A below works as follows: as long as there are elements in the global import variable S , one of them will be assigned nondeterministically to a local variable x , as denoted by the nondeterministic assignment statement x := x (x 2 S ) [?]. Thereafter the element is removed from S and inserted into the global import variable R. The latter is carried out via a call to the local procedure Trans . A :: j[ var x 2 integer ; proc Trans (val v 2 integer ) = (R := R [ fv g) do S 6= ; ! x := x (x 2 S ); S := S ? fx g; Trans (x ) od ]j: S R :::
0
0
:
:
0
0
;
2.2. Denition of procedures
The meaning of a call on a parameterless procedure p = P in a statement S is determined by the substitution principle: S = S [P p ] i.e., the body P of procedure p is substituted for each call on this procedure in statement S. Procedures with parameters can be handled in a similar way by substitution. Let p (val x res y ) = P be a procedure declaration, where x denotes the formal call-by-value parameters and y the formal call-by-result parameters. Then a call on p with the actual parameters a b is removed by the substitution S = S [P p (a b )] where P is the statement j[ var x y ; x := a ; P ; b := y ]j Call to a procedure with call-by-value-result parameter passing mechanism can also be reduced to an ordinary statement as follows. Let p (valres x ) = P be a procedure declaration, where x denotes the formal call-by-value-result parameters. Then a call on p with the actual parameters a is removed by the substitution S = S [P p (a )] where P is the statement j[ var x ; x := a ; P ; a := x ]j =
;
;
;
0
=
;
;
0
;
:
0
=
;
0
:
111 The denition of procedures is studied more carefully in [?, ?]. Let p = (b ! T ) be a procedure and let a ! S ; p be an action that calls on p . Then the enabledness of this action is determined by the value of the action guard g (a ! S ; p ) = a ^ g (S ; p )
where g (S ; p ) is calculated as follows: = = = = = =
g (S ; p ) g (S ; (b ! T )) :wp(S ; (b ! T ); false ) :wp(S ; wp((b ! T ); false )) :wp(S ; b ) wp(T ; false )) :wp(S ; b ) :gT ) fassuming T always enabledg :wp(S ; :b )
If a procedure or action contains a call to a procedure that is not declared in the action system, then the behavior of the action system will depend on the way in which the procedures are declared in some other action system, which constitutes the environment of the action system as will be described below.
3. COMPOSING ACTION SYSTEMS 3.1. Parallel composition Consider two action systems A and B: A :: var v ; proc r j[ := x 0; proc p1 = P1; ; pn = Pn ; do A1 [] Am od ]j: z B :: var w ; proc s j[ := y 0; proc q1 = Q1; ; ql = Ql ; do B1 [] Bk od ]j: u where x \ y = ;, v \ w = ;, and r \ s = ;. Furthermore, the local procedures declared in the two action systems are required to be distinct. We dene the parallel composition A k B of A and B to be the action system C C :: var b ; proc c j[ x y := x 0 y 0; proc p1 = P1; ; pn = Pn ; q1 = Q1; ; ql = Ql ; do A1 [] [] Am [] B1 [] [] Bk od ]j: a where a = z [ u ? (v [ r [ w [ s ) b = v [ w c = r [ s . Thus, parallel composition :::
:::
:::
:::
;
;
:::
:::
:::
:::
;
;
will combine the state spaces of the two constituent action systems, merging the global
112 variables and global procedures and keeping the local variables distinct. The imported identiers denote those global variables and/or procedures that are not declared in either A or B. The exported identiers are the variables and/or procedures declared global in A or B. The procedure declarations and the actions in the parallel composition consists of the procedure declarations and and actions in the original systems. Parallel composition is a way of associating a meaning to procedures that are called in an action system but which are not declared there, i.e., they are part of the import list. The meaning can be given by a procedure declared in another action system, provided the procedure has been declared global, i.e., it is included in the export list. The behaviour of a parallel composition of action systems is dependent on how the individual action systems, the reactive components, interact with each other. We have for instance that a reactive component does not terminate by itself: termination is a global property of the composed action system. More on these topics can be found in [?].
3.2. Hiding and revealing Let var v1 v2; proc v3 v4 A : z be an action system of the form above, where z denotes ;
;
the import list and v1 v2 v3 v4 denote the export lists. We can hide some of the exported global variables (v2) and procedure names (v4) by removing them from the export list, A = Ê var v1; proc v3 A : z Hiding the variables v2 and procedure names v4 makes them inaccessible from other actions outside A in a parallel composition. Hiding thus has an eect only on the variables and procedures in the export list. The opposite operation, revealing, may also be useful. ;
;
;
0
:
0
3.3. Example
Consider a producer-consumer system var v j[ var S R 2 set of integer ; P rod k S nd k Rec k C ons ]j with four action systems P rod S nd Rec , and C ons executing in parallel. The variable S denotes a set of messages to be transmitted between the producer P rod and the consumer C ons . Similarly, the variable R denotes the set of messages received by the consumer action system C ons . The producer uses the services of the sender S nd for the actual communication. These two systems communicate through the variable S . The consumer receives the messages via the receiver process Rec . The receiver and the consumer communicate via the variable R. The variables v are some externally visible variables. We study next the action systems S nd and Rec more carefully: S nd :: j[ var x 2 integer ; do S 6= ; ! x := x (x 2 S ); S := S ? fx g; Trans (x ) od ]j: S Trans ;
;
;
0
:
0
;
Rec :: proc Trans j[ proc Trans (val v 2 integer ) = (R := R [ fv g) ]j : R The action system S nd communicates with the receiver Rec via the global procedure Trans , which is in the import list of S nd and in the export list of Rec . The two action
113 systems S nd and Rec are examples of reactive components. Therefore for instance the action system S nd does not terminate locally when S becomes empty, but rather it waits for new elements to appear in S . The parallel composition of S nd and Rec , T = S nd k Rec , is according to the rule above as follows: T :: proc Trans j[ var x 2 integer ; proc Trans (val v 2 integer ) = (R := R [ fv g) do S 6= ; ! x := x (x 2 S ); S := S ? fx g; Trans (x ) od ]j: S R We can now hide the procedure Trans , as it is only called by S nd . This gives us the system T : T :: j[ var x 2 integer ; proc Trans (val v 2 integer ) = (R := R [ fv g) do S 6= ; ! x := x (x 2 S ); S := S ? fx g; Trans (x ) od ]j: S R We can remove the procedure by substituting the procedure body in place of the procedure call and the actual parameter for the formal parameter of the procedure. Substitution gives T :: j[ var x 2 integer ; proc Trans (val v 2 integer ) = (R := R [ fv g) do S 6= ; ! x := x (x 2 S ); S := S ? fx g; j[ var v 2 integer ; v := x ; R := R [ fv g ]j 0
:
0
;
0
0
0
:
0
;
00
0
:
0
od
]j: S R Finally, removing the redundant local variable v and procedure Trans that is not needed anywhere, gives us the action system T : T :: j[ var x 2 integer ; do S 6= ; ! x := x (x 2 S ); S := S ? fx g; R := R [ fx g od ]j: S R; Because all these versions are equivalent in the producer-consumer system, we can rewrite the system as ;
000
000
0
;
:
0
var v j[ var S R 2 set of integer ; P rod k T k C ons ]j 3.4. Enabledness of an action ;
000
:
We permit procedure bodies to have guards that are not identically true. Hence, it is possible that an action which is enabled, calls a procedure in another action system, which then turns out not to be enabled in the state in which it is called. This situation is then the same as if the calling action had not been enabled at all, and had therefore
114 never initiated the call. In other words, the enabledness of an action is determined by the enabledness of the whole statement that is invoked when the action is executed, including enabledness of all procedures that might be invoked. The following is an example of this situation: Assume that the set R of the producerconsumer action system is bounded above by an integer L. This is reected in the action system Rec as follows: Rec :: proc Trans j[ proc Trans (val v 2 integer ) = (jRj L ! R := R [ fv g) ]j : R Let C =def x := x (x 2 S ); S := S ? fx g. We have for the sending action in S nd that S 6= ; ! x := x (x 2 S ); S := S ? fx g; Trans (x ) = fdenitions of C Trans g S 6= ; ! C ; j[ var v ; v := x ; (jRj L ! R := R [ fv g) ]j = fremoving local variable v g S 6= ; ! C ; (jRj L ! R := R [ fx g) = fdenition of guardg S 6= ; ^ :wp(C jRj L) ! C ; (jRj L ! R := R [ fx g) = fcalculation, denition of C g S 6= ; ^ jRj L ! x := x (x 2 S ); S := S ? fx g; R := R [ fx g Hence, the parallel composition of S nd and Rec is the action system T : T :: j[ var x 2 integer ; do S 6= ; ^ jRj L ! x := x (x 2 S ); S := S ? fx g; R := R [ fx g od ]j: S R Here the sending action is only enabled if S 6= ; and jRj L both hold. 0
0