Correctly Implementing Synchronous Message Passing in the Pi-Calculus By Concurrent Haskell’s MVars
Abstract
Comparison of concurrent programming languages and correctness of program transformations in concurrency are the focus of this research. As criterion we use contextual semantics adapted to concurrency, where may- as well as should-convergence are observed. We investigate the relation between the synchronous pi-calculus and a core language of Concurrent Haskell (CH). The contextual semantics is on the one hand forgiving with respect to the details of the operational semantics, and on the other hand implies strong requirements for the interplay between the processes after translation. Our result is that CH embraces the synchronous pi-calculus. Our main task is to find and prove correctness of encodings of pi-calculus channels by CH’s concurrency primitives, which are MVars. They behave like (blocking) 1-place buffers modelling the shared-memory. The first developed translation uses an extra private MVar for every communication. We also automatically generate and check potentially correct translations that reuse the MVars where one MVar contains the message and two additional MVars for synchronization are used to model the synchronized communication of a single channel in the pi-calculus. Our automated experimental results lead to the conjecture that one additional MVar is insufficient.
1 Introduction
Our goals are the comparison of programming languages, correctness of transformations, compilation and optimization of programs, in particular of concurrent programs. We already used the contextual semantics of concurrent (functional) programming languages to effectively verify correctness of transformations [(17), (24), (25)], also under the premise not to worsen the runtime [(31)]. We propose to test may- and should-convergence in the contextual semantics, since, in particular, it rules out transformations that transform an always successful process into a process that may run into an error, for example a deadlock. There are also other notions of program equivalence in the literature, like bisimulation based program equivalences [(28)], however, these tend to take also implementation specific behavior of the operational semantics into account, whereas contextual equivalence abstracts from the details of the executions.
In [(29), (32)] we developed notions of correctness of translations w.r.t. contextual semantics, and in [(33)] we applied them in the context of concurrency, but for quite similar source and target languages. In this paper we translate a synchronous message passing model into a shared memory model, namely a synchronous -calculus into a core-language of Concurrent Haskell, called .
The contextual semantics of concurrent programming languages is a generalization of the extensionality principle of functions. The test for a program is whether – i.e. plugged into a program context – successfully terminates (converges) or not, which usually means that the standard reduction sequence ends with a value. For a concurrent program , we use two observations: may-convergence () – at least one execution path terminates successfully, and should-convergence111An alternative observation is must-convergence (all execution paths terminate). The advantages of equivalence notions based on may- and should-convergence are invariance under fairness restrictions, preservation of deadlock-freedom, and equivalence of busy-wait and wait-until behavior (see e.g. [(33)]). () – every intermediate state of a reduction sequence may-converges. For two processes and , holds iff for all contexts : , and and are contextually equivalent, , iff and . Showing equal expressivity of two (concurrent) calculi by a translation requires that may- and should-convergence make sense in each calculus. Important properties are convergence-equivalence (may- and should-convergencies are preserved and reflected by the translation) and adequacy (see Definition 4.4), which holds if implies , for all -calculus processes . Full-abstraction, i.e. iff , only holds if the two calculi are more or less the same.
Source and Target Calculi.
The well-known -calculus [(16), (15), (28)] is a minimal model for mobile and concurrent processes. Dataflow is expressed by passing messages between them via named channels, where messages are channel names. Processes and links between processes can be dynamically created and removed which makes processes mobile. The interest in the -calculus is not only due to the fact that it is used and extended for various applications, like reasoning about cryptographic protocols [(2)], applications in molecular biology [(22)], and distributed computing [(14), (8)]. The -calculus also permits the study of intrinsic principles and semantics of concurrency and the inherent nondeterministic behavior of mobile and communicating processes. We investigate a variant of the -calculus which is the synchronous -calculus with replication, but without sums, matching operators, or recursion. To observe termination of a process, the calculus has a constant Stop which signals successful termination.
The calculus , a core language of Concurrent Haskell, is a process calculus where threads evaluate expressions from a lambda calculus extended by data constructors, case-expressions, recursive let-expressions, and Haskell’s seq-operator. Also monadic operations (sequencing and creating threads) are available. The shared memory is modelled by MVars (mutable variables) which are one-place buffers that can be either filled or empty. The operation takeMVar tries to empty a filled MVar and blocks if the MVar is already empty. The operation putMVar tries to fill an empty MVar and blocks if the MVar is already filled. The calculus is a variant (or a subcalculus) of the calculus [(24), (25)] which extends Concurrent Haskell with futures. A technical advantage of this approach is that we can reuse studies and results on the contextual semantics of also for .
Details and Variations of the Translation.
One main issue for a correct translation from -processes to -programs is to encode the synchronous communication of the -calculus. The problem is that the MVars in have an asynchronous behavior (communication has to be implemented in two steps: the sender puts the message into an MVar, which is later taken by the receiver). To implement synchronous communication, the weaker synchronisation property of MVars has to be exploited, where we must be aware of the potential interferences of the executions of other translated communications on the same channel. The task of finding such translations is reminiscent of the channel-encoding used in [(21)], but, however, there an asynchronous channel is implemented while we look for synchronous communication.
We provide a translation which uses a private MVar per channel and per communication to ensure that no other process can interfere with the interaction. A similar idea was used in [(13), (4)] for keeping channel names private in a different scenario (see [(11), (10)] for recent treatments of these encodings). We prove that the translation is correct. Since we are also interested in simpler translations, we looked for correct translations with a fixed and static number of MVars per channel in the -calculus. Since this task is too complex and error-prone for hand-crafting, we automated it by implementing a tool to rule out incorrect translations222The tool and some output generated by the tool are available via https://gitlab.com/davidsabel/refute-pi.. Thereby we fix the MVars used for every channel: a single MVar for exchanging the channel-name and perhaps several additional MVars of unit type to perform checks whether the message was sent or received (we call them check-MVars, they behave like binary semaphores that are additionally blocking for signal-operations on an unlocked semaphore). The outcomes of our automated search are: a further correct translation that uses two check-MVars, where one is used as a mutex between all senders or receivers on one channel, and further correct translations using three additional MVars where the filling and emptying operations for each MVar need not come from the same sender or receiver. The experiments lead to the conjecture that there is no translation using only one check-MVar.
Results.
Our novel result is convergence-equivalence and adequacy of the open translation (Theorems 4.5 and 4.8), translating the -calculus into . The comparison of the -calculus with a concurrent programming language (here ) using contextual semantics for may- and should-convergence in both calculi exhibits that the -calculus is embeddable in where we can prove that the semantical properties of interest are kept. The adaptation of the adequacy and full abstraction notions (Definition 4.4) for open processes is a helpful technical extension of our work in [(29), (32)].
We further define a general formalism for the representation of translations with global names and analyze different classes of such translations using an automated tool. In particular, we show correctness of two particular translations in Theorems 5.9 and 5.12. The discovered correct translations look quite simple and their correctness seems to be quite intuitive. However, our experience is that searching for correct translations is quite hard, since there are apparently correct (and simple) translations which were wrong. Our automated tool helped us to rule out wrong translations and to find potentially correct ones.
Discussion of Related Work on Characterizing Encodings.
There are five criteria for valid translations resp. encodings proposed and discussed in [(12), (10)], which mainly restrict the translations w.r.t. language syntax and reduction semantics of the source and target language, called: compositionality, name invariance, operational correspondence, divergence reflection and success sensitiveness. Compositionality and name invariance restrict the syntactic form of the translated processes; operational correspondence means that the transitive closure of the reduction relation is transported by the translation, modulo the syntactic equivalence; and divergence reflection and success sensitiveness are conditions on the semantics.
In our approach, we define semantical congruence (and precongruence) relations on the source and target language. Thus the first two conditions are not part of our notion of contextual equivalence, however, may be used as restrictions in showing non-encodability. We also omit the third condition and only use stronger variants of the fourth and fifth condition. Convergence equivalence as a tool for finding out may-and should-convergence is our replacement of Gorla’s divergence reflection and success sensitiveness. We do not define an infinite reduction sequence as an error, which has as nice consequence that synchronization could be implemented by busy-wait techniques.
Further Related Work.
Encodings of synchronous communication by asynchronous communication using a private name mechanism are given in [(13), (4)] for (variants of the) -calculus. Our idea of the translation similarly uses a private MVar to encode the channel based communication, but our setting is different, since our target language is Concurrent Haskell. Encodings between -calculi with synchronous and with asynchronous communication were, for instance, already considered in [(13), (4), (20), (19)] where encodability results are obtained for the -calculus without sums [(13), (4)], while in [(19), (20)] the expressive power of synchronous and asynchronous communication in the -calculus with mixed sums was compared and non-encodability is a main result. Translations of the -calculus into programming calculi and logical systems are given in [(3)], where a translation into a graph-rewriting calculus is given and soundness and completeness w.r.t. the operational behavior is proved. The article [(34)] shows a translation and a proof that the -calculus is exactly operationally represented. There are several works on session types which are related to the -calculus, e.g., orchard-yoshida:16 studies encodings from a session calculus into PCF extended by concurrency and effects and also an embedding in the other direction, mapping PCF extended by effects into a session calculus. The result is a (strong) operational correspondence between the two calculi. In cano-et-al:2017 an embedding of a session -calculus into ReactiveML is given and operational correspondence between the two languages is shown. Encodings of CML-events in Concurrent Haskell using MVars are published in Russell01 ; Chaudhuri09 . This approach is more high-level than ours (since it considers events, while we focus the plain -calculus). In Chaudhuri09 correctness of a distributed protocol for selective-communication w.r.t. an excerpt of CML is shown and a correct implementation of the protocol in the -calculus is given. The protocol is implemented in Concurrent-Haskell, but no correctness of this part is shown, since Chaudhuri09 focuses to show that CML-events are implementable in languages with first-order message-passing which is different from our focus (translating the -calculus into ).
Outline.
We introduce the source and target calculi in Sections 2 and 3, the translation using private names in Section 4, and in Section 5 we treat translations with global names. We conclude and discuss future work in Section 6. Due to space constraints most proofs are in the technical report schmidt-schauss-sabel:frank-60:19 .
2 The -Calculus with Stop
Interaction rule: (ia)
Closure: | If then |
We explain the synchronous -calculus milner-parrow-walker:92 ; milner-pi-calc:99 ; sangiorgi-walker:01 without sums, with replication, extended with a constant Stop sabel-schmidt-schauss-pistop:2015 , that signals successful termination. The -calculus with Stop and the -calculus without Stop but with so-called barbed convergences sangiorgi-walker:2001 are equivalent w.r.t. contextual semantics schmidt-schauss-sabel:frank-60:19 . Thus, adding the constant Stop is not essential, but our arguments are easier to explain with Stop.
Definition 2.1 (Calculus ).
Let be a countable set of (channel) names. The syntax of processes is shown in Fig. 3. Name restriction restricts the scope of name to process , is the parallel composition of and , the process waits on channel to output over channel and then becoming , the process waits on channel to receive input, after receiving the input , the process turns into (where is the substitution of all free occurrences of name by name in process ), the process is the replication of process , i.e. it behaves like an infinite parallel combination of process with itself, the process is the silent process, and Stop is a process constant that signals success. We sometimes write instead of as well as instead of .
Free names , bound names , and -equivalence in are as usual in the -calculus. A process is closed if . Let be the closed processes in . Structural congruence is the least congruence satisfying the laws shown in Fig. 3. Process contexts and reduction contexts are defined in Fig. 3. Let be the substitution of the hole in by . The reduction rule performs interaction and standard reduction is its closure w.r.t. reduction contexts and (see Fig. 3). Let denote -reductions and denotes the reflexive-transitive closure of . A process is successful, if for some .
Remark 2.2.
We do not include “new” laws for structural congruences on the constant Stop, like Stop | Stop equals Stop, since this would require to re-develop a lot of theory known from the -calculus without Stop. In our view, Stop is a mechanism for a notion of success that can be easily replaced by other similar notions (e.g. observing an open input or output as in barbed testing). However, it is easy to prove those equations on the semantic level. (i.e. w.r.t. as defined below in Definition 2.5).
As an example for a reduction sequence, consider sending name over channel and then sending name over channel :
For the semantics of processes, we observe whether standard reductions successfully terminate or not. Since reduction is nondeterministic, we test whether there exists a successful reduction sequence (may-convergence), and we test whether all reduction possibilities are successful (should-convergence).
Definition 2.3.
Let be a -process. We say process is may-convergent and write , if and only if there is a successful process with . We say is should-convergent and write if and only if for all : implies . If is not may-convergent, then we say is must-divergent (written ). If is not should-convergent, then we say it is may-divergent (written ).
Example 2.4.
The process is may-convergent () and should-convergent (), since
is the only -sequence for .
The process is may- and must-divergent (i.e. and ), since is the only -sequence for .
For
,
we have
and
.
The first result is successful, and the second result is not successful.
Hence, for we have
and .
Should-convergence implies may-convergence, and must-divergence implies may-divergence.
Definition 2.5.
For and observation , we define iff The -contextual preorders and then -contextual equivalences are defined as
Contextual equivalence of -processes is defined as
Example 2.6.
For , we have (which can be proved using the methods in sabel-schmidt-schauss-pistop:2015 ), but , since and and thus . Note that holds in , since there is a context such that for all processes : (see sabel-schmidt-schauss-pistop:2015 ). For instance, the equivalence does not hold, since and and thus the context distinguishes and w.r.t. should-convergence.
Contextual preorder and equivalence are (pre)-congruences. Contextual preorder remains unchanged if observation is restricted to closing contexts:
Lemma 2.7.
Let , be -processes. Then if, and only if such that and are closed: .
3 The Process Calculus
The calculus (a variant of the language , sabel-schmidt-schauss-PPDP:2011 ; sabel-schmidt-schauss-LICS:12 ) models a core language of Concurrent Haskell peyton-gordon-finne:96 . We assume a partitioned set of data constructors where each family represents a type . The data constructors of type are where each has an arity . We assume that there is a type () with data constructor (), a type Bool with constructors True, False, a type List with constructors Nil and : (written infix), and a type Pair with a constructor written .
Processes in have expressions as subterms. See Fig. 5 where are variables from an infinite set Var. Processes are formed by parallel composition “ | ”. The -binder restricts the scope of a variable. A concurrent thread evaluates . In a process there is (at most one) unique distinguished thread, called main thread, written as . MVars are mutable variables which are empty or filled. A thread blocks if it wants to fill a filled MVar or empty an empty MVar . Here is called the name of the MVar. Bindings model the global heap, of shared expressions, where is called a binding variable. If is a name of an MVar or a binding variable, then is called an introduced variable. In the scope of is . A process is well-formed, if all introduced variables are pairwise distinct and there exists at most one main thread .
Expressions consist of functional and monadic expressions . Functional expressions are variables, abstractions , applications , seq-expressions , constructor applications , letrec-expressions , and caseT-expressions for every type . We abbreviate case-expressions as where are the case-alternatives such that there is exactly one alternative for every constructor of type , where (occurring in the pattern ) are pairwise distinct variables that become bound with scope . We often omit the type index in . In the variables are pairwise distinct and the bindings are recursive, i.e. the scope of is and . Monadic operators , takeMVar, and putMVar are used to create, to empty and to fill MVars, the “bind”-operator >>= implements sequential composition of IO-operations, the forkIO-operator performs thread creation, and return lifts expressions into the monad.
Monadic values are , , , , , or . Functional values are abstractions and constructor applications. A value is a functional or a monadic value.
Abstractions, letrec-expressions, case-alternatives, and introduce variable binders. This induces bound and free variables (dentoted by ), -renaming, and -equivalence . If , then we call process closed. We assume the distinct variable convention: free variables are distinct from bound variables, and bound variables are pairwise distinct. We assume that -renaming is applied to obey this convention. Structural congruence of -processes is the least congruence satisfying the laws , , , , and .
We assume expressions and processes to be well-typed w.r.t. a monomorphic type system: the typing rules are standard (they can be found in schmidt-schauss-sabel:frank-60:19 ). The syntax of types is in Fig. 5 where is the type of a monadic action with return type , is the type of an MVar with content type , and is a function type. We treat constructors like overloaded constants to use them in a polymorphic way.
We introduce a call-by-name small-step reduction for . This operational semantics can be shown to be equivalent to a call-by-need semantics (see sabel-schmidt-schauss-PPDP:2011 for the calculus ). However, the equivalence of the reduction strategies is not important for this paper. That is why we do not include it.
In , a context is a process or an expression with a (typed) hole . We introduce several classes of contexts in Fig. 5. They are used by the reduction rules.
Definition 3.1.
The standard reduction is defined by the rules and the closure in Fig. 5. It is only permitted for well-formed processes which are not successful.
Functional evaluation includes -reduction (beta), copying shared bindings into needed positions (cpce), evaluating case- and seq-expressions (case) and (seq), and moving letrec-bindings into the global bindings (mkbinds). For monadic computations, rule (lunit) implements the monadic evaluation. Rules (nmvar), (tmvar), and (pmvar) handle the MVar creation and access. A takeMVar-operation can only be performed on a filled MVar, and a putMVar-operation needs an empty MVar. Rule (fork) spawns a new thread. A concurrent thread of the form is terminated (where is of type ()).
Example 3.2.
The process creates a filled MVar, that is emptied by a spawned thread, and then again filled by the main thread.
We say that a -process is successful if and if is well-formed. This captures Haskell’s behavior that termination of the main-thread terminates all threads.
Definition 3.3.
Let be a -process. Then may-converges (denoted as ), iff is well-formed and such that is successful. If does not hold, then must-diverges and we write . Process should-converges (written as ), iff is well-formed and . If is not should-convergent, then we say may-diverges written as .
Definition 3.4.
Contextual approximation and equivalence on -processes are defined as and where and . For -expressions, let iff for all process-contexts with a hole at expression position: and iff .
As an example, we consider the processes
Process is may-convergent and may-divergent (and thus not should-convergent), since either the main-thread succeeds in emptying the MVar , or (if the other threads empties the MVar ) the main-thread is blocked forever. The process is sucessful. The process is must-divergent. The equivalence holds, but , since is should-convergent and thus . As a further example, it is easy to verify that holds, since both processes are not should-convergent and a surrounding context cannot change this. However, , since .
Contextual approximation and equivalence are (pre)-congruences. The following equivalence will help to prove properties of our translation.
Lemma 3.5.
The relations in Definition 3.4 are unchanged, if we add closedness: for , let iff such that are closed: .
4 The Translation with Private MVars
We present a translation that encodes -processes as -programs. It establishes correct synchronous communication by using a private MVar, which is created by the sender and its name is sent to the receiver. The receiver uses it to acknowledge that the message was received. Since only the sender and the receiver know this MVar, no other thread can interfere the communication.The approach has similarities with Boudol’s translation boudol:1992 from the -calculus into an asynchronous one, where a private channel name of the -calculus was used to guarantee safe communication between sender and receiver.
For translating -calculus channels into , we use a recursive data type Channel (with constructor Chan), which is defined in Haskell-syntax as
We abbreviate as .
We use for and also use Haskell’s do-notation with the following meaning:
As a further abbreviation, we write inside a -block to abbreviate the sequence , where is a must-divergent expression. Our translation uses one MVar per channel which contains a pair consisting of the (translated) name of the channel and a further MVar used for the synchronization, which is private, i.e. only the sender and the receiver know it. Privacy is established by the sender: it creates a new MVar for every send operation. Message is sent over channel by sending a pair where is an MVar containing (). The receiver waits for a message by the sender. After sending the message, the sender waits until check is emptied, and the receiver acknowledges by emptying the MVar check333A variant of the translation would be to change the roles for the acknowledgement such that an empty MVar is created, which is filled by the receiver and emptied by the sender. The reasoning on the correctness of the translation is very similar to the one presented here.
Definition 4.1.
We define the translation and its inner translation from the -calculus into the -calculus in Fig. 6. For contexts, the translations are the same where the context hole is treated like a constant and translated as .
The translation generates a main-thread and an MVar . The main thread is then waiting for the MVar to be emptied. The inner translation translates the constructs and constants of the -calculus into -expressions. Except for the main-thread (and using keyword let instead of letrec), the translation generates a valid Concurrent Haskell-program, i.e. if we write as , we can execute the translation in the Haskell-interpreter.
Example 4.2.
We consider the -process which is may-convergent and may-divergent: depending on which receiver communicates with the sender, the result is the successful process or the must-divergent process . The -process reduces after several steps to the process
Now the first thread (which is the translation of sender ) is blocked, since it tries to fill the full MVar . The second thread (the encoding of ) and the third thread (the encoding of ) race for emptying the MVar . If the second thread wins, then it will fill the MVar which is then emptied by the first thread, and all other threads are blocked forever. If the third thread wins, then it will fill the MVar which is then emptied by the first thread, and then the second thread will empty the MVar . This allows the main-thread to fill it, resulting in a successful process.
For the following definition of being compositional, adequate, or fully abstract, we adopt the view that is a translation from into the -language with a special initial evaluation context .
Definition 4.3.
Let Variants of may- and should-convergence of expressions within the context in are defined as and . The relation is defined by , where iff .
Since is a subset of , we often can use the more general relations for reasoning.
Definition 4.4.
Let be the contexts of . We define the following properties for and (see schmidtschauss-sabel-niehren-schwing-tcs:15 for a general framework of properties of translations under observational semantics). For open processes , we say that translation is
- convergence-equivalent
-
iff for all : and ,
- compositional upto
-
iff for all , all , and all
, - adequate
-
iff for all processes : , and
- fully abstract
-
iff for all processes : .
Convergence-equivalence of translation for may- and should-convergence holds. For readability the proof is omitted, but given in the technical report schmidt-schauss-sabel:frank-60:19 , where we show:
Theorem 4.5.
Let be closed. Then is convergence-equivalent for and , i.e. is equivalent to . and is equivalent to . This also shows convergence-equivalence of w.r.t. , i.e. and .
We show that the translation is adequate (see Theorem 4.8 below). The interpretation of this result is that the -calculus with the concurrent semantics is semantically represented within . This result is on a more abstract level, since it is based on the property whether the programs (in all contexts) produce values or may run into failure, or get stuck; or not. Since the -calculus does not have a notion of values, also the translated processes cannot be compared w.r.t. values other than a single form of value.
The translation is not fully abstract (see Theorem 4.9 below), which is rather natural, since it only means that it is mapped into a subset of the -expressions and that this is a proper subset w.r.t. the semantics. For proving both theorems, we first use a simple form of a context lemma:
Lemma 4.6.
Let be -expressions, where the only free variable in is .
Then holds, if and only if and .
Proposition 4.7.
The translation is compositional upto .
We show that the translation transports -processes into , such that adequacy holds. Thus the translated processes also correctly mimic the behavior of the original -processes when plugged into contexts. If the translated open processes cannot be distinguished by , i.e. there is no test that detects a difference w.r.t. may- and should-convergence, then the original processes are equivalent in the -calculus. However, this open translation is not fully abstract, which means that there are -contexts (not in the image of the translation) that can see and exploit too much of the details of the translation.
Theorem 4.8.
The translation is adequate.
Proof.
We prove the adequacy for the preorder , for and the claim follows by symmetry. Let be -processes, such that . We show that . We use Lemma 3.5 to restrict considerations to closed below. Let be a context in , such that are closed and . Then . Closed convergence-equivalence implies . By Proposition 4.7. we have . Now implies , which is the same as using Proposition 4.7. Closed convergence-equivalence implies . The same arguments hold for instead of . In summary, we obtain . ∎
Theorem 4.9.
The translation is not fully abstract, but it is fully abstract on closed processes, i.e. for closed processes , we have .
Proof.
The first part holds, since an open translation can be closed by a context without initializing the -bound MVars. For , we have but : let be a context that does not initialize the MVars for (as the translation does). Then , but . Restricted to closed processes, full abstraction holds: follows from Lemma 4.6, since produces closed processes in context . Theorem 4.8 implies the other direction. ∎
5 Translations with Global MVars
In this section we investigate translations that do not use private MVars, but use a fixed number of global MVars. We first motivate this investigation. The translation is quite complex and thus we want to figure out whether there are simpler translations. A further reason is that is not optimal, since it generates one MVar per communication which can be garbage-collected after the communication, however, generation and garbage collection require resources and thus the translation may be inefficient in practice.
To systematically search for small global translations we implemented an automated tool. It searches for translations with global MVars (abstracting from a lot of other aspects of the translation) and tries to refute the correctness. As we show, most of the small translations are shown as incorrect by our tool. Analyzing correctness of the remaining translations can then be done by hand.
We only consider the aspect of how to encode the synchronous message passing of the -calculus, the other aspects (encoding parallel composition, replication and the Stop-constant) are not discussed and we assume that they are encoded as before (as the translation did). We also keep the main idea to translate a channel of the -calculus into by representing it as an object of a user-defined data type Channel that consists of an MVar for transferring the message (which again is a Channel), and additional MVars for implementing a correct synchronization mechanism. For the translation , we used a private MVar (created by the sender, and transferred together with the message). Now we investigate translations where this mechanism is replaced by one or several public MVars, which are created once together with the channel object. To restrict the search space for translations, only the synchronization mechanism of MVars (by emptying and filling them) is used, but we forbid to transfer specific data (like numbers etc.). Hence, we restrict these MVars (which we call check-MVars) to be of type MVar (). Such MVars are comparable to binary semaphores, where filling and emptying correspond to operations signal and wait. In summary, we analyze translations of -calculus channels into a -data type Channel defined in Haskell-syntax as
A -calculus channel is represented as a -binding where , are appropriately initialized (i.e. empty) MVars. The MVars are public (or global), since all processes which know have access to the components of the channel. After fixing this representation of a -channel in , the task is to translate the input- and output-actions and into -programs such that the interaction reduction is performed correctly and synchronously. We call the translation of , the receiver (program) and the translation of the sender (program). As a simplification, we restrict the allowed operations of the sender and receiver allowing only the operations:
- :
-
The sender puts its message into the -MVar of the channel. It represents the expression in where is the remaining program of the sender. The operation occurs exactly once in the sender program. We write it as , or as , if and are clear.
- :
-
The receiver takes the message from the -MVar of channel and replaces name by the received name in the subsequent program. The operation occurs exactly once in the receiver program. We write it as , or as , if and are clear. It represents the -expression where is the remaining program of the receiver. In -notation, we write to abbreviate the above -expression.
- and :
-
The sender and the receiver may synchronize on a check-MVar by putting into it or by emptying the MVar. These operations are written as and , or also as if the name is clear. We write and if there is only one check-MVar. Let be the remaining program of the sender or receiver. Then represents the -expression and represents the expression
We restrict our search for translations to the case that the sender and the receiver programs are sequences of the above operations, assuming that they are independent of the channel name . With this restriction, we can abstractly write the translation of the sender and the receiver as a pair of sequences, where only and operations are used. We make some more restrictions:
Definition 5.1.
Let be a number of check-MVars. A standard global synchronized-to-buffer translation (or gstb-translation) is a pair of a send-sequence and a receive-sequence consisting of , , and operations, where the send-sequence contains once, the receive-sequence contains once, and for every -action in , there is also a -action in . W.l.o.g., we assume that in the send-sequence the indices are ascending. I.e. if or is before or , then holds.
We often say translation instead of gstb-translation, if this is clear from the context.
Definition 5.2.
Let be a gstb-translation. We write for the program instantiated for , i.e. is , and all other operations are indexed with . We write for the program instantiated for , i.e. is , and all other operations are indexed with .
The induced translations and of are defined in Fig. 7.
The induced translations are defined similar to the translations and , where the differences are the representations of the channel. The translation of , , and is different, but the other cases remain the same. Since and by the same arguments as in Theorem 4.8, we have:
Proposition 5.3.
If is closed convergence-equivalent, then is adequate.
An execution of a translation for name is the simulation of the abstract program, i.e. a program that starts with empty MVars , , and is an interleaved sequence of actions from the send and receive-sequence and , respectively.
To speak about the translations we make further classifications: We say that a translation allows multiple uses, if a check-MVar is used more than once, i.e. the sender or receiver may contain or more than once for the same . A translation has the interprocess check restriction, if for every : and do not occur both in , and also not both in .
Definition 5.4.
A translation according to Definition 5.1 is
-
•
executable if there is a deadlock free execution of ;
-
•
communicating, if contains at least one -action;
-
•
overlap-free if for a fixed name , starting with empty MVars, every interleaved (concurrent) execution of cannot be disturbed by starting another execution of and/or . More formally, let and be two copies of for a fixed name . We call a command from one of the four sequences, an -action for . The translation is overlap-free if every execution of the four sequences has the property that it can be split into a prefix and a suffix (called parts in the following) such that one of the following properties holds
-
1.
One part contains only - and -actions, and the other part contains only - and -actions.
-
2.
One part contains only - and -actions and the other part contains only - and -actions.
-
1.
We implemented a tool to enumerate translations and to test whether each translation preserves and reflects may- and should-convergence for a (given) finite set of processes. Hence, our tool can refute the correctness of translations, but it can also output (usually small) sets of translations which are not refuted and which are promising candidates for correct translations. The above mentioned parallel execution of and is not sufficient to refute most of the translations, since it corresponds to the evaluation of the -program (which is must-divergent). Thus, we apply the translation to a subset of -processes, which we view as critical and for which we can automatically decide may- and should-convergence (before and after the translation). We consider only -programs of the form where contains only , Stop, parallel composition, and input- and output-prefixes. These programs are replication free and the -binders are on the top, and hence terminate. In the following we omit the -binders, but always mean them to be present. We also implemented techniques to generates all such programs until a bound on the size of the program is reached.
Our simulation tool444Available via https://gitlab.com/davidsabel/refute-pi. can execute all possible evaluations of those -processes and – since all evaluation paths are finite – the tool can check for may- and should-convergence of the -program. For the translated program, we do not generate a full -program, but generate a sequence of sequences of and Stop-operations by applying the translation to all action prefixes in the -program and by encoding Stop as Stop, 0 into an empty sequence. We get a sequence of sequences, since we have several threads and each thread is represented by one sequence. For executing the translated program, we simulate the global store (of MVars) and execute all possible interleavings where we check for may- and should-convergence by looking whether the Stop eventually occurs at the beginning of the sequence. This simulates the behavior of the real -program in a controllable manner.
With the encoding of the sender- and receiver program and a -calculus process we
-
1.
translate with the encodings in the sequence of sequences consisting of , , , and Stop-operations;
-
2.
simulate the execution on all interleavings;
-
3.
test may- and should convergence of the original -program as well as the encoded program (w.r.t. the simulation);
-
4.
compare the convergence before and after the translation. If there is a difference in the convergence behavior, then is a counter-example for the correctness of the encodings.
Example 5.5.
Let us consider the gstb-translation and the -process . Our tool recognizes that and holds, since reduces to the must-divergent process and there are no other reduction possibilities.
Applying to yields the abstract program
For , our tool inspects all executions. Among them there is the sequence
which can be executed ending in Stop. Thus is may-convergent, and thus the process is a counter-example that refutes the correctness of the translation.
The case that there is no check-MVar leads to one possible translation which means that is translated into and is translated into . This translation is not correct, since for instance the -process is neither may- nor should-convergent, but the translation (written as an abstract program) is . I.e., it consists of one process which is may- and should-convergent (since is the only evaluation sequence and its execution ends in Stop). Note that the translation into will generate two threads: the main threads that will wait until the MVar is filled, and a concurrent thread that will do the above operations.
5.1 Translations with Interprocess Check Restriction
We consider translations with the interprocess check restriction (each and must be distributed between the sender and the receiver). There are different translations (for check-MVars).
Translation (sender,receiver) | Counter-example (-process) |
|
|
|
|
||||
---|---|---|---|---|---|---|---|---|---|
N | N | Y | Y | ||||||
N | N | Y | Y | ||||||
N | N | Y | Y | ||||||
N | N | Y | Y | ||||||
N | N | Y | N | ||||||
Y | Y | N | N | ||||||
N | N | Y | N | ||||||
Y | Y | Y | N |
For a single check-MVar, all 8 translations are rejected by our tool, Table 1 shows the translations and the obtained counter examples. For check-MVars, our tool refutes all 72 translations. Compared to Table 1, there are two further -programs used as counterexample. However, also the programs and suffice to refute all 72 translations.
Theorem 5.6.
There is no valid gstb-translation with the interprocess check restriction for less than three check-MVars.
A reason for the failure of translations with less than three check-MVars may be:
Theorem 5.7.
There is no executable, communicating, and overlap-free gstb-translation with the interprocess check restriction for .
Proof.
For , we check the translations in Table 1. The first four are non-communicating. For the translation a deadlock occurs. For , after , , we can execute again. For , after executing , we can execute again. For , after ,, we can execute again. For , the simulator finds no executable, communicating, and overlap-free translation: 18 translations are non-communicating, 21 lead to a deadlock, and 33 may lead to an overlap. ∎
For 3 MVars, our tool rejects 762 out of 768 translations (using the same counter examples as for check-MVars) and the following 6 translations remain:
Proposition 5.8.
The translations , and are executable, communicating, and overlap-free, whereas the translations and are executable, communicating, but overlapping.
Proof.
We only consider overlaps. For - , only if all 8 actions are finished, the next send or receive can start. For , after executing , , we can again execute . ∎
In schmidt-schauss-sabel:frank-60:19 we argue that the induced translation leaves may- and should-convergence invariant. The main help in reasoning is that there is no unintended interleaving of send and receive sequences according to Proposition 5.8. Application of Proposition 5.3 then shows:
Theorem 5.9.
Translation is adequate.
For 4 MVars, our tool refutes 9266 and there remain 334 candidates for correct translations.
5.2 Dropping the Interprocess Check Restriction
We now consider gstb-translations without the interprocess check restriction, i.e. and both may occur in the sender-program (or the receiver program, resp.). If we allow one check-MVar without reuse, then there are 20 candidates for translations. All are refuted by our simulation. Allowing reuse of the single check-MVar seems not to help to construct a correct translation: We simulated this for up to 6 uses, leading to 420420 candidates for a correct translation – our simulation refutes all of them.
Conjecture 5.10.
We conjecture that there is no correct translation for one check-MVar where re-uses are permitted and the interprocess check restriction is dropped, i.e., is a word over and a word over , where occur exactly once. 555We already have a proof in the meantime, not yet published.
For two MVars, one use and without the interprocess check restriction there are 420 translations. Our tool refutes all except for two: and . In the second check-MVar is used as a mutex for the senders, ensuring that only one sender can operate at a time. does the same on the receiver side.
Proposition 5.11.
The translations are executable, communicating, overlap-free.
Proof.
The translations are executable and communicating. For , and are performed in this order. An additional sender cannot execute its first command before the original sender performs and this again is only possible after the receiver program is finished. An additional receiver can only be executed after a is performed, which cannot be done by the current sender and receivers. For , and are performed in this order. An additional receiver can only start after was executed by the original receiver, which can only occur after the original sender and receiver program are fully evaluated. An additional sender can only start after has been executed again, but the current sender and receiver cannot execute this command. ∎
The induced translation is (closed) convergence-equivalent schmidt-schauss-sabel:frank-60:19 . With Proposition 5.3 this shows:
Theorem 5.12.
Translation is adequate.
We are convinced that the same holds for . We conclude the statistics of our search for translations without the interprocess restriction: For 3 MVars, there are 10080 translations and 9992 are refuted, i.e. 98 are potentially correct. One is which is quite intuitive: check-MVar is used as a mutex for all senders on the same channel, check-MVar is used as a mutex for all receivers, and check-MVar is used to send an acknowledgement. For 4 MVars, there are 277200 translations and 273210 are refuted, i.e. 3990 are potentially correct.
6 Discussion and Conclusion
We investigated translating the -calculus into and showed correctness and adequacy of a translation with private MVars for every translated communication. For translations with global names, we started an investigation on exhibiting (potentially) correct translations. We identified several minimal potentially correct translations and characterized all incorrect “small” translations. For two particular global translations, we have shown that they are convergence-equivalent and we proved their adequacy on open processes. The exact form of the translations were found by our tool to search for translations and to refute their correctness. The tool showed that there is no correct gstb-translation with the interprocess check restriction for less than 3 check-MVars. We also may consider extended variants of the -calculus. We are convinced that adding recursion and sums can easily be built into the translation, while it might be challenging to encode mixed sums or (name) matching operators. For name matching operators, our current translation would require to test usual bindings in for equality which is not available in core-Haskell. Solutions may either use an adapted translation or a target language that supports observable sharing Claessen-Sands:99 ; Gill:09 . The translation of mixed-sums into appears to require more complex translations, where the send- and receive-parts are not linear lists of actions.
Acknowledgments
We thank the anonymous reviewers for their valuable comments. In particular, we thank an anonymous reviewer for advises to improve the construction of translations, and for providing the counter-example in the last row of Table 1.
References
- (1)
- (2) Martín Abadi & Andrew D. Gordon (1997): A Calculus for Cryptographic Protocols: The Spi Calculus. In: CCS 1997, ACM, pp. 36–47, 10.1145/266420.266432.
- (3) Richard Banach, J. Balázs & George A. Papadopoulos (1995): A Translation of the Pi-Calculus Into MONSTR. J.UCS 1(6), pp. 339–398, 10.3217/jucs-001-06-0339.
- (4) Gérard Boudol (1992): Asynchrony and the Pi-calculus. Technical Report Research Report RR-1702,inria-00076939, INRIA, France. Available at https://hal.inria.fr/inria-00076939.
- (5) Mauricio Cano, Jaime Arias & Jorge A. Pérez (2017): Session-Based Concurrency, Reactively. In: FORTE 2017, LNCS 10321, Springer, pp. 74–91, 10.1007/978-3-319-60225-7_6.
- (6) Avik Chaudhuri (2009): A concurrent ML library in concurrent Haskell. In: ICFP 2009, ACM, pp. 269–280, 10.1145/1596550.1596589.
- (7) Koen Claessen & David Sands (1999): Observable Sharing for Functional Circuit Description. In: ASIAN 1999, LNCS 1742, Springer, pp. 62–73, 10.1007/3-540-46674-6_7.
- (8) Cédric Fournet & Georges Gonthier (2002): The Join Calculus: A Language for Distributed Mobile Programming. In: APPSEM 2000, LNCS 2395, Springer, pp. 268–332, 10.1007/3-540-45699-6_6.
- (9) Andy Gill (2009): Type-safe observable sharing in Haskell. In: Haskell 2009, ACM, pp. 117–128, 10.1145/1596638.1596653.
- (10) Rob van Glabbeek, Ursula Goltz, Christopher Lippert & Stephan Mennicke (2019): Stronger Validity Criteria for Encoding Synchrony. In: The Art of Modelling Computational Systems: A Journey from Logic and Concurrency to Security and Privacy - Essays Dedicated to Catuscia Palamidessi on the Occasion of Her 60th Birthday, LNCS 11760, Springer, pp. 182–205, 10.1007/978-3-030-31175-9_11.
- (11) Rob J. van Glabbeek (2018): On the validity of encodings of the synchronous in the asynchronous -calculus. Inf. Process. Lett. 137, pp. 17–25, 10.1016/j.ipl.2018.04.015.
- (12) Daniele Gorla (2010): Towards a unified approach to encodability and separation results for process calculi. Inf. Comput. 208(9), pp. 1031–1053, 10.1016/j.ic.2010.05.002.
- (13) Kohei Honda & Mario Tokoro (1991): An Object Calculus for Asynchronous Communication. In: ECOOP 1991, Springer-Verlag, pp. 133–147, 10.1007/BFb0057019.
- (14) Cosimo Laneve (1996): On testing equivalence: May and Must Testing in the Join-Calculus. Technical Report UBLCS 96-04, University of Bologna. Available at https://www.cs.unibo.it/~laneve/papers/laneve96may.pdf.
- (15) Robin Milner (1999): Communicating and mobile systems - the Pi-calculus. Cambridge University Press.
- (16) Robin Milner, Joachim Parrow & David Walker (1992): A Calculus of Mobile Processes, I & II. Inform. and Comput. 100(1), pp. 1–77, 10.1016/0890-5401(92)90008-4.
- (17) Joachim Niehren, David Sabel, Manfred Schmidt-Schauß & Jan Schwinghammer (2007): Observational Semantics for a Concurrent Lambda Calculus with Reference Cells and Futures. Electron. Notes Theor. Comput. Sci. 173, pp. 313–337, 10.1016/j.entcs.2007.02.041.
- (18) Dominic A. Orchard & Nobuko Yoshida (2016): Effects as sessions, sessions as effects. In: POPL 2016, ACM, pp. 568–581, 10.1145/2837614.2837634.
- (19) Catuscia Palamidessi (1997): Comparing the Expressive Power of the Synchronous and the Asynchronous pi-calculus. In: POPL 1997, ACM Press, pp. 256–265, 10.1145/263699.263731.
- (20) Catuscia Palamidessi (2003): Comparing The Expressive Power Of The Synchronous And Asynchronous Pi-Calculi. Math. Structures Comput. Sci. 13(5), pp. 685–719, 10.1017/S0960129503004043.
- (21) Simon L. Peyton Jones, Andrew Gordon & Sigbjorn Finne (1996): Concurrent Haskell. In: POPL 1996, ACM, pp. 295–308, 10.1145/237721.237794.
- (22) Corrado Priami (1995): Stochastic pi-Calculus. Comput. J. 38(7), pp. 578–589, 10.1093/comjnl/38.7.578.
- (23) George Russell (2001): Events in Haskell, and How to Implement Them. In: ICFP 2001, ACM, pp. 157–168, 10.1145/507635.507655.
- (24) David Sabel & Manfred Schmidt-Schauß (2011): A contextual semantics for Concurrent Haskell with futures. In: PPDP 2011, ACM, pp. 101–112, 10.1145/2003476.2003492.
- (25) David Sabel & Manfred Schmidt-Schauß (2012): Conservative Concurrency in Haskell. In: LICS 2012, IEEE, pp. 561–570, 10.1109/LICS.2012.66.
- (26) David Sabel & Manfred Schmidt-Schauß (2015): Observing Success in the Pi-Calculus. In: WPTE 2015, OASICS 46, pp. 31–46, 10.4230/OASIcs.WPTE.2015.31.
- (27) Davide Sangiorgi & David Walker (2001): On Barbed Equivalences in pi-Calculus. In: CONCUR 200, LNCS 2154, Springer, pp. 292–304, 10.1007/3-540-44685-0_20.
- (28) Davide Sangiorgi & David Walker (2001): The -calculus: a theory of mobile processes. Cambridge university press.
- (29) Manfred Schmidt-Schauß, Joachim Niehren, Jan Schwinghammer & David Sabel (2008): Adequacy of Compositional Translations for Observational Semantics. In: IFIP TCS 2008, IFIP 273, Springer, pp. 521–535, 10.1007/978-0-387-09680-3_35.
- (30) Manfred Schmidt-Schauß & David Sabel (2020): Embedding the Pi-Calculus into a Concurrent Functional Programming Language. Frank report 60, Institut für Informatik. Fachbereich Informatik und Mathematik. J. W. Goethe-Universität Frankfurt am Main. Available at http://www.ki.informatik.uni-frankfurt.de/papers/frank/frank-60v5.pdf.
- (31) Manfred Schmidt-Schauß, David Sabel & Nils Dallmeyer (2018): Sequential and Parallel Improvements in a Concurrent Functional Programming Language. In: PPDP 2018, ACM, pp. 20:1–20:13, 10.1145/3236950.3236952.
- (32) Manfred Schmidt-Schauß, David Sabel, Joachim Niehren & Jan Schwinghammer (2015): Observational program calculi and the correctness of translations. Theor. Comput. Sci. 577, pp. 98–124, 10.1016/j.tcs.2015.02.027.
- (33) Jan Schwinghammer, David Sabel, Manfred Schmidt-Schauß & Joachim Niehren (2009): Correctly translating concurrency primitives. In: ML 2009, ACM, pp. 27–38, 10.1145/1596627.1596633.
- (34) Ping Yang, C. R. Ramakrishnan & Scott A. Smolka (2004): A logical encoding of the pi-calculus: model checking mobile processes using tabled resolution. STTT 6(1), pp. 38–66, 10.1007/s10009-003-0136-3.