=Paper= {{Paper |id=Vol-1720/short7 |storemode=property |title=Deadlock Analysis with Behavioral Types for Actors |pdfUrl=https://ceur-ws.org/Vol-1720/short7.pdf |volume=Vol-1720 |authors=Vincenzo Mastandrea |dblpUrl=https://dblp.org/rec/conf/ictcs/Mastandrea16 }} ==Deadlock Analysis with Behavioral Types for Actors== https://ceur-ws.org/Vol-1720/short7.pdf
    Deadlock analysis with behavioral types for
                      actors.

                             Vincenzo Mastandrea12
        1
            University Nice Sophia Antipolis, CNRS, I3S, UMR 7271, France
                       2
                         INRIA - Sophia Antipolis Méditerranée




1   Introduction

Actors are a powerful computational model for defining distributed and concurrent
systems [1,2]. This model has recently gained prominence, largely thanks to
the success of the programming languages Erlang [3] and Scala [9]. The actor
model relies on a few key principles: (a) an actor encapsulates a number of
data, by granting access only to the methods inside the actor itself; (b) method
invocations are asynchronous, actors retain a queue for storing the invocations to
their methods, which are processed sequentially by executing the corresponding
instances of method bodies. The success of this model originates at the same time
from its simplicity, from its properties, and from its abstraction level. Indeed,
programming a concurrent system as a set of independent entities that only
communicate through asynchronous messages eases the reasoning on the system.
1.1 Problem: Actors and synchronizations.
Actors do not explicitly support synchronization: requests between actors are in
general remote procedure calls. The only guarantee of asynchronous messages is
the causal ordering created by the communication. The retrieval of the result of
an asynchronous message is usually simulated by a callback mechanism where
the invoker sends its identity and the invoked actor sends a result message to
the invoker. However callbacks introduce an inversion of control that makes the
reasoning on the program difficult. Henceforth, providing synchronization as
first-class linguistic primitive is generally preferable.
    Some languages extend the actor model and provide synchronizations by
allowing methods to return values. In general, this is realised by using explicit
futures. A method of an actor returns a special kind of objects called future; in
turn the type system is extended so that some values are tagged with a future
type. A special operation on a future allows the programmer to check whether
the method has finished and at the same time retrieves the method result. The

Copyright c by the paper’s authors. Copying permitted for private and academic pur-
poses.
V. Biló, A. Caruso (Eds.): ICTCS 2016, Proceedings of the 17th Italian Conference on
Theoretical Computer Science, 73100 Lecce, Italy, September 7–9 2016, pp. 257–262
published in CEUR Workshop Proceedins Vol-1720 at http://ceur-ws.org/Vol-1720
258     Vincenzo Mastandrea

drawback of this approach is that programmers must be aware of futures and
must know how to deal with them.
    We study a different extension of the actor model that uses implicit futures
and a wait-by-necessity strategy: the caller synchronizes with a method invoca-
tion only when its returned value is strictly necessary [4]. This strategy does
not require explicit synchronization operators and ad-hoc types: the scheduler
stops the flow of execution when a value to be returned by a method is needed
for computing an expression. The synchronization becomes data-flow oriented:
if some data is accessed and this data is not yet available, the program is au-
tomatically blocked. This way, an actor can return a result containing a future
without worrying about which actor will be responsible for synchronizing with
the result: the synchronization will always occur as late as possible. Replacing a
future by its value is no more an operation that has to be explicitly written by
the programmer, as it automatically happens at some point of the computation
that can be optimized by the designer of the language runtime. We defined a
simple actor calculus with wait-by-necessity synchronizations, called gASP [6].
    While synchronization is useful, if it used improperly it can cause deadlocks
(deadlocks cannot occur in the basic actor model). Deadlock detection is a sensible
issue, in particular because it is hard to verify in languages that admit systems
with unbounded (mutual) recursion and dynamic actor creation.
    The following example illustrates the expressiveness of (implicit) futures and
the difficulties of deadlock analysis:
01 Int fact(Int n, Int r){
02     Act x; Int y;
03     if (n == 0) return r;
04     else { x = new Act(); r = r*n; n = n-1;
05             y = x.fact(n,r); return y; }}

The access to fact(n,1) boils down to exactly n synchronizations. Indeed, since
the value of y is never accessed within the method, the future is returned to the
caller. When accessing the value of fact(n,1) a synchronization is performed on
the result of the first nested invocation fact(n-1,n) which will need to access
the result of the next invocation fact(n-1,n*n-1), and so on. Technically, let
the type of an asynchronous invocation be called future type. Then the type of
fact(n,r) is a recursive future type. Because of this type, it is not possible to
determine at compile time how many explicit synchronizations happen when the
value of fact(x,1) is needed, with x unknown.
1.2 A technique for deadlock analysis.
To address (static-time) deadlock detection of gASP programs, we rely on a
technique that has been already used for pi-calculus [7] and for a concurrent object-
oriented calculus called (core) ABS [5,8]. Our technique consists of two modules:
a front-end type (inference) system that automatically extracts abstract
behavioral descriptions relevant to deadlock analysis from gASP programs, called
behavioral types, and a back-end analyzer of types that computes a model of
dependencies between runtime entities using a fixpoint technique.
    According to this technique, a synchronization between actors α and α0 is
modeled by a dependency pair (α, α0 ), which means that the termination of
                            Deadlock analysis with behavioral types for actors.       259

a process of α depends on the termination of a process of α0 . Programs are
denoted by finite models that are sets of relations on names. If a circular depen-
dency (α1 , α2 ) · · · (αn−1 , αn )(αn , α1 ) is found in one of the relations, then the
corresponding program may manifest a deadlock.
    Synchronization on explicit futures boils down to checking the end of a method
execution and retrieving the returned object, the retrieved object can be a future
itself. On the contrary, with wait-by-necessity, if a computation requires a not-yet
available value then a synchronization occurs, until a proper value is available.
Retrieving this value might require to wait for the termination of several methods.
Indeed, consider the factorial example, let β be the actor needing the value of
fact(n,1). This synchronization requires that β simultaneously synchronizes
with all the actors computing the nested factorial invocations, say β1 , . . . , βn−1 .
A translation from gASP to ABS would require to know statically the number n
of synchronisation to perform. From the analysis point of view, this means that
we have to collect all the dependencies of the form (β, β1 ), (β, β2 ), . . . , (β, βn−1 ).
In [5,8], this collection was done step-by-step by generating a dependency pair
for every explicit synchronization. For synchronization on implicit futures, we
need to generate a sequence of dependence pair when a value is needed, and this
sequence is not bound statically.
1.3 Main contribution.
Addressing adequately implicit futures amounts to define a new type system of
the above program and adapt in a non-trivial way the analyzer. The challenge we
address is the ability to extend the synchronization point so that an unbounded
number of events can be awaited at the same time. Our solution first extends
the behavioural type with fresh future identifiers and to introduce specific types
that identify whether a future is synchronised or not. A method signature also
declares the set of actors and futures it creates to handle the potential unbounded
number of future and actor creations. Then, we exploit the relation that exists
between the number of dependencies of a synchronization and the number of
nested method invocations. Instead of associating dependencies to synchroniza-
tion points, we delegate the production of the dependencies to method invocations,
each contributing with its own dependency. The sequence of dependencies is
unfolded during the analysis. To implement this methods types of gASP carry an
additional formal parameter, called handle, which is instantiated by the actor
requiring the synchronization when this happens. The evaluation of behavioural
types in the analyzer also carries an environment binding future names to their
values (method invocations).


2    Behavioral Types

The deadlock detection technique we present uses abstract descriptions, called
behavioral types, that are associated to programs by a type system. The purpose of
the type system is to collect dependencies between actors and between futures and
actors. At each point of the program, the behavioral type gathers informations on
260       Vincenzo Mastandrea

local synchronizations and on actors potentially running in parallel. We perform
such an analysis for each method body, gathering the behavioral information at
each point of the program.
                                                     
    A behavioral type program is a pair L, Θ  L , where L is a finite set of method
behaviors m(α, x̄, X) = (ν ϕ)(Θm  Lm ), with α, x̄, X being the formal parameters of
m, Θm the future environment of m, Lm the behavioral types for the body of m, and
Θ and L are the main future environment and the main behavioral type, respec-
tively. A future environment Θ maps future names to future behaviors (without
synchronization information) λX.m(α, x, X). In the method behavior, the formal
parameter α corresponds to the identity of the object on which the method is
called (the this), while X , called handle, is a place-holder for the actor that will
synchronize with the method. In practice several actors can synchronise with the
same future, but only one at a time. x̄ are the type of the method parameters.
The binder (νϕ) binds the occurrences of ϕ in Θm and Lm , with ϕ ranging over
future or actor names.
    The basic types r are used for values: they may be either @, to model inte-
gers, or any actor name α. The extended type x is the type of variables, and
it may be a value type r or a not-yet-synchronized type rf (in order to retrieve
the value r it is necessary to synchronize the future f ). The behavioral type 0
enforces no dependency, (κ, α) enforces the dependency between κ and α meaning
that, if κ is instantiated by an actor β , β will need α to be available in order
to proceed its execution. fκ may represent different behaviors depending on the
value of κ: f? represents an unsynchronized future f , which is a pointer in the
future environment to the corresponding method invocation; fα represents the
synchronization of the actor α with the future f ; fX represents the return of
a future f by the method associated to the handler X . The type L N L0 is the
parallel composition of L and L0 , it is the behavior of two methods running in
parallel and not necessarily synchronized. The sum L + L0 it is the composition
of two behaviors that cannot occur at the same time, either because one occurs
before the other or because they are exclusive.
    In general, a statement has a behavior which is a sum of behaviors. Each
term of the sum is a parallel composition of synchronization dependencies and
unsynchronized behaviors. We propagate this way the set of methods running in
parallel as a set of not-yet-synchronized futures all along the type analysis. The
statements that create no synchronization at all (i.e. that do not access a future,
nor call a method, nor return from a method) have behavior 0.
Example. The behavioral type associated to the following program is (fact_d(α, @f , X)
= (ν f 0 )(Θfd  Lfd ), Θ  L).
01 Int fact_d(Int n){                        Θfd = {f 0 7→ λX. fact_d(α, @, X)}
02    Int y;                                 Lfd = (fα + f?0 + fα
                                                                0
                                                                  ) N (X, α)
03    if (n == 0) return 1;
04    else { n = n-1; y = this.fact_d(n);    Θ   = {f 00 7→ λX.fact_d(α, @, X)}
05           y = y*(n+1) ; return y; }}      L   = f?00 + fmain
                                                           00


The synchronization fα0 , contained in the behavior Lfd , causes a deadlock. The
corresponding method invocation (λX. fact_d(α, @, X)) is performed on the
actor α, which amounts to instantiate the pair (X, α) into (α, α).
                          Deadlock analysis with behavioral types for actors.     261

3    Future work.

Relaxing constraints. In order to simplify our arguments, we focussed on a
sublanguage where futures are either returned or synchronized within a method
body. This implies that a synchronization on a method will cause the simulta-
neous synchronization on every new future it may have directly or indirectly
triggered. More specifically, after the synchronization we are guaranteed that
every other method invocation triggered by it has terminated. We intend to relax
this restriction by admitting method behaviours that trigger unsynchronized
tasks. We already investigated this extension in [8] and the application to gASP
of the solutions therein seems possible. A similar remark concerns the restriction
that fields of actors must be ground integers. We can relax it by using records,
as we did in [8]. In this case, the problematic issue will be to admit fields that
store futures while keeping the precision of the analysis acceptable.
Actor model extension. A possible evolution of our work could be continue
the study of deadlock analysis on some actor model extension. Generally an
actor runs a single applicative thread, but in [10] a version of the model in which
each actor is able to run more than one thread in parallel is presented. This
extension both enhances efficiency on multicore machines, and prevents most of
the deadlocks of the actors. It is trivial to see that if there are no constraints
related to the number of methods that can run in parallel on the same actor,
the model results to be deadlock free. However, it could be interesting to study
this extension of the actor model enriched by a concept that can be defined as
compatibility between methods. This compatibility can be a property defined by
the programmer that through some kind of annotation can specify if it is safe
to run in parallel some methods. In this context safe can mean that there are
no data races condition if the compatible methods are executed in parallel on
the same actor. We think that our technique can be applied on this scenario
extending the type system in order to express the compatibility concept.


References
 1. G. Agha. The structure and semantics of actor languages. In REX Workshop,
    pages 1–59, 1990.
 2. G. Agha, I. Mason, S. Smith, and C. Talcott. A foundation for actor computation.
    Journal of Functional Programming, 7:1–72, 1997.
 3. J. Armstrong. Erlang. Communications of ACM, 53(9):68–75, 2010.
 4. D. Caromel, L. Henrio, and B. P. Serpette. Asynchronous sequential processes. Inf.
    Comput., 207(4):459–495, 2009.
 5. E. Giachino, C. A. Grazia, C. Laneve, M. Lienhardt, and P. Y. H. Wong. Deadlock
    analysis of concurrent objects: Theory and practice. In Proceedings of IFM 2013,
    volume 7940 of LNCS, pages 394–411. Springer, 2013.
 6. E. Giachino, L. Henrio, C. Laneve, and V. Mastandrea. Actors may synchronize,
    safely! In PPDP, Sep 2016, Edinburgh, United Kingdom. (to appear), 2016.
 7. E. Giachino, N. Kobayashi, and C. Laneve. Deadlock analysis of unbounded process
    networks. In Proceedings of CONCUR 2014, volume 8704, pages 63–77.
262     Vincenzo Mastandrea

 8. E. Giachino, C. Laneve, and M. Lienhardt. A framework for deadlock detection in
    core ABS. Software and Systems Modeling, 2015.
 9. P. Haller and M. Odersky. Scala actors: Unifying thread-based and event-based
    programming. Theoretical Computer Science, 410(2-3):202–220, 2009.
10. L. Henrio, F. Huet, and Z. István. Multi-threaded active objects. In C. Julien and
    R. De Nicola, editors, COORDINATION’13, LNCS. Springer, June 2013.