Manifest Deadlock-Freedom for Shared Session Types

  • Stephanie BalzerEmail author
  • Bernardo ToninhoEmail author
  • Frank Pfenning
Open Access
Conference paper
Part of the Lecture Notes in Computer Science book series (LNCS, volume 11423)


Shared session types generalize the Curry-Howard correspondence between intuitionistic linear logic and the session-typed \(\pi \)-calculus with adjoint modalities that mediate between linear and shared session types, giving rise to a programming model where shared channels must be used according to a locking discipline of acquire-release. While this generalization greatly increases the range of programs that can be written, the gain in expressiveness comes at the cost of deadlock-freedom, a property which holds for many linear session type systems. In this paper, we develop a type system for logically-shared sessions in which types capture not only the interactive behavior of processes but also constrain the order of resources (i.e., shared processes) they may acquire. This type-level information is then used to rule out cyclic dependencies among acquires and synchronization points, resulting in a system that ensures deadlock-free communication for well-typed processes in the presence of shared sessions, higher-order channel passing, and recursive processes. We illustrate our approach on a series of examples, showing that it rules out deadlocks in circular networks of both shared and linear recursive processes, while still being permissive enough to type concurrent implementations of shared imperative data structures as processes.


Linear and shared session types Deadlock-freedom 

1 Introduction

Session types [25, 26, 27] naturally describe the interaction protocols that arise amongst concurrent processes that communicate via message-passing. This typing discipline has been integrated (with varying static safety guarantees) into several mainstream language such as Java [28, 29], F# [43], Scala [49, 50], Go [11] and Rust [33]. Session types moreover enjoy a logical correspondence between linear logic and the session-typed \(\pi \)-calculus [8, 9, 51, 55]. Languages building on this correspondence [24, 52, 55] not only guarantee session fidelity (i.e., type preservation) but also deadlock-freedom (i.e., global progress). The latter is guaranteed even in the presence of interleaved sessions, which are often excluded from the deadlock-free fragments of traditional session-typed frameworks [20, 26, 27, 53]. These logical session types, however, exclude programming scenarios that demand sharing of mutable resources (e.g., shared databases or shared output devices) instead of functional resource replication.

To increase their practicality, logical session types have been extended with manifest sharing [2]. In the resulting language, linear and shared sessions coexist, but the type system enforces that clients of shared sessions run in mutual exclusion of each other. This separation is achieved by enforcing an acquire-release policy, where a client of a shared session must first acquire the session before it can participate in it along a private linear channel. Conversely, when a client releases a session, it gives up its linear channel and only retains a shared reference to the session. Thus, sessions in the presence of manifest sharing can change, or shift, between shared and linear execution modes. At the type-level, the acquire-release policy manifests in a stratification of session types into linear and shared with adjoint modalities [5, 47, 48], connecting the two strata. Operationally, the modality shifting up from the linear to the shared layer translates into an acquire and the one shifting down from shared to linear into a release.

Manifest sharing greatly increases the range of programs that can be written because it recovers the expressiveness of the untyped asynchronous \(\pi \)-calculus [3] while maintaining session fidelity. As in the \(\pi \)-calculus, however, the gain in expressiveness comes at the cost of deadlock-freedom. An illustrative example is an implementation of the classical dining philosophers problem, shown in Fig. 1, using the language \(\mathsf {SILL}_{\mathsf {S}}\) [2] that supports manifest sharing (in this setting we often equate a process with the session it offers along a distinguished channel). The code shows the process \( fork\_proc \), implementing a session of type \(\mathsf {sfork}\), and the processes \( thinking \) and \( eating \), implementing sessions of type \(\mathsf {philosopher}\). We defer the details of the typing and the definition of the session types \(\mathsf {sfork}\) and \(\mathsf {philosopher}\) to Sect. 2 and focus on the programmatic working of the processes for now. For ease of reading, we typeset shared session types and variables denoting shared channel references in Open image in new window .

A \( fork\_proc \) process represents a fork that can be perpetually acquired and released. The actions \(\mathsf {accept}\) and \(\mathsf {detach}\) are the duals of \(\mathsf {acquire}\) and \(\mathsf {release}\), respectively, allowing a process to accept an acquire by a client and to initiate a release by a client, respectively. Process \(\mathsf {thinking}\) has two shared channel references as arguments, for the forks to the left and right of the philosopher, which the process tries to acquire. If the acquire succeeds, the process recurs as an \(\mathsf {eating}\) philosopher with two (now) linear channel references of type \(\mathsf {lfork}\). Once a philosopher is done eating, it releases both forks and recurs as a \(\mathsf {thinking}\) philosopher. Let’s set a table for three philosopher that share three forks, all spawned as processes executing in parallel:
Fig. 1.

Dining philosophers in \(\mathsf {SILL}_{\mathsf {S}}\) [2].

Infamously, this configuration may deadlock because of the circular dependency between the acquires. We can break this cycle by changing the last line to Open image in new window , ensuring that forks are acquired in increasing order.

Perhaps surprisingly, cyclic dependencies between acquire requests are not the only source of deadlocks. Fig. 2 gives an example, defining the processes \( owner \) and \( contester \), which both have a shared channel reference to a common resource that can be perpetually acquired and released. Both processes acquire the shared resource, but additionally exchange the message \(\mathsf {ping}\). More precisely, process \( owner \) spawns the process \( contester \), acquires the shared resource, and only releases the resource after having received the message \(\mathsf {ping}\) from the \( contester \). Process \( contester \), on the other hand, first attempts to acquire the resource and then sends the message \( ping \) to the owner. The program deadlocks if process \( owner \) acquires the resource first. In that case, process \( owner \) waits for process \( contester \) to send the message \(\mathsf {ping}\) while process \( contester \) waits to acquire the resource held by process \( owner \). We note that this deadlock arises in both synchronous and asynchronous semantics.
Fig. 2.

Circular dependencies among acquire and synchronization actions.

In this paper, we develop a type system for manifest sharing that rules out cycles between acquire requests and interdependencies between acquire requests and synchronization actions, detecting the two kinds of deadlocks explained above. In our type system, session types not only prescribe when resources must be acquired and released, but also the range of resources that may be acquired. To this end, we equip the type system with the notion of a world, an abstract value at which a process resides, and type processes relative to an acyclic ordering on worlds, akin to the partial-order based approaches of [34, 37]. The contributions of this paper are:
  • a characterization of the possible forms of deadlocks that can arise in shared session types;

  • the introduction of manifest deadlock-freedom, where resource dependencies are manifest in the type structure via world modalities;

  • its elaboration in the programming language \(\mathsf {SILL}_{\mathsf {S}^+}\), resulting in a type system, a synchronous operational semantics, and proofs of session fidelity (preservation) and a strong form of progress that excludes all deadlocks;

  • the novel abstraction of green and red arrows to reason about the interdependencies between processes;

  • an illustration of the concepts on various examples, including an extensive comparison with related work.

This paper is structured as follows: Sect. 2 provides a short introduction to manifest sharing. Sect. 3 develops the type system and dynamics of the language \(\mathsf {SILL}_{\mathsf {S}^+}\). Sect. 4 illustrates the introduced concepts on an extended example. Sect. 5 discusses the meta-theoretical properties of \(\mathsf {SILL}_{\mathsf {S}^+}\), emphasizing progress. Sect. 6 compares with examples of related work and identifies future work. Sect. 7 discusses related work, and Sect. 8 concludes this paper.

2 Manifest Sharing

In the previous section, we have already explored the programmatic workings of manifest sharing [2], which enforces an acquire-release policy on shared channel references. In this section, we clarify the typing of shared processes.

A key contribution of manifest sharing is not only to support acquire-release as a programming primitive but also to make it manifest in the type system. Generalizing the idea of type stratification [5, 47, 48], session types are partitioned into a linear and shared layer with two adjoint modalities connecting the layers:

In the linear layer, we get the standard connectives of intuitionistic linear logic (\( A _{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\otimes B _{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\), \( A _{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\multimap B _{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\), \(\oplus \{\overline{l:A_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\}\), Open image in new window , and \(\mathbf {1}\)). These connectives are extended with the modal operator \({\downarrow }^{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}A_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}\), shifting down from the shared to the linear layer. Similarly, in the shared layer, we have the operator \({\uparrow }^{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}A_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\), shifting up from the linear to the shared layer. The former translates into a release (and, dually, detach), the latter into an acquire (and, dually, accept). As a result, we obtain a system in which session types prescribe all forms of communication, including the acquisition and release of shared processes.

Table 1 provides an overview of \(\mathsf {SILL}_{\mathsf {S}}\)’s session types and their operational reading. Since \(\mathsf {SILL}_{\mathsf {S}}\) is based on an intuitionistic interpretation of linear logic session types [8], types are expressed from the point of view of the providing process with the channel along which the process provides the session behavior being characterized by its session type. This choice avoids the explicit duality operation present in original presentations of session types [25, 26] and in those based on classical linear logic [55]. Table 1 lists the points of view of the provider and client of a given connective in the first and second lines, respectively. Moreover, Table 1 gives for each connective its session type before and after the message exchange, along with their respective process terms. We can see that the process terms of a provider and a client for a given connective come in matching pairs, indicating that the participants’ views of the session change consistently. We use the subscripts \({\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\) and \({\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}\) to distinguish between linear and shared channels, respectively.
Table 1.

Session types in \(\mathsf {SILL}_{\mathsf {S}}\) and their operational meaning.

We are now able to give the session types of the processes \( fork\_proc \), \( thinking \), and \( eating \) defined in the previous section:

The mutually recursive session types \(\mathsf {lfork}\) and \(\mathsf {sfork}\) represent a fork that can perpetually be acquired and released. We adopt an equi-recursive [14] interpretation for recursive session types, silently equating a recursive type with its unfolding and requiring types to be contractive [19].

We briefly discuss the typing and the dynamics of acquire-release. The typing and the dynamics of the residual linear connectives are standard, and we detail them in the context of \(\mathsf {SILL}_{\mathsf {S}^+}\) (see Sect. 3). As is usual for an intuitionistic interpretation, each connective gives rise to a left and a right rule, denoting the use and provision, respectively, of a session of the given type:The typing judgments \(\varGamma \vdash P \; {:}\,\!{:} \; (x_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}: A_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}})\) and \(\varGamma ; \varDelta \vdash P \; {:}\,\!{:} \; (x_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}: A_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}})\) indicate that process P provides a session of type A along channel x, given the typing of the channels specified in typing contexts \(\varGamma \) (and \(\varDelta \)). \(\varGamma \) and \(\varDelta \) consist of hypotheses on the typing of shared and linear channels, respectively, where \(\varGamma \) is a structural and \(\varDelta \) a linear context. To allow for recursive process definitions, the typing judgment depends on a signature \(\varSigma \) that is populated with all process definitions prior to type-checking. The adjoint formulation precludes shared processes from depending on linear channel references [2, 47], a restriction motivated from logic referred to as the independence principle [47]. Thus, when a shared session accepts an acquire and shifts to linear, it starts with an empty linear context.
Operationally, the dynamics of \(\mathsf {SILL}_{\mathsf {S}}\) is captured by multiset rewriting rules [12], which denote computation in terms of state transitions between configurations of processes. Multiset rewriting rules are local in that they only mention the parts of a configuration they rewrite. For acquire-release we have the following:

Configuration states are defined by the predicates \(\mathsf {proc}( c_{ m } , \, P )\) and \(\mathsf {unavail}( a_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}} )\). The former denotes a running process with process term P providing along channel \(c_{ m }\), the latter acts as a placeholder for a shared process providing along channel \(a_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}\) that is currently not available. The above rule exploits the invariant that a process’ providing channel a can appear at one of two modes, a linear one, \(a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\), and a shared one, \(a_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}\). While the process (i.e. the session) is linear, it provides along \(a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\), while it is shared, along \(a_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}\). When a process shifts between modes, it switches between the two modes of its offering channel. The channel at the appropriate mode is substituted for the variables occurring in process terms.

3 Manifest Deadlock-Freedom

In this section, we introduce our language \(\mathsf {SILL}_{\mathsf {S}^+}\), a session-typed language that supports sharing without deadlock. We focus on \(\mathsf {SILL}_{\mathsf {S}^+}\)’s type system and dynamics in this section and discuss its meta-theoretical properties in Sect. 5.

3.1 Competition and Collaboration

The introduction of acquire-release, to ensure that the multiple clients of a shared process interact with the process in mutual exclusion from each other, gives rise to an obvious source of deadlocks, as acquire-release effectively amounts to a locking discipline. The typical approach to prevent deadlocks in that case is to impose a partial order on the resources and to “lock-up”, i.e., to lock the resources in ascending order. We adopted this strategy in Sect. 1 (Fig. 1) to break the cyclic dependencies among the acquires in the dining philosophers.

In Sect. 1, however, we also considered another example (Fig. 2) and discovered that cyclic acquisitions are not the only source of deadlocks, but deadlocks can also arise from interdependent acquisitions and synchronizations. In that example, we can prevent the deadlock by moving the acquire past the synchronization, in either of the two processes. Whereas in a purely linear session-typed system the sequencing of actions within a process do not affect other processes, the relative placement of acquire requests and synchronizations become relevant in a shared session-typed system.

Based on this observation, we can divide the processes in a shared-session discipline into competitors and collaborators. The former compete for a set of resources, whereas the latter do not overlap in the set of resources they acquire. For example, in the dining philosophers (Fig. 1), the philosophers \( p_0 \), \( p_1 \), and \( p_2 \) compete with each other for the set of forks \( f_0 \), \( f_1 \), and \( f_2 \), whereas the process that spawns the philosophers and the forks collaborates with either of them.

Transferring this idea to the process graph that emerges at run-time, we note that competitors are siblings whereas collaborators stand in a parent-descendant relationship. We illustrate this outcome on Fig. 3 that shows a possible run-time process graph for the dining philosophers. Linear processes are depicted as solid black circles with a white identifier and shared processes are depicted as dotted filled violet circles with a black identifier. Linear channels are depicted as black lines, shared channel references as dotted violet lines with the arrow head pointing to the shared process being acquired1. The identifiers \(P_0\), \(P_1\), and \(P_2\) stand for the three philosophers, \(F_0\), \(F_1\), and \(F_2\) for the three forks, and T for the process that sets the table. The current run-time graph depicts the scenario in which \(P_1\) is eating, while the other two philosophers are still thinking.
Fig. 3.

Run-time process graph for dining philosophers (see Fig. 1).

Embedded in the graph is a tree that arises from the linear processes and the linear channels connecting them. For any two nodes in this tree, the parent node denotes the client process and the child node the providing process. We note that the independence principle (see Sect. 2), which precludes shared processes from depending on linear channel references, guarantees that there exists exactly one tree in the process graph, with the linear main process as its root. The shape of the tree changes when new processes are spawned, linear channels exchanged (through \(\otimes \) and \(\multimap \)), or shared processes acquired. For example, process \(P_2\) could acquire the shared fork \(F_0\), which then becomes a linear child process of \(P_2\), should the acquire succeed. As indicated by the shared channel references, the sibling nodes \(P_0\), \(P_1\), and \(P_2\) compete with each other for the nodes \(F_0\), \(F_1\), and \(F_2\), whereas the node T does not compete for any of the resources acquired by its descendants (including \(F_1\) and \(F_2\)). Our type system enforces this paradigm, as we discuss in the next section.

3.2 Type System

Invariants. Having identified the notions of collaborators and competitors, our type system must guarantee: (i) that collaborators acquire mutually disjoint sets of resources; (ii) that competitors employ a locking-up strategy for the resources they share; and, (iii) that competitors have released all acquired resources when synchronizing with other competitors. Invariant (ii) rules out cyclic acquisitions and invariants (i) and (iii) combined rule out interdependent acquisitions and synchronizations.

To express the high-level invariants above in our type system, we introduce the notion of a world – an abstract value that is equipped with a partial order – and associate such a world with every process. Programmers can create worlds, indicate the world at which a process resides at spawn time, and define an order on worlds. Moreover, we associate with each process a range of worlds that indicates the worlds of resources that the process may acquire. As a result, we obtain the following typing judgments:
$$ \varPsi ; \, \varGamma \vdash P \; {:}\,\!{:} \; (x_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}: A_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}[{\omega _k}\updownarrow ^{\omega _n}_{\omega _l}]) \quad \text {(where} \,\,\varPsi ^+\,\, {\mathrm{irreflexive)}} $$
$$ \varPsi ; \, \varGamma ; \, \varPhi ; \, \varDelta \vdash P \; {:}\,\!{:} \; (x_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}: A_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\omega _k}\updownarrow ^{\omega _n}_{\omega _l}]) \quad \text {(where}\,\, \varPsi ^+\,\, {\mathrm{irreflexive)}} $$
The typing judgments reveal that we impose worlds at the judgmental level, resulting in a hybrid system, in which the adjoint modalities for acquire-release are complemented with world modalities that occur as syntactic objects in propositions [7]. We use the notation \(x_m : A_m [{\omega _k}\updownarrow ^{\omega _n}_{\omega _l}]\) (where m stands for \(\mathsf {S}\) or \(\mathsf {L}\)) to associate worlds \(\omega _k\), \(\omega _l\), and \(\omega _n\) with a process that offers a session of type \(A_m\) along channel x. World \(\omega _k\) denotes the world at which the process resides. We refer to this world as the self world. Worlds \(\omega _l\) and \(\omega _n\) indicate the range of worlds of resources that the process may acquire, with \(\omega _l\) denoting the minimal (min) world in this range and \(\omega _n\) the maximal (max) one.

Process terms are typed relative to the order specified in \(\varPsi \) and the contexts \(\varGamma \), \(\varPhi \), and \(\varDelta \). As in Sect. 2, \(\varGamma \) is a structural context consisting of hypotheses on the typing of variables bound to shared channel references, augmented with world annotations. We find it necessary to split the linear context “\(\varDelta \)” from Sect. 2 into the two disjoint contexts \(\varPhi \) and \(\varDelta \), allowing us to separate channels that are possibly aliased (due to sharing) from those that are not, respectively. Both \(\varPhi \) and \(\varDelta \) consist of hypotheses on the typing of variables that are bound to linear channels, augmented with world annotations. \(\varPsi \) is presupposed to be acyclic and defined as: \( \varPsi \,\triangleq \,\cdot \,\mid \,\varPsi ', \; \omega _{ k } < \omega _{ l } \,\mid \,\varPsi ', \; \omega _{ o } \), where \(\omega \) stands for a concrete world \(\mathsf {w}\) or a world variable \(\delta \). We allow \(\varPsi \) to contain single worlds, to support singletons as well as to accommodate world creation prior to order declaration. We define the transitive closure \(\varPsi ^+\), yielding a strict partial order, and the reflexive transitive closure \(\varPsi ^*\), yielding a partial order.

The high-level invariants (i), (ii), and (iii) identified earlier naturally transcribe into the following invariants, which we impose on the typing judgments above. We use the notation \(\_\langle x_m \rangle ; P\) to denote a process term that currently executes an action along channel \(x_m\).

  1. 1.

    \(\mathsf {min}(\mathsf {parent}) \le \mathsf {self}(\mathsf {acquired\_child}) \le \mathsf {max}(\mathsf {parent})\):

    \(\forall y_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}: B_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\omega _o}\updownarrow ^{\omega _r}_{\omega _p}] \in \varPhi : \varPsi ^* \,\vdash \,\omega _l \le \omega _o \le \omega _n\)

  2. 2.

    \(\mathsf {max}(\mathsf {parent}) < \mathsf {min}(\mathsf {child})\):

    \(\forall y_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}: B_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\omega _o}\updownarrow ^{\omega _r}_{\omega _p}] \in \varDelta \cup \varPhi : \varPsi ^+ \,\vdash \,\omega _n < \omega _p\)

  3. 3.

    If \(\varPsi ; \, \varGamma , x_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}: {A}[{\omega _t}\updownarrow ^{\omega _v}_{\omega _u}]; \, \varPhi ; \, \varDelta \vdash x_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} \leftarrow \mathsf {acquire}\; x_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}; \, Q_{x_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}} \; {:}\,\!{:} \; (z_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}: C_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\omega _k}\updownarrow ^{\omega _n}_{\omega _l}])\), then \(\forall y_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}: B_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\omega _o}\updownarrow ^{\omega _r}_{\omega _p}] \in \varPhi : \varPsi ^+ \,\vdash \,\omega _o < \omega _t\).

  4. 4.

    If \(\varPsi ; \, \varGamma ; \, \varPhi ; \, \varDelta \vdash \_\langle x_m \rangle ; P \; {:}\,\!{:} \; (x_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}: A_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\omega _k}\updownarrow ^{\omega _n}_{\omega _l}])\), then \(\varPhi = (\cdot )\).


Invariants 1 and 2 ensure that, for any node in the tree, the acquired resources reside at smaller worlds than those acquired by any descendant. As a result, the two invariants guarantee high-level invariant (i). Invariant 3, on the other hand, imposes a lock-up strategy on acquires and thus guarantees high-level invariant (ii). To guarantee high-level invariant (iii), we impose Invariant 4, which forces a process to release any acquired resources before communicating along its offering channel. Since sibling nodes cannot be directly connected by a linear channel, the only way for them to synchronize is through a common parent. Finally, to guarantee that world annotations are internally consistent, we require for each annotation \([{\omega _k}\updownarrow ^{\omega _n}_{\omega _l}]\) that \(\omega _k < \omega _l \le \omega _n\).

Rules. We now present select process typing rules, a complete listing is provided in the companion technical report [4]. The only new rules with respect to the language \(\mathsf {SILL}_{\mathsf {S}}\) [2] are those pertaining to world creation and order determination. These are extra-logical judgmental rules. We allow both linear and shared processes to create and relate worlds. Rules Open image in new window and Open image in new window create a new world \(\mathsf {w}\) and make it available to the continuation \(Q_{\mathsf {w}}\). Rules Open image in new window and Open image in new window relate two existing worlds, while preserving acyclicity of the order.We now consider the typing rule for acquire, which must explicitly enforce the various low-level invariants above. Since an acquire results in the addition of a new child node to the executing process, the rule can interfere with Invariants 1 and 2. The first two premises of the rule ensure that the two invariants are preserved. Moreover, the rule has to ensure that the acquiring process is locking-up (Invariant 3), which is achieved by the third premise.The remaining shift rules are actually unchanged with respect to \(\mathsf {SILL}_{\mathsf {S}}\), modulo the world annotations. In particular, low-level Invariant 4 is already satisfied because the conclusion of rule Open image in new window does not have a context \(\varPhi \) and because the independence principle forces \(\varPhi \) to be empty in rule Open image in new window .We now consider the linear connectives, starting with \(\mathbf {1}\). Rule Open image in new window reveals that only processes that have never been acquired may be terminated. This restriction is important to guarantee progress because existing clients of a shared process may wait indefinitely otherwise. We impose the restriction as a well-formedness condition on a session type, giving rise to a strictly equi-synchronizing session type. The notion of an equi-synchronizing session type [2] has been defined for \(\mathsf {SILL}_{\mathsf {S}}\) and guarantees that a process that has been acquired at a type \(A_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}\) is released back to the type \(A_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}\), should it ever be released. A strictly equi-synchronizing session type additionally requires that an acquired resource must be released. The corresponding rules can be found in [4]. Linearity enforces Invariant 4 in rule Open image in new window , making sure that no linear channels are left behind.Next, we consider internal and external choice. Since internal and external choice cannot alter the linear process tree of a process graph, the rules are very similar to the ones in \(\mathsf {SILL}_{\mathsf {S}}\). The only differences are that we get two left rules for each connective and that the \(\varPhi \)-context of each right rule must be empty to satisfy Invariant 4. The former is merely due to the tracking of possibly aliased sessions in the \(\varPhi \) context. We only list rules for internal choice, those for external choice are dual and can be found in [4].More interesting are linear channel output and input, since these alter the linear process tree of a process graph. Moreover, additional world annotations are needed to indicate the worlds of the channel that is exchanged. For the latter we use the notation \(@{\omega _l}\updownarrow ^{\omega _r}_{\omega _p}\), indicating that the exchanged channel has the worlds \(\omega _l\), \(\omega _p\), and \(\omega _r\) for \(\mathsf {self}\), \(\mathsf {min}\), and \(\mathsf {max}\), respectively. To account for induced changes in the process graph, the rules that type an input of a linear channel must guard against any disturbance of Invariants 1 and 2. Because the two invariants guarantee that parents do not overlap with their descendants in terms of acquired resources, they prevent any exchange of acquired channels. We thus restrict \(\otimes \) and \(\multimap \) to the exchange of channels that have not yet been acquired. This is not a limitation since, as we will see below, shared channel output and input are unrestricted.
Even with the above restriction in place, we still have to make sure that a received channel satisfies Invariant 2. If we were to state a corresponding premise on the receiving rules, invertibility of the rules would be disturbed. To uphold invertibility, we impose a well-formedness condition on session types that ensures for a session of type \(A_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}@{\omega _l}\updownarrow ^{\omega _r}_{\omega _p} \otimes B_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\omega _m}\updownarrow ^{\omega _v}_{\omega _u}]\) that \(\omega _v < \omega _p\) and, analogously, for a session of type \(A_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}@{\omega _l}\updownarrow ^{\omega _r}_{\omega _p} \multimap B_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\omega _m}\updownarrow ^{\omega _v}_{\omega _u}]\) that \(\omega _v < \omega _p\). Session types are checked to be well-formed upon process definition. Given type well-formedness, we obtain the following rules for \(\multimap \), noting that the right rule enforces Invariant 4 by requiring an empty \(\varPhi \)-context. The rules for \(\otimes \) are dual.Since there are no invariants imposed on the shared context \(\varGamma \), the rules for shared channel output and input are identical to those in \(\mathsf {SILL}_{\mathsf {S}}\). The only differences are that we have two left rules and that the \(\varPhi \)-context of the right rule must be empty to satisfy Invariant 4. The former is merely due to the tracking of possibly aliased sessions in the \(\varPhi \) context.We finally consider the rules for forwarding and spawning. We allow a shared forward between processes that offer the same session at the same worlds. Because forwards have to be world-invariant, however, no well-typed program could ever have a linear forward. The process being forwarded to must be in either of the contexts \(\varPhi \) or \(\varDelta \), and thus satisfies Invariant 2, making it impossible for the world annotations of the forwarder and forwardee to match. We omit linear forwarding and discuss possible future extensions in Sect. 6.The rules for spawning depend on the possible modes of the spawning and spawned processes: Open image in new window specifies how a linear process can spawn another linear process; Open image in new window specifies how a shared processes can spawn another shared process. The rules are checked relative to a process definition found in the signature \(\varSigma \) and to a world substitution mapping \(\gamma : |\varPsi | \rightarrow |\varPsi '|\), such that for each \(\delta \in \varPsi '\) we have \(\varPsi \,\vdash \,\gamma (\delta )\), where \(|\varPsi |\) denotes the field of \(\varPsi \) (i.e., the union of its domain and range). As usual, we lift substitution to types \(\hat{\gamma }(A_m)\), contexts \(\hat{\gamma }(\varGamma )\), and orders \(\hat{\gamma }(\varPsi )\). Both rules ensure that, given the mapping \(\gamma \), the order \(\varPsi \) of the spawning process entails the one of the process definition (\(\varPsi \,\vdash \,\hat{\gamma }(\varPsi ')\)). The linear spawn rule Open image in new window further enforces Invariant 2 for the spawned child. We note that the spawned child enters the linear context \(\varDelta \) in the spawning process’ continuation since no aliases to such a process can exist at this point.In the companion technical report [4], we provide a variant of rule Open image in new window for the case of a linear recursive tail call. Without linear forwarding, a linear tail call can no longer be implicitly “de-sugared” into a spawn and a linear forward [2, 22, 52], but must be accounted for explicitly. In the report, we also provide the rules for checking process definitions. Those rules make sure that the process’ world order is acyclic, that the types of the providing session and argument sessions are well-formed, and that the process satisfies Invariants 1 and 2.

3.3 Dining Philosophers in \(\mathsf {SILL}_{\mathsf {S}^+}\)

Having introduced our type system, we revisit the dining philosophers from Sect. 1 and show how to program the example in \(\mathsf {SILL}_{\mathsf {S}^+}\), ensuring that the program will run without deadlocks. The code is given in Fig. 4. We note the world annotations in the signature of the process definitions. For instance,

indicates that, given the order \(\delta _0< \delta _1< \delta _2 < \delta _3\), process \( thinking \) provides a session of type \(\mathsf {phil}[{\delta _0}\updownarrow ^{\delta _2}_{\delta _1}]\) and uses two shared channel references of type \(\mathsf {sfork}[{\delta _1}\updownarrow ^{\delta _3}_{\delta _3}]\) and \(\mathsf {sfork}[{\delta _2}\updownarrow ^{\delta _3}_{\delta _3}]\). The two \(\cdot \) signify that neither acquired nor linear channel references are given as arguments. The signature indicates that the two shared fork references reside at different worlds, such that the world of the first one is smaller than the one of the second.

Let’s briefly convince ourselves that the two acquires in process \( thinking \) in Fig. 4 are type-correct. For each acquire we have to show that: the world of the resource to be acquired is within the acquiring process’ range; the \(\mathsf {max}\) of the acquiring process is smaller than the \(\mathsf {min}\) of the acquired resource; and, that the \(\mathsf {self}\) of the acquired resource is larger than those of all already acquired resources. We can convince ourselves that all those conditions are readily met. We note, however, that if we were to swap the two acquires, the program would not type-check.
Fig. 4.

Deadlock-free version of dining philosophers in \(\mathsf {SILL}_{\mathsf {S}^+}\).

Let us once more set the table for three philosophers and three forks. We execute this code in a process with world annotations \([{\delta _a}\updownarrow ^{\delta _b}_{\delta _b}]\) such that \(\delta _a < \delta _b\). We first create new worlds and define their order:
We then spawn the forks, each residing at a different world, such that the \(\mathsf {max}\) world of a fork is higher than the \(\mathsf {self}\) of the highest fork, ensuring Invariant 2 for the philosopher processes that we spawn afterwards:
When we spawn the philosophers, we ensure that \(P_0\) is going to pick up fork \(F_1\) and then \(F_2\), \(P_1\) is going to pick up \(F_2\) and then \(F_3\), and \(P_2\) is going to pick up \(F_1\) and then \(F_3\).
We note that the deadlocking spawn

is type-incorrect since we would substitute both \(\mathsf {w_1}\) and \(\mathsf {w_3}\) for \(\delta _1\) and \(\mathsf {w_3}\) and \(\mathsf {w_1}\) for \(\delta _2\), which violates the ordering constraints put in place by typing.

3.4 Dynamics

We now give the dynamics of \(\mathsf {SILL}_{\mathsf {S}^+}\). Our current system is based on a synchronous dynamics. While this choice is more conservative, it allows us to narrow the complexity of the problem at hand.

As in \(\mathsf {SILL}_{\mathsf {S}}\), we use multiset rewriting rules [12] to capture the dynamics of \(\mathsf {SILL}_{\mathsf {S}^+}\) (see Sect. 2). Multiset rewriting rules represent computation in terms of local state transitions between configurations of processes, only mentioning the parts of a configuration they rewrite. We use the predicates \(\mathsf {proc}( a_m , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, P_{a_m} )\) and \(\mathsf {unavail}( a_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}})\) to define the states of a configuration (see Sect. 5.1). The former denotes a process executing term P that provides along channel \(a_m\) at mode m with worlds \(\mathsf {w_{a_1}}\), \(\mathsf {w_{a_2}}\), and \(\mathsf {w_{a_3}}\) for \(\mathsf {self}\), \(\mathsf {min}\), and \(\mathsf {max}\), respectively. The latter acts as a placeholder for a shared process providing along channel \(a_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}\) with worlds \(\mathsf {w_{a_1}}\), \(\mathsf {w_{a_2}}\), and \(\mathsf {w_{a_3}}\) for \(\mathsf {self}\), \(\mathsf {min}\), and \(\mathsf {max}\), respectively, that is currently unavailable. We note that since worlds are also run-time artifacts, they must occur as part of the state-defining predicates.

Fig. 5 lists selected rules of the dynamics. Since the rules remain largely the same as those of \(\mathsf {SILL}_{\mathsf {S}}\), apart from the world annotations that are “threaded through” unchanged, we only discuss the rules that actually differ from the \(\mathsf {SILL}_{\mathsf {S}}\) rules. The interested reader can find the remaining rules in the companion technical report [4].
Fig. 5.

Selected multiset rewriting rules of \(\mathsf {SILL}_{\mathsf {S}^+}\).

Noteworthy are the rules Open image in new window and Open image in new window for creating and relating worlds, respectively. Rule Open image in new window creates a fresh world, which will be globally available in the configuration. Rule Open image in new window , on the other hand, updates the configuration’s order with the pair \(\mathsf {w} < \mathsf {w}'\). Rule Open image in new window , lastly, substitutes actual worlds for world variables in the body of the spawned process, using the substitution mapping \(\gamma \) defined earlier. It relies on the existence of a corresponding definition predicate for each process definition contained in the signature \(\varSigma \). We note that the substitution \(\gamma \) in rule Open image in new window instantiates the appropriate world variables in the spawned process P.

4 Extended Example: An Imperative Shared Queue

We now develop a typical imperative-style implementation of a queue that uses a list data structure internally to store the queue’s elements and has shared references to the front and the back of the list for concurrent dequeueing and enqueueing, respectively. The session types for the queue and the list are2
The list is implemented in terms of processes \( empty \) and \( elem \), denoting the empty list and a cons cell, respectively. We show the more interesting case of a cons cell (Fig. 6). The queue is defined by processes \( head \) (Fig. 7) and \( queue \_ proc \) (Fig. 8), the latter being the queue’s interface to its clients.
Fig. 6.

Imperative queue – \( elem \) process.

Fig. 7.

Imperative queue – \( head \) process.

Fig. 8.

Imperative queue – \( queue\_proc \) process and \( client \) process.

We can now define a client (Fig. 8) for the queue, assuming existence of a corresponding shared session type \(\mathsf {item}\) and a process \( item\_proc \) offering a session of type \(\mathsf {item}[{\delta _3}\!\!\!\updownarrow ^{\delta _4}_{\delta _4}]\). The client instantiates the queue at world \(\delta _b\), allowing it to acquire resources at world \(\mathsf {w_1}\), which is exactly the world at which process \( queue\_proc \) instantiates the list. Given that the client itself resides at world \(\delta _a\), which is smaller than the queue’s world \(\delta _b\), the client is allowed to acquire the queue, which in turn will acquire the list to satisfy any requests by the client.

The example showcases a paradigmatic use of several collaborators, where collaborators can hold resources while they “talk down” in the tree. In particular, as illustrated in Fig. 9, the clients \(C_1\), \(C_2\), and \(C_3\) compete for resources at world \(\delta _b\), i.e., the queue Q. On the other hand, a client \(C_i\) collaborates with the queue Q, the list elements \(L_i\), and the items \(I_i\), since they do not overlap in the set of resources they may acquire: a client acquires resources at \(\delta _b\), a queue resources at \(\mathsf {w_1}\), a list resources at \(\mathsf {w_2}\), and an item resources at \(\mathsf {w_4}\), and we have \(\delta _a< \delta _b< \mathsf {w_1}< \mathsf {w_2}< \mathsf {w_3} < \mathsf {w_4}\). We note in particular that the setup prevents a list element from acquiring its successor, forcing linear access through the queue.

5 Semantics

In this section, we discuss the meta-theoretical properties of \(\mathsf {SILL}_{\mathsf {S}^+}\), focusing on deadlock-freedom. The companion technical report [4] provides further details.
Fig. 9.

Run-time process graph for imperative queue (see Fig. 3 for legend).

5.1 Configuration Typing and Preservation

Given the hierarchy between mode \(\mathsf {S}\) and \(\mathsf {L}\) and the fact that shared processes cannot depend on linear processes, we divide a configuration into a shared part \(\varLambda \) and a linear part \(\varTheta \). We use the typing judgment \(\varPsi ; \varGamma \vDash \varLambda ; \varTheta \; {:}\,\!{:} \; \varGamma ; \varPhi , \varDelta \) to type configurations. The judgment expresses that a well-formed configuration \(\varLambda ; \varTheta \) provides the shared channels in \(\varGamma \) and the linear channels in \(\varPhi \) and \(\varDelta \). A configuration is type-checked relative to all shared channel references and a global order \(\varPsi \). While type-checking is compositional insofar as each process definition can be type-checked separately, solely relying on the process’ local \(\varPsi \) (and \(\varGamma \)), at run-time, the entire order that a configuration relies upon is considered. We give the configuration typing rules in Fig. 10.

Our progress theorem crucially depends on the guarantee that the Invariants 1 and 2 from Sect. 3 hold for every linear process in a configuration’s tree. This is expressed by the premises Open image in new window and Open image in new window in rule Open image in new window , based on the Definitions 1 and 2 below that restate Invariants 1 and 2 for an entire configuration. We note that Invariant 2 is based on the set of all transitive children (i.e., descendants) of a process. We formally define the notion of a descendant inductively over a well-typed linear configuration. The interested reader can find the definition in the companion technical report [4].

Invariant 1

(\(\mathsf {min}(\mathsf {parent})\le \mathsf {self}(\mathsf {acquired\_child})\le \mathsf {max}(\mathsf {parent})\)). If \(\varPsi ; \, \varGamma \vDash \varTheta \; {:}\,\!{:} \; \varPhi , \varDelta \) and for any \(\mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, P_{a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}} )\in \varTheta \) such that \(\varPsi ; \, \varGamma ; \, \varPhi _1; \, \varDelta _1 \vdash P_{a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}} \; {:}\,\!{:} \; (a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}: A_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}])\), \(\mathsf {Inv}_{{1}}(\mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, P_{a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}} ))\) holds if an only if for every acquired resource \(b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}: B_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\mathsf {w_{b_1}}}\updownarrow ^{\mathsf {w_{b_3}}}_{\mathsf {w_{b_2}}}] \in \varPhi _1\) it holds that \(\varPsi ^* \,\vdash \,\mathsf {w_{a_2}} \le \mathsf {w_{b_1}} \le \mathsf {w_{a_3}}\). Moreover, if \(P_{a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}} = x_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\leftarrow \mathsf {acquire} \, c_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}\,; Q_{ x_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} }\), for a \((c_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}: {\uparrow }^{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}C_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\mathsf {w_{c_1}}}\updownarrow ^{\mathsf {w_{c_3}}}_{\mathsf {w_{c_2}}}]) \in \varGamma \), then, for every acquired resource \(b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}: B_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\mathsf {w_{b_1}}}\updownarrow ^{\mathsf {w_{b_3}}}_{\mathsf {w_{b_2}}}] \in \varPhi _1\), it holds that \(\varPsi ^+ \,\vdash \,\mathsf {w_{b_1}} < \mathsf {w_{c_1}}\) and that \(\varPsi ^* \,\vdash \,\mathsf {w_{a_2}} \le \mathsf {w_{c_1} \le \mathsf {w_{a_3}}}\).

Fig. 10.

Configuration typing

Invariant 2

(max(parent) < minima(descendants)). If \(\varPsi ; \, \varGamma \vDash \varTheta \; {:}\,\!{:} \; \varPhi , \varDelta \) and for any \(\mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, P_{a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}} ) \in \varTheta \) and that process’ descendants \((\varPsi ; \, \varGamma \vDash \varTheta \; {:}\,\!{:} \; \varPhi , \varDelta ) \, \vartriangleright \, a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} \; = \; (\varPhi ', \varDelta ')\), \(\mathsf {Inv}_{{2}}(\mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, P_{a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}} ))\) holds iff for every descendant \(b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}: B_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\mathsf {w_{b_1}}}\updownarrow ^{\mathsf {w_{b_3}}}_{\mathsf {w_{b_2}}}] \in (\varPhi ', \varDelta ')\) it holds that \(\varPsi ^+ \,\vdash \,\mathsf {w_{a_3}} < \mathsf {w_{b_2}}\).

Our preservation theorem states that Invariants 1 and 2 are preserved for every linear process in the configuration along transitions. Moreover, the theorem expresses that the types of the providing linear channels \(\varPhi \) and \(\varDelta \) are maintained along transitions and that new shared channels and worlds may be allocated. The proof relies, in particular, on session types being strictly equi-synchronizing, on a process’ type well-formedness and assurance that the process’ \(\mathsf {min}\) world is less than or equal to its \(\mathsf {max}\) world.

Theorem 5.1

(Preservation). If \(\varPsi ; \, \varGamma \vDash \varLambda ; \, \varTheta \; {:}\,\!{:} \; \varGamma ; \, \varPhi , \varDelta \) and \(\varLambda ; \varTheta \longrightarrow \varLambda '; \varTheta '\), then \(\varPsi '; \, \varGamma ' \vDash \varLambda '; \, \varTheta ' \; {:}\,\!{:} \; \varGamma '; \, \varPhi , \varDelta \), for some \(\varLambda '\), \(\varTheta '\), \(\varPsi '\), and \(\varGamma '\).

5.2 Progress

In our development so far we have distilled the two scenarios of interdependencies between processes that can lead to deadlocks: cyclic acquisitions and interdependent acquisitions and synchronizations. This has lead to the development of a type system that ingrains the notions of competitors and collaborators, such that the former compete for a set of resources whereas the latter do not overlap in the set of resources they acquire. Our type system then ties these notions to a configuration’s linear process tree such that collaborators stand in a parent-descendant relationship to each other and competitors in a sibling/cousin relationship. In this section, we prove that this orchestration is sufficient to rule out any of the aforementioned interdependencies.

To this end we introduce the notions of red and green arrows that allow us to reason about process interdependencies in a configuration’s tree. A red arrow points from a linear \(\mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, Q )\) to a linear \(\mathsf {proc}( b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{b_1}}}\updownarrow ^{\mathsf {w_{b_3}}}_{\mathsf {w_{b_2}}}}, \, P )\), if the former is attempting to acquire a resource held by the latter and, consequently, is waiting for the latter to release that resource. A green arrow points from a linear \(\mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, Q )\) to a linear \(\mathsf {proc}( b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{b_1}}}\updownarrow ^{\mathsf {w_{b_3}}}_{\mathsf {w_{b_2}}}}, \, P )\), if the former is waiting to synchronize with the latter. We define these arrows formally as follows:

Definition 5.2

(Acquire Dependency — “Red Arrow”). Given a well-formed and well-typed configuration \(\varPsi ; \varGamma \vDash \varLambda ; \varTheta \; {:}\,\!{:} \; \varGamma ; \varPhi , \varDelta \), there exists a waiting-due-to-acquire relation \(\mathcal {A}(\varTheta )\) among linear processes in \(\varTheta \) at run-time such that
$$ \mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, x_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} \leftarrow \mathsf {acquire}\; c_{\mathchoice{\mathsf {S}}{\mathsf {S}}{\scriptscriptstyle \mathsf {S}}{\scriptscriptstyle \mathsf {S}}}; \, Q_{x_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}} ) <_{{\mathchoice{\mathsf {\mathcal {A}}}{\mathsf {\mathcal {A}}}{\scriptscriptstyle \mathsf {\mathcal {A}}}{\scriptscriptstyle \mathsf {\mathcal {A}}}}} \mathsf {proc}( b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{b_1}}}\updownarrow ^{\mathsf {w_{b_3}}}_{\mathsf {w_{b_2}}}}, \, P\langle c_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\rangle ) $$
where \(P\langle c_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\rangle \) denotes a process term with an occurrence of channel \(c_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\).

Definition 5.3

(Synchronization Dependency — “Green Arrow”). Given a well-formed and well-typed configuration \(\varPsi ; \varGamma \vDash \varLambda ; \varTheta \; {:}\,\!{:} \; \varGamma ; \varPhi , \varDelta \), there exists a waiting-due-to-synchronization relation \(\mathcal {S}(\varTheta )\) among linear processes in \(\varTheta \) at run-time such that
$$\begin{aligned} \mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, \_ \langle b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\rangle ; Q )&<_{{\mathchoice{\mathsf {\mathcal {S}}}{\mathsf {\mathcal {S}}}{\scriptscriptstyle \mathsf {\mathcal {S}}}{\scriptscriptstyle \mathsf {\mathcal {S}}}}} \mathsf {proc}( b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{b_1}}}\updownarrow ^{\mathsf {w_{b_3}}}_{\mathsf {w_{b_2}}}}, \, \_ \langle \lnot b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\rangle ; P ) \\ \mathsf {proc}( b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{b_1}}}\updownarrow ^{\mathsf {w_{b_3}}}_{\mathsf {w_{b_2}}}}, \, \_ \langle b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\rangle ; P )&<_{{\mathchoice{\mathsf {\mathcal {S}}}{\mathsf {\mathcal {S}}}{\scriptscriptstyle \mathsf {\mathcal {S}}}{\scriptscriptstyle \mathsf {\mathcal {S}}}}} \mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, \_ \langle \lnot b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\rangle ; Q \langle b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\rangle ) \nonumber \end{aligned}$$
where \(P\langle a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\rangle \) denotes a process term with an occurrence of channel \(b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}\), \(\_\langle a \rangle ; \, P\) a process term that currently executes an action along channel a, and \(\_\langle \lnot a \rangle ; \, P\) a process term whose currently executing action does not involve the channel a.

It may be helpful to consult Fig. 3 at this point and note the semantic difference between the violet arrows in that figure and the red arrows discussed here. Whereas violet arrows point from the acquiring process to the resource being acquired, red arrows point from the acquiring process to the process that is holding the resource. Thus, violet arrows can go out of the tree, while red arrows stay within. Given the definitions of red and green arrows, we can define the relation \(\mathcal {W}(\varTheta )\) on the configuration’s tree, which contains all process pairs that are in some way waiting for each other:

Definition 5.4

(Waiting Dependency). Given a well-formed and well-typed configuration \(\varPsi ; \varGamma \vDash \varLambda ; \varTheta \; {:}\,\!{:} \; \varGamma ; \varPhi , \varDelta \), there exists a waiting relation \(\mathcal {W}(\varTheta )\) among processes in \(\varTheta \) at run-time such that \(\mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, P ) <_{{\mathchoice{\mathsf {\mathcal {W}}}{\mathsf {\mathcal {W}}}{\scriptscriptstyle \mathsf {\mathcal {W}}}{\scriptscriptstyle \mathsf {\mathcal {W}}}}} \mathsf {proc}( b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{b_1}}}\updownarrow ^{\mathsf {w_{b_3}}}_{\mathsf {w_{b_2}}}}, \, Q )\),
  • if \(\mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, P ) <_{{\mathchoice{\mathsf {\mathcal {A}}}{\mathsf {\mathcal {A}}}{\scriptscriptstyle \mathsf {\mathcal {A}}}{\scriptscriptstyle \mathsf {\mathcal {A}}}}} \mathsf {proc}( b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{b_1}}}\updownarrow ^{\mathsf {w_{b_3}}}_{\mathsf {w_{b_2}}}}, \, Q )\), or

  • if \(\mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, P ) <_{{\mathchoice{\mathsf {\mathcal {S}}}{\mathsf {\mathcal {S}}}{\scriptscriptstyle \mathsf {\mathcal {S}}}{\scriptscriptstyle \mathsf {\mathcal {S}}}}} \mathsf {proc}( b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{b_1}}}\updownarrow ^{\mathsf {w_{b_3}}}_{\mathsf {w_{b_2}}}}, \, Q )\).

Having defined the relation \(\mathcal {W}(\varTheta )\), we can now state the key lemma underlying our progress theorem, indicating that \(\mathcal {W}(\varTheta )\) is acyclic in a well-formed and well-typed configuration.

Lemma 5.5

(Acyclicity of \(\mathcal {W}(\varTheta )\)). If \(\varPsi ; \, \varGamma \vDash \varLambda ; \, \varTheta \; {:}\,\!{:} \; \varGamma ; \, \varPhi , \varDelta \), then \(\mathcal {W}(\varTheta )\) is acyclic.

We focus on explaining the main idea of the proof here. The proof proceeds by induction on \(\varPsi ; \varGamma \vDash \varTheta \; {:}\,\!{:} \; \varPhi , \varDelta \), assuming for the non-empty case \(\varPsi ; \varGamma \vDash \varTheta , \mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, P_{a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}} ) \; {:}\,\!{:} \; (\varPhi , \varDelta , a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}: A_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}[{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}])\) that \(\mathcal {W}(\varTheta )\) is acyclic, by the inductive hypothesis. We then know that there cannot exist any paths of green and red arrows in \(\varTheta \) that form a cycle, and we have to show that there is no way of introducing such a cyclic path by adding node \(\mathsf {proc}( a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}} , \, \mathsf {{\mathsf {w_{a_1}}}\updownarrow ^{\mathsf {w_{a_3}}}_{\mathsf {w_{a_2}}}}, \, P_{a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}} )\) to the configuration \(\varTheta \). In particular, the proof considers all possible new arrows that may be introduced by adding the node and that are necessary for creating a cycle, showing that such arrows cannot come about in a well-typed configuration.

We illustrate the reasoning for the two selected cases shown in Fig. 11. Case (a) represents a case in which process \(P_{a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\) is waiting to synchronize with its child \(P_{b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\) while holding a resource a descendant of \(P_{b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\) or \(P_{b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\) itself wants to acquire. However, this scenario cannot come about in a well-typed configuration because \(P_{a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\) and \(P_{b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\) are collaborators and thus cannot overlap in resources they acquire. Case (b) represents a case in which process \(P_{a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\) is waiting to synchronize with its child \(P_{b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\) while another child, process \(P_{c_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\), is waiting to synchronize with \(P_{a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\). Given acyclicity of \(\mathcal {W}(\varTheta )\), a necessary condition for a cycle to form is that there already must exist a red arrow \(\mathbf C \) in the configuration that connects the subtrees in which the siblings \(P_{b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\) and \(P_{c_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\) reside. However, this scenario cannot come about in a well-typed configuration because \(P_{b_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\) and \(P_{c_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\) are competitors, forcing \(P_{c_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\) or any of its descendant to release a resource before synchronizing with \(P_{a_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}}\). These arguments are made precise in various lemmas in [4].
Fig. 11.

Two prototypical cases in proof of acyclicty of \(\mathcal {W}(\varTheta )\).

Given acyclicity of \(\mathcal {W}(\varTheta )\), we can state and prove the following strong progress theorem. The theorem relies on the notion of a poised process, a process currently executing an action along its offering channel, and distinguishes a configuration only consisting of the top-level, linear “main” process from one that consists of several linear processes. We use \(|\varTheta |\) to denote the cardinality of \(\varTheta \):

Theorem 5.6

(Progress). If \(\varPsi ; \varGamma \vDash \varLambda ; \varTheta \; {:}\,\!{:} \; (\varGamma ; c_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}: \mathbf {1}[{\mathsf {w_{c_1}}}\updownarrow ^{\mathsf {w_{c_3}}}_{\mathsf {w_{c_2}}}])\), then either
  • \(\varLambda \longrightarrow \varLambda '\), for some \(\varLambda '\), or

  • \(\varLambda \) is poised and
    • if \(|\varTheta | = 1\), then either \(\varLambda ; \varTheta \longrightarrow \varLambda '; \varTheta '\), for some \(\varLambda '\) and \(\varTheta '\), or \(\varTheta \) is poised, or

    • if \(|\varTheta | > 1\), then \(\varLambda ; \varTheta \longrightarrow \varLambda '; \varTheta '\), for some \(\varLambda '\) and \(\varTheta '\).

The theorem indicates that, as long as there exist at least two linear processes in the configuration, the configuration can always step. If the configuration only consists of the main process, then this process will become poised (i.e., ready to close), once all sub-computations are finished. The proof of the theorem relies on the acyclicity of \(\mathcal {W}(\varTheta )\) and the fact that all sessions must be strictly equi-synchronizing.

6 Additional Discussion

Linear Forwarding. Our current formalization does not include linear forwarding because a forward changes the process tree and thus endangers the invariants imposed on it. This means that certain programs from the purely linear fragment may not type-check in our system. However, the correspondingly \(\eta \)-expanded versions of these programs should be expressible and type-checkable in \(\mathsf {SILL}_{\mathsf {S}^+}\). As part of future work, we want to explore the addition of the linear forwardwhich allows forwarding to processes that are known to not yet be aliased and whose world annotations meet the premise \(\varPsi ^+ \,\vdash \,\omega _n < \omega _u\). Restricting to processes in \(\varDelta \) should uphold Invariant 1, while the premise of the rule should uphold Invariant 2. However, this change will affect the inner working of the proofs, the use of inversion in particular, which might have far-reaching consequences that need to be carefully explored.

Unbounded Process Networks and World Polymorphism. The typing discipline presented in the previous sections, while rich enough to account for a wide range of interesting programs, cannot type programs that spawn a statically undetermined number of shared sessions that are then to be used. For instance, while we can easily type a configuration of any given number of dining philosophers (Sect. 3.3), we cannot type a recursive process in which the number of philosophers (and forks) is potentially unbounded (as done in [21, 38]), due to the way worlds are created and propagated across processes.

The general issue lies in implementing a statically unbounded network of processes that interact with each other. These interactions require the processes to be spawned at different worlds which must be generated dynamically as needed. To interact with such a statically unknown number of processes uniformly, their offering channels must be stored in a list-like structure for later use. However, in our system, recursive types have to be invariant with respect to worlds. For instance, in a recursive type such as \(T = A_{\mathchoice{\mathsf {L}}{\mathsf {L}}{\scriptscriptstyle \mathsf {L}}{\scriptscriptstyle \mathsf {L}}}@{\omega _l}\updownarrow ^{\omega _r}_{\omega _p} \otimes T\), the worlds \(\omega _l\), \(\omega _p\), \(\omega _r\) are fixed in the unfoldings of T. Thus, we cannot type a world-heterogeneous list and cannot form such process networks.

Given that the issues preventing us from typing such unbounded networks lie in problems of world invariance, the natural solution is to explore some form of world polymorphism, where types can be parameterized by worlds which are instantiated at a later stage. Such techniques have been studied in the context of hybrid logical processes in [7] by considering session types of the form \(\forall \delta .A\) and \(\exists \delta .A\), sessions that are parametric in the world variable \(\delta \), that is instantiated by a concrete reachable world at runtime. While their development cannot be mapped directly to our setting, it is a promising avenue of future work.

7 Related Work

Behavioral Type Analysis of Deadlocks. The addition of channel usage information to types in a concurrent, message-passing setting was pioneered by Kobayashi and Igarashi [30, 34], who applied the idea to deadlock prevention in the \(\pi \)-calculus and later to more general properties [31, 32], giving rise to a generic system that can be instantiated to produce a variety of concrete typing disciplines for the \(\pi \)-calculus (e.g., race detection, deadlock detection, etc.).

This line of work types \(\pi \)-calculus processes with a simplified form of process (akin to CCS [42] terms without name restriction) that characterizes the input/output behavior of processes. These types are augmented with abstract data that pertain to the relative ordering of channel actions, with the type system ensuring that the transitive closure of such orderings forms a strict partial order, ensuring deadlock-freedom (i.e., communication succeeds unless a process diverges). Building on this, Kobayashi et al. proposed type systems that ensure a stronger property dubbed lock-freedom [35] (i.e., communication always succeeds), and variants that are amenable to type inference [36, 39]. Kobayashi [37] extended this latter system to more accurately account for recursive processes while preserving the existence of a type inference algorithm.

Our system draws significant inspiration from this line of work, insofar as we also equip types with abstract ordering data on certain communication actions, which is then statically enforced to form a strict partial order. We note that our \(\mathsf {SILL}_{\mathsf {S}^+}\) language differs sufficiently from the pure \(\pi \)-calculus in terms of its constructs and semantics to make the formulation of a direct comparison or an immediate application of their work unclear (e.g., [37] uses replication to encode recursive processes). Moreover, we integrate this style of order-based reasoning with both linear and shared session typing, which interact in non-trivial ways (especially in the presence of recursive types and recursive process definitions).

In terms of typability, enforcing session fidelity can be a double-edged sword: some examples of the works above can be transposed to \(\mathsf {SILL}_{\mathsf {S}^+}\) with mostly cosmetic changes and without making use of shared sessions (e.g., a parallel implementation of factorial that recurses via replication but always answers on a private channel); others are incompatible with linear sessions and require the use of shared sessions via the acquire-release discipline, which entails a more indirect but still arguably faithful modelling of the original \(\pi \)-calculus behavior; some examples, however, cannot be easily adapted to the shared session discipline (e.g., \(*c?(x,y).x?(z).y?(z) \mid *c?(x,y).y?(z).x?(z)\) is typable in [37], where x?(z) denotes input on x and \(*c?(x,y)\) denotes replicated input) and their transcription, while possible, would be too far removed from the original term to be deemed a faithful representation. Recursive processes are known to produce patterns that can be challenging to analyze using such order-based techniques. The work of [21, 38] specializes Kobayashi’s system to account for potentially unbounded process networks with non-trivial forms of sharing. Such systems are not typable in our work (see Sect. 6 for additional discussion on this topic).

The work of Padovani [44] develops techniques inspired by [35, 37] to develop a typing system for deadlock (and lock) freedom for the linear \(\pi \)-calculus where (linear) channels must be used exactly once. By enforcing this form of linearity, the resulting system uses only one piece of ordering data per channel usage and can easily integrate a form of channel polymorphism that accounts for intricate cyclic interleavings of recursive processes. The combination of manifest sharing and linear session typing does not seem possible without the use of additional ordering data, and the lack of single-use linear channels make the robust channel polymorphism of [44] not feasible in our setting.

Dardha and Gay [15] recently integrated a system of Kobayashi-style orderings in a logical session \(\pi \)-calculus based on classical linear logic, extended with the ability to form cyclic dependencies of actions on linear session channels (Atkey et al. [1] study similar cycles but do not consider deadlock-freedom), without the need for new process constructs or an acquire-release discipline. Their work considers only a restricted form of replication common in linear logic-based works, not including recursive types nor recursive process definitions. This reduces the complexity of their system, at the cost of expressiveness. We also note that the cycles enabled by their system are produced by processes sharing multiple linear names. Since linearity is still enforced, they cannot represent the more general form of cycles that exploit shared channels, as we do.

A comparative study of session typing and Kobayashi-style systems in terms of sharing was developed by Dardha and Pérez [16], showing that such order-based techniques can account for sharing in ways that are out of reach of both classical session typing and pure logic-based session typing. Our system (and that of [15]) aims to combine the heightened power of Kobayashi-style systems with the benefits of session typing, which seems to be better suited as a typing discipline for a high-level programming language [18].

Progress and Session Typing. To address limitations of classical binary session types, Honda et al. [27] introduced multiparty session types, where sessions are described by so-called global types that capture the interactions between an arbitrary number of session participants. Under some well-formedness constraints, global types can be used to ensure that a collection of processes correctly implements the global behavior in a deadlock-free way. However, these global type-based approaches do not ensure deadlock freedom in the presence of higher-order channel passing or interleaved multiparty sessions. Coppo et al. [13] and Bettini et al. [6] develop systems that track usage orders among interleaved multiparty sessions, ruling out cyclic dependencies that can lead to deadlocks. The resulting system is quite intricate, since it combines the full multiparty session theory with the order tracking mechanism, interacts negatively with recursion (essentially disallowing interleaving with recursion) and, by tracking order at the multiparty session-level, ends up rejecting various benign configurations that can be accounted for by our more fine-grained analysis. We also highlight the analyses of Vieira and Vasconcelos [54] and Padovani et al. [45] that are more powerful than the approaches above, at the cost of a more complex analysis based on conversation types [10] (themselves a partial-order based technique).

Static Analysis of Concurrent Programs. Lange et al. [40, 41] develop a deadlock detection framework applied to the Go programming language. Their work distills CCS processes from programs which are then checked for deadlocks by a form of symbolic execution [40] and model-checked against modal \(\mu \)-calculus formulae [41] which encode deadlock-freedom of the abstracted process (among other properties of interest). Their abstraction introduces some distance between the original program and the analysed process and so the analysis is sound only for certain restricted program fragments, excluding any combination of recursion and process spawning. Our direct approach does not suffer from this limitation.

de’Liguoro and Padovani [17] develop a typing discipline for deadlock-freedom in a setting where processes exchange messages via unordered mailboxes. Their calculus subsumes the actor model and their analysis combines both so-called mailbox types and specialized dependency graphs to track potential cycles between mailboxes in actor-based systems. The unordered nature of actor-based communication introduces significant differences wrt our work, which crucially exploits the ordering of exchanged messages.

8 Concluding Remarks

In this paper we have developed the concept of manifest deadlock-freedom in the context of the language \(\mathsf {SILL}_{\mathsf {S}^+}\), a shared session-typed language, showcasing both the programming methodology and the expressiveness of our framework with a series of examples. Deadlock-freedom of well-typed programs is established by a novel abstraction of so-called green and red arrows to reason about the interdependencies between processes in terms of linear and shared channel references.

In future work, we plan to address some of the limitations of the interactions of deadlock-free shared sessions with recursion, by considering promising notions of world polymorphism and world communication. We also plan to study the problem of world inference and the inclusion of a linear forwarding construct.


  1. 1.

    We have made sure to make the different concepts distinguishable in greyscale mode.

  2. 2.

    We adopt polymorphism for the example without formal treatment since it is orthogonal and has been studied for session types in [23, 46].


  1. 1.
    Atkey, R., Lindley, S., Morris, J.G.: Conflation confers concurrency. In: Lindley, S., McBride, C., Trinder, P., Sannella, D. (eds.) A List of Successes That Can Change the World. LNCS, vol. 9600, pp. 32–55. Springer, Cham (2016). Scholar
  2. 2.
    Balzer, S., Pfenning, F.: Manifest sharing with session types. Proc. ACM Program. Lang. (PACMPL) 1(ICEP), 37:1–37:29 (2017)Google Scholar
  3. 3.
    Balzer, S., Pfenning, F., Toninho, B.: A universal session type for untyped asynchronous communication. In: 29th International Conference on Concurrency Theory (CONCUR). LIPIcs, pp. 30:1–30:18. Schloss Dagstuhl - Leibniz-Zentrum fuer Informatik (2018)Google Scholar
  4. 4.
    Balzer, S., Toninho, B., Pfenning, F.: Manifest deadlock-freedom for shared session types. Technical report CMU-CS-19-102, Carnegie Mellon University (2019)Google Scholar
  5. 5.
    Benton, P.N.: A mixed linear and non-linear logic: proofs, terms and models. In: Pacholski, L., Tiuryn, J. (eds.) CSL 1994. LNCS, vol. 933, pp. 121–135. Springer, Heidelberg (1995). Scholar
  6. 6.
    Bettini, L., Coppo, M., D’Antoni, L., Luca, M.D., Dezani-Ciancaglini, M., Yoshida, N.: Global progress in dynamically interleaved multiparty sessions. In: van Breugel, F., Chechik, M. (eds.) CONCUR 2008. LNCS, vol. 5201, pp. 418–433. Springer, Heidelberg (2008). Scholar
  7. 7.
    Caires, L., Pérez, J.A., Pfenning, F., Toninho, B.: Logic-based domain-aware session types, unpublished draftGoogle Scholar
  8. 8.
    Caires, L., Pfenning, F.: Session types as intuitionistic linear propositions. In: Gastin, P., Laroussinie, F. (eds.) CONCUR 2010. LNCS, vol. 6269, pp. 222–236. Springer, Heidelberg (2010). Scholar
  9. 9.
    Caires, L., Pfenning, F., Toninho, B.: Linear logic propositions as session types. Math. Struct. Comput. Sci. 26(3), 367–423 (2016)MathSciNetCrossRefGoogle Scholar
  10. 10.
    Caires, L., Vieira, H.T.: Conversation types. Theor. Comput. Sci. 411(51–52), 4399–4440 (2010)MathSciNetCrossRefGoogle Scholar
  11. 11.
    Castro, D., Hu, R., Jongmans, S., Ng, N., Yoshida, N.: Distributed programming using role-parametric session types in go: statically-typed endpoint APIs for dynamically-instantiated communication structures. PACMPL 3(POPL), 29:1–29:30 (2019)Google Scholar
  12. 12.
    Cervesato, I., Scedrov, A.: Relating state-based and process-based concurrency through linear logic. Inf. Comput. 207(10), 1044–1077 (2009)CrossRefGoogle Scholar
  13. 13.
    Coppo, M., Dezani-Ciancaglini, M., Yoshida, N., Padovani, L.: Global progress for dynamically interleaved multiparty sessions. Math. Struct. Comput. Sci. 26(2), 238–302 (2016)MathSciNetCrossRefGoogle Scholar
  14. 14.
    Crary, K., Harper, R., Puri, S.: What is a recursive module? In: ACM SIGPLAN Conference on Programming Language Design and Implementation (PLDI), pp. 50–63 (1999)Google Scholar
  15. 15.
    Dardha, O., Gay, S.J.: A new linear logic for deadlock-free session-typed processes. In: Baier, C., Dal Lago, U. (eds.) FoSSaCS 2018. LNCS, vol. 10803, pp. 91–109. Springer, Cham (2018). Scholar
  16. 16.
    Dardha, O., Pérez, J.A.: Comparing deadlock-free session typed processes. In: EXPRESS/SOS, pp. 1–15 (2015)Google Scholar
  17. 17.
    de’Liguoro, U., Padovani, L.: Mailbox types for unordered interactions. In: 32nd European Conference on Object-Oriented Programming, ECOOP 2018, pp. 15:1–15:28 (2018)Google Scholar
  18. 18.
    Gay, S.J., Gesbert, N., Ravara, A.: Session types as generic process types. In: 21st International Workshop on Expressiveness in Concurrency and 11th Workshop on Structural Operational Semantics, EXPRESS/SOS 2014, pp. 94–110 (2014)Google Scholar
  19. 19.
    Gay, S.J., Hole, M.: Subtyping for session types in the \(\pi \)-calculus. Acta Informatica 42(2–3), 191–225 (2005)MathSciNetCrossRefGoogle Scholar
  20. 20.
    Gay, S.J., Vasconcelos, V.T., Ravara, A., Gesbert, N., Caldeira, A.Z.: Modular session types for distributed object-oriented programming. In: 37th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL), pp. 299–312 (2010)Google Scholar
  21. 21.
    Giachino, E., Kobayashi, N., Laneve, C.: Deadlock analysis of unbounded process networks. In: Baldan, P., Gorla, D. (eds.) CONCUR 2014. LNCS, vol. 8704, pp. 63–77. Springer, Heidelberg (2014). Scholar
  22. 22.
    Gommerstadt, H., Jia, L., Pfenning, F.: Session-typed concurrent contracts. In: Ahmed, A. (ed.) ESOP 2018. LNCS, vol. 10801, pp. 771–798. Springer, Cham (2018). Scholar
  23. 23.
    Griffith, D.: Polarized substructural session types. Ph.D. thesis, University of Illinois at Urbana-Champaign (2016)Google Scholar
  24. 24.
    Griffith, D., Pfenning, F.: SILL (2015).
  25. 25.
    Honda, K.: Types for dyadic interaction. In: Best, E. (ed.) CONCUR 1993. LNCS, vol. 715, pp. 509–523. Springer, Heidelberg (1993). Scholar
  26. 26.
    Honda, K., Vasconcelos, V.T., Kubo, M.: Language primitives and type discipline for structured communication-based programming. In: Hankin, C. (ed.) ESOP 1998. LNCS, vol. 1381, pp. 122–138. Springer, Heidelberg (1998). Scholar
  27. 27.
    Honda, K., Yoshida, N., Carbone, M.: Multiparty asynchronous session types. In: 35th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL), pp. 273–284. ACM (2008)Google Scholar
  28. 28.
    Hu, R., Yoshida, N.: Hybrid session verification through endpoint API generation. In: Stevens, P., Wąsowski, A. (eds.) FASE 2016. LNCS, vol. 9633, pp. 401–418. Springer, Heidelberg (2016). Scholar
  29. 29.
    Hu, R., Yoshida, N.: Explicit connection actions in multiparty session types. In: Huisman, M., Rubin, J. (eds.) FASE 2017. LNCS, vol. 10202, pp. 116–133. Springer, Heidelberg (2017). Scholar
  30. 30.
    Igarashi, A., Kobayashi, N.: Type-based analysis of communication for concurrent programming languages. In: Van Hentenryck, P. (ed.) SAS 1997. LNCS, vol. 1302, pp. 187–201. Springer, Heidelberg (1997). Scholar
  31. 31.
    Igarashi, A., Kobayashi, N.: A generic type system for the Pi-calculus. In: Conference Record of POPL 2001: The 28th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pp. 128–141 (2001)Google Scholar
  32. 32.
    Igarashi, A., Kobayashi, N.: A generic type system for the Pi-calculus. Theor. Comput. Sci. 311(1–3), 121–163 (2004)MathSciNetCrossRefGoogle Scholar
  33. 33.
    Jespersen, T.B.L., Munksgaard, P., Larsen, K.F.: Session types for rust. In: 11th ACM SIGPLAN Workshop on Generic Programming, WGP 2015, pp. 13–22 (2015)Google Scholar
  34. 34.
    Kobayashi, N.: A partially deadlock-free typed process calculus. In: Proceedings of the 12th Annual IEEE Symposium on Logic in Computer Science, pp. 128–139 (1997)Google Scholar
  35. 35.
    Kobayashi, N.: A type system for lock-free processes. Inf. Comput. 177(2), 122–159 (2002)MathSciNetCrossRefGoogle Scholar
  36. 36.
    Kobayashi, N.: Type-based information flow analysis for the \(\pi \)-calculus. Acta Inf. 42(4–5), 291–347 (2005)MathSciNetCrossRefGoogle Scholar
  37. 37.
    Kobayashi, N.: A new type system for deadlock-free processes. In: Baier, C., Hermanns, H. (eds.) CONCUR 2006. LNCS, vol. 4137, pp. 233–247. Springer, Heidelberg (2006). Scholar
  38. 38.
    Kobayashi, N., Laneve, C.: Deadlock analysis of unbounded process networks. Inf. Comput. 252, 48–70 (2017)MathSciNetCrossRefGoogle Scholar
  39. 39.
    Kobayashi, N., Saito, S., Sumii, E.: An implicitly-typed deadlock-free process calculus. In: Palamidessi, C. (ed.) CONCUR 2000. LNCS, vol. 1877, pp. 489–504. Springer, Heidelberg (2000). Scholar
  40. 40.
    Lange, J., Ng, N., Toninho, B., Yoshida, N.: Fencing off go: liveness and safety for channel-based programming. In: 44th ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (POPL), pp. 748–761. ACM (2017)Google Scholar
  41. 41.
    Lange, J., Ng, N., Toninho, B., Yoshida, N.: A static verification framework for message passing in go using behavioural types. In: Proceedings of the 40th International Conference on Software Engineering, ICSE 2018, Gothenburg, Sweden, 27 May–03 June 2018, pp. 1137–1148 (2018)Google Scholar
  42. 42.
    Milner, R.: A Calculus of Communicating Systems. LNCS, vol. 92. Springer, Heidelberg (1980). Scholar
  43. 43.
    Neykova, R., Hu, R., Yoshida, N., Abdeljallal, F.: A session type provider: compile-time API generation of distributed protocols with refinements in F#. In: Proceedings of the 27th International Conference on Compiler Construction, CC 2018, pp. 128–138 (2018)Google Scholar
  44. 44.
    Padovani, L.: Deadlock and lock freedom in the linear \(\pi \)-calculus. In: Computer Science Logic - Logic in Computer Science (CSL-LICS), pp. 72:1–72:10 (2014)Google Scholar
  45. 45.
    Padovani, L., Vasconcelos, V.T., Vieira, H.T.: Typing liveness in multiparty communicating systems. In: Kühn, E., Pugliese, R. (eds.) COORDINATION 2014. LNCS, vol. 8459, pp. 147–162. Springer, Heidelberg (2014). Scholar
  46. 46.
    Pérez, J.A., Caires, L., Pfenning, F., Toninho, B.: Linear logical relations and observational equivalences for session-based concurrency. Inf. Comput. 239, 254–302 (2014)MathSciNetCrossRefGoogle Scholar
  47. 47.
    Pfenning, F., Griffith, D.: Polarized substructural session types. In: Pitts, A. (ed.) FoSSaCS 2015. LNCS, vol. 9034, pp. 3–22. Springer, Heidelberg (2015). Scholar
  48. 48.
    Reed, J.: A judgmental deconstruction of modal logic, January 2009., unpublished manuscript
  49. 49.
    Scalas, A., Dardha, O., Hu, R., Yoshida, N.: A linear decomposition of multiparty sessions for safe distributed programming. In: 31st European Conference on Object-Oriented Programming, ECOOP 2017, pp. 24:1–24:31 (2017)Google Scholar
  50. 50.
    Scalas, A., Yoshida, N.: Lightweight session programming in scala. In: 30th European Conference on Object-Oriented Programming, ECOOP 2016, pp. 21:1–21:28 (2016)Google Scholar
  51. 51.
    Toninho, B.: A logical foundation for session-based concurrent computation. Ph.D. thesis, Carnegie Mellon University and New University of Lisbon (2015)Google Scholar
  52. 52.
    Toninho, B., Caires, L., Pfenning, F.: Higher-order processes, functions, and sessions: a monadic integration. In: Felleisen, M., Gardner, P. (eds.) ESOP 2013. LNCS, vol. 7792, pp. 350–369. Springer, Heidelberg (2013). Scholar
  53. 53.
    Vasconcelos, V.T.: Fundamentals of session types. Inf. Comput. 217, 52–70 (2012)MathSciNetCrossRefGoogle Scholar
  54. 54.
    Vieira, H.T., Vasconcelos, V.T.: Typing progress in communication-centred systems. In: De Nicola, R., Julien, C. (eds.) COORDINATION 2013. LNCS, vol. 7890, pp. 236–250. Springer, Heidelberg (2013). Scholar
  55. 55.
    Wadler, P.: Propositions as sessions. In: 17th ACM SIGPLAN International Conference on Functional Programming (ICFP), pp. 273–286. ACM (2012)Google Scholar

Copyright information

© The Author(s) 2019

Open Access This chapter is licensed under the terms of the Creative Commons Attribution 4.0 International License (, which permits use, sharing, adaptation, distribution and reproduction in any medium or format, as long as you give appropriate credit to the original author(s) and the source, provide a link to the Creative Commons license and indicate if changes were made.

The images or other third party material in this chapter are included in the chapter's Creative Commons license, unless indicated otherwise in a credit line to the material. If material is not included in the chapter's Creative Commons license and your intended use is not permitted by statutory regulation or exceeds the permitted use, you will need to obtain permission directly from the copyright holder.

Authors and Affiliations

  1. 1.Carnegie Mellon UniversityPittsburghUSA
  2. 2.NOVA LINCSUniversidade Nova de LisboaLisbonPortugal

Personalised recommendations