Preventing Recursion Deadlo ck in

Concurrent Ob jectOriented Systems

by

Eric A Brewer Carl A Waldspurger

Technical Rep ort MITLCSTR

January

Abstract

This pap er presents solutions to the problem of deadlo ck due to recursion in concurrent ob ject

oriented programming languages Two languageindep endent systemlevel mechanisms for

solving this problem are prop osed a novel technique using multiported objects and a named

threads scheme that b orrows from previous work in We compare the

solutions and present an analysis of their relative merits

Keywords deadlo ck recursion ob jectoriented systems programming languages concurrency

c

Massachusetts Institute of Technology

This work was supp orted in part by the National Science Foundation under grant CCR

by the Defense Advanced Research Pro jects Agency DARPA under Contract NJ

and by an equipment grant from Digital Equipment Corp oration Eric A Brewer was

supp orted by an Oce of Naval Research Fellowship

Massachusetts Institute of Technology

Lab oratory for Computer Science Cambridge Massachusetts

INTRODUCTION

Introduction

Recursion is a p owerful programming technique that allows straightforward expression of many

Unfortunately recursion often leads to deadlo ck in contemporary concurrent ob ject

oriented systems In many systems Ame Yon Man Chi a metho d that mo dies

an ob jects state cannot even call itself recursively This o ccurs b ecause the ob ject as sender

is blo cked waiting for its call to complete but the called metho d never executes b ecause the

ob ject as receiver is blo cked In general recursion deadlock o ccurs whenever an ob ject is

blo cked p ending a result whose computation requires the invocation of additional metho ds on

that same ob ject

We present two transparent solutions that allow general recursion without deadlo ck These

solutions are transparent in that programs suering from recursion deadlo ck will run correctly

without change if either solution is incorp orated into the underlying system The rst solution

is based on multiported objects and uses separate communication p orts to identify recursive

calls The second solution named threads draws on previous work in distributed computing

and generates a unique name for each in order to detect recursive calls

A combination of three factors leads to recursion deadlo ck First an ob ject must hold a lo ck

on some state In systems with at most one active thread p er ob ject Ame Yon Man

Chi there is a single implicit lo ck for the entire ob ject state Second the ob ject must make

a blo cking call to some ob ject p ossibly itself holding the lo ck while it waits for the resp onse

to the call Finally the resulting call graph must contain a call back to the lo cked ob ject that

requires access to the lo cked state forming a cycle When these criteria are met every ob ject

involved in the cycle is waiting for a reply but none of the ob jects can make any progress The

ob jects on the cycle are deadlo cked

Aside from simple recursive metho ds many patterns of messagepassing can lead to recur

sion deadlo ck A common practice in programming sequential ob jectoriented systems is to

use a metho d as a mo dular subroutine from within another metho d dened on the same

ob ject An attempt to do this in a concurrent system however will result in deadlo ck More

sophisticated programs that manipulate cyclic data structures use callbacks while resp onding

to unusual or exceptional conditions or implement dynamic sharing mechanisms are all candi

dates for recursion deadlo ck Some programming styles are also prone to recursion deadlo ck

For example using inheritance by delegation Lie Lie an ob ject can delegate the handling

of a metho d to another ob ject dynamically In a delegated call references to self should b e

1

resolved to the original ob ject that p erformed the delegation Thus all calls to self involve

1

The term self may b e somewhat misleading in this context Whenever a message is delegated it must

callbacks that could lead to recursion deadlo ck

In the next section we examine existing work related to the recursion deadlo ck problem Our

basic mo del of concurrent ob jectoriented systems is dened in section Section discusses

the semantics of recursion without deadlo ck In section we outline our general solution

framework and we present the solutions in sections and An illustrative example app ears

in section Finally we compare the solutions in section and then present our conclusions

Related Work

A variety of partial solutions exist for handling some cases of recursion deadlo ck The simplest

partial solutions handle only direct recursion involving a single ob ject These amount to re

leasing the ob ject lo ck and ensuring that the next metho d invoked is the recursive call eg

by prep ending it to the incoming message queue which will reacquire the lo ck This approach

is implicit in languages such as Vulcan Kah which ensure that calls to self are pro cessed

b efore other incoming messages

Another solution for direct recursion is to provide procedures in addition to metho ds Yon

Unlike metho ds pro cedures are stateless and need not b e asso ciated with an ob ject Since

pro cedures are stateless they do not require lo cks Using this approach a metho d calls a

pro cedure and the pro cedure handles the recursion This avoids deadlo ck b ecause there is no

lo ck acquisition assuming the pro cedures never invoke any metho ds Recursion deadlo ck is

p ossible if the pro cedures invoke metho ds or otherwise acquire lo cks Since pro cedures only

have access to the current ob jects state multipleob ject recursion is not p ossible

A partial solution for xeddepth recursion is the use of selective message acceptance con

structs Yon Ame For example ABCL allows calls to b e accepted in the b o dy of a

metho d if the ob ject enters a selective waiting mo de In this case the recursive call is handled

in the b o dy and need not acquire the ob ject lo ck An explicit waiting mo de must b e introduced

for each level of recursion if there are to o many recursive calls the system will deadlo ck

If recursive calling patterns are completely known in advance deadlo ck can b e avoided

in actor systems by using replacement actors By cleverly sp ecifying insensitive actors that

buer most incoming messages while resp onding to a few sp ecial messages such as become

programmers can write co de that explicitly avoids p otential deadlo cks Agh Insensitive

actors are automatically generated by compilers for actor languages to supp ort the acceptance of

include a reference to the client ob ject that originall y received the message The term client is used b ecause

the ob ject that is the target of the delegation can b e thought of as p erforming a service for the original ob ject Lie

COMPUTATIONAL MODEL

2

replies to messages sent by a lo cked actor Although actor replacement provides the exibili ty

required to write deadlo ckfree co de the complexity of explicitly introducing insensitive actors

and b ehaviors for all p ossible recursive calling patterns is daunting In fact these lowlevel

actor mechanisms could b e used to implement the solutions we prop ose without systemlevel

changes In general systems that provide linguistic control of message acceptance such as

enabledsets Tom or protocols Bos can b e used to implement our languageindep endent

solutions

Techniques for deadlock detection from the distributed systems and database literature

Gli Sin could also b e used to address the recursion deadlo ck problem Deadlo ck de

tection algorithms examine pro cess and resource interactions to nd cycles assumed to b e

relatively infrequent and usually op erate autonomously separate from normal system activi

ties Although such schemes theoretically could b e used to detect and recover from deadlo cks

in a concurrent ob jectoriented system they would not b e practical for negrained programs

that use recursion Nevertheless the general idea of maintaining a list of blo cked de

p endencies is related to the deadlo ckprevention techniques that we prop ose

Finally recursion deadlo ck is closely related to the nestedmonitor problem Lis In the

nestedmonitor problem monitors corresp ond to ob jects with a single lo ck Nestedmonitor

calls corresp ond to blo cking calls made while an ob ject holds its lo ck Thus deadlo ck o ccurs if

3

there is a cycle in the call chain Most work on the nestedmonitor problem o ccurred b efore

the advent of concurrent ob jectoriented languages Solutions presented during that p erio d

amounted to either releasing the lo ck across the call or forbidding calls entirely Had

Computational Mo del

We make a few basic assumptions ab out the underlying computational mo del The mo del we

assume encompasses most contemporary concurrent ob jectoriented systems Objects abstractly

encapsulate lo cal state with a set of methods that can manipulate that state directly Ob jects

interact only by sending messages to invoke metho ds at other ob jects To avoid ambiguity we

dene the following terms

Message A message is a request from a sender ob ject to a receiver ob ject to p erform an

op eration A message causes the invocation of a particular metho d at the receiver the

2

In actor parlance an actor that has not yet computed its replacement b ehavior

3

The nestedmonitor problem is not restricted to cyclic calls At the time other forms of deadlo ck were the primary concern

arguments for that metho d are passed in the message Messages may or may not arrive

in the order they were sent but message delivery is guaranteed

Message Queue Each ob ject has a message queue that buers all incoming messages

An ob ject removes messages from its queue and invokes the corresp onding metho ds We

ignore issues of message priority and queue overow

Send We divide messages into two categories sends and calls A send is an asynchronous

nonblo cking metho d invocation It is unidirectional and has no corresp onding reply

After p erforming a send the sender immediately continues execution and do es not wait

for a reply or for the completion of the invoked metho d

Call A call is a synchronous blo cking metho d invocation After p erforming a call the

sender waits for a reply This is analogous to normal pro cedure call semantics Any lo cks

held by the sender prior to the call are held until the reply is received Every call has

a matching reply we assume the underlying system handles the matching of callreply

4

pairs

A set of concurrent calls may also b e sent such that each of the calls op erates in parallel

and the sender waits for replies from all of the calls b efore continuing execution This

corresp onds to a forkjoin semantics

Lo ck A lo ck ensures for some piece of state A given ob ject may

contain several lo cks We assume that lo cks are the underlying primitive synchronization

mechanism for mutual exclusion Lo ck acquisition may b e implicit or explicit In actor

languages for example a single ob ject lo ck is acquired implicitly up on metho d invocation

and is released explicitly via the ready construct which indicates that the metho d has

5

nished mo difying the actors state

To avoid complication we will assume that there is a single implicit lo ck p er ob ject that

provides mutual exclusion for the entire ob ject state as in most contemporary languages

Ame Yon Man Chi However the solutions we present can b e easily adapted

for languages with more sophisticated lo cking schemes we briey discuss this after pre

senting the solutions for the singlelo ck case

Thread A thread is a single ow of control that p erforms a sequential computation

A single thread may execute co de at several dierent ob jects For example if ob ject

4

We do not preclude explicit handling of reply values which can b e useful for forwarding or delegation

5

In actor terms there is no mutation the actor computes a new replacement actor to pro cess subsequent messages

RECURSIVE CALL SEMANTICS

A calls ob ject B the sequential ow of control would initially execute some co de at A

then pro ceed to execute the invoked metho d at B and nally continue execution back

at A In a sense the thread travels with the messages b etween A and B This view

of threads may dier from the lowlevel details of the underlying implementation which

might involve two distinct threads at A and B Semantically however there is only

one thread b ecause the computation is sequential

A thread can also fork several distinct subthreads by p erforming concurrent calls In this

case the original thread is susp ended until its subthreads or children all reply and join

6

with the original parent thread

Recursive Call Semantics

Existing Sequential Semantics

In sequential ob jectoriented systems such as Smalltalk Gol and C Str there is

only a single thread of control so mutualexclusion lo cks are unnecessary In these systems if

the call chain generated during a metho d invocation results in a later invocation on the same

ob ject the recursive call is p ermitted to mo dify the ob jects state Thus a recursive call may

b e used to change the state of an ob ject in sequential ob jectoriented systems and there is no

deadlo ck issue

Prop osed Concurrent Semantics

In concurrent systems a complete lack of mutual exclusion is not satisfactory b ecause of the

need to avoid interference b etween concurrently executing threads For example consider a

bank account ob ject A with a current balance of that is accessed concurrently by two

dierent threads t and t Without provisions for serialization t and t could concurrently

1 2 1 2

invoke withdraw metho ds on A If b oth threads happ ened to read the current balance

b efore either mo died it to reect a withdrawal the account would have a balance of

instead of b eing overdrawn In order to serialize the withdraw metho ds a mutualexclusion

lo ck could b e asso ciated with the account balance to ensure that each metho d app ears to

execute atomically However the addition of this lo ck makes recursion deadlo ck p ossible

Ideally we would like to preserve atomicity while eliminating the p otential for recursion

deadlo ck Our prop osed semantics for concurrent systems is consistent with the exp ected

6 Joins are relevant only for blo cking calls

Recursion and Message Order

b ehavior in sequential systems we allow recursive calls to execute without reacquiring lo cks

However the resulting b ehavior is undened if a thread forks subthreads When a thread

forks several children which thread gets the lo ck If all subthreads have access to the ob ject

state they may interfere with one another exactly the b ehavior lo cks are supp osed to prevent

The desired b ehavior is that any of the descendant threads may access the state but only one

may have access at any given time Thus our prop osed semantics is to satisfy two prop erties

rst descendants must b e able to acquire lo cks held by their ancestors and second mutual

exclusion must b e provided among siblings One way to view this is that a descendant thread

must acquire a lo ck from its ancestor providing mutual exclusion from its siblings The lo ck

is returned to the ancestor when the descendant releases it Once returned another descendant

may acquire the lo ck

The semantics discussed so far provide mutual exclusion at the granularity of a single

metho d Atomicity at b oth smaller and larger grain sizes may b e desirable Finer granularity

exclusion can b e provided by explicitly acquiring and releasing lo cks within a metho d Larger

granularity exclusion requires that threads hold lo cks across multiple metho d invocations Al

though our work do es not address these granularities explicitly they can b e handled by the

solutions we present with simple mo dications Furthermore most concurrent ob jectoriented

7

languages provide little or no supp ort for ne or coarsegrain lo cking These languages com

monly acquire lo cks up on metho d invocation and release them at or near completion of the

metho d This implicitly limits the granularity of mutual exclusion to the metho d level

The recursion allowed by the solutions presented in this pap er is generated by calls not by

sends This implies that a metho d that p erforms a send and requires a result generated by that

send before it completes will suer from deadlo ck up on recursion For example a metho d that

p erforms a request using send and then waits for information from a second send will deadlo ck

if recursion is required to generate the second send The obvious solution is to use call instead

so that the reply either is the result or guarantees that the required action has taken place

Thus we view send as a mechanism for causing remote actions that need not complete b efore

the current metho d This matches the use of call and send in current ob jectoriented systems

Recursion and Message Order

The eect of the prop osed mechanisms on message order dep ends on the p olicy of the un

derlying language In some languages such as Acore Man message ordering is completely

nondeterministic Others such as ABCL Yon make the transmissionorder preserva

7 Exceptions include Argus Lis and Concurrent Smalltalk Dal

MULTIPORTED OBJECT SOLUTION

tion assumption TOPA TOPA guarantees p ointtopoint ordering for any pair of messages

sent from an ob ject X to another ob ject Y the order of reception is identical to the order of

transmission

If message ordering is nondeterministic there are no ordering constraints that our mecha

nisms could violate If TOPA is guaranteed by the underlying message delivery system then

our mechanisms preserve TOPA

However recursion introduce a new notion of order Recursion implies that recursive sub

tasks are logically part of the current task In other words all nested subtasks must complete

b efore the current task can complete Thus recursive subtasks spawned by recursive messages

must b e executed while the main task is waiting for the reply that the subtasks are supp osed

to generate The logical order of execution is the order of reception except that only recursive

subtasks execute while the main task blo cks on a call Recursive messages are handled in the

order received relative to other recursive messages but b efore all nonrecursive messages

General Solution Framework

We describ e two dierent transparent systemlevel mechanisms that allow programmers to

express computations using recursive metho ds No syntactic changes or programmervisible

linguistic mechanisms are necessary

The solutions presented in this pap er have two key asp ects in common First each message

is tagged with identifying information by its sender Second each ob ject lters incoming mes

sages dynamically deciding whether to accept or buer each message based on the identifying

information that it contains A subset of messages in the message queue are currently accept

able A predicate called the accept predicate is used to test for membership in this set When

an ob ject is ready to pro cess a new message it accepts the rst message in its message queue

that satises the accept predicate

MultiPorted Ob ject Solution

In this section we present a novel solution to the recursion deadlo ck problem using multiple

communication channels or ports p er ob ject Conventional ob jectoriented systems assume

ob jects have a single p ort through which all incoming messages arrive The traditional notion

of an ob ject can b e relaxed to allow several p orts The use of multiple p orts to enable dierent

client capabilities multiple viewp oints and secure communications is explored in Kah We

demonstrate that the recursion deadlo ck problem can b e solved by providing ob jects with the

Message Acceptance

ability to create and select p orts dynamically

The recursion problem is solved by creating a new current port for each metho d invocation

This p ort receives all replies and recursive calls and p ersists until the metho d terminates An

ob ject accepts incoming messages from its current p ort and buers messages addressed to other

X

p orts The current p ort for an idle ob ject X is the distinguished toplevel p ort P

0

Message Acceptance

Messages that arrive at an ob ject X while it is executing some metho d H are buered in the

message queue asso ciated with X for later pro cessing If H is blo cked p ending the arrival

of messages that are required for further computation or if H completes X enters message

reception mo de At this p oint X may b egin pro cessing messages that satisfy the accept predicate

Multip orted ob jects use the following accept predicate a message is accepted if and only if it

is addressed to the current p ort

Message Handling

Normal ob ject semantics guarantee that for each ob ject only one metho d activation exists at

a time ob jects pro cess messages serially b etween state transitions To p ermit recursive calls

we weaken this constraint to require that each ob ject maintain a method activation stack of

p ending metho d activation frames and guarantee that only the activation at the top of this

stack may b e actively executing This corresp onds to the stack of pro cedure call frames found

in conventional sequential languages

The top frame on the metho d activation stack contains the state of the currently executing

computation Frames other than the top frame contain the state of susp ended metho d invo

cations that are blo cked p ending the arrival of reply messages New frames are pushed on the

8

metho d activation stack when handling messages other than replies

When message M is accepted by ob ject X the following actions are p erformed

If M is a reply match the reply value to its corresp onding call If there are no remaining

outstanding concurrent calls resume the asso ciated blo cked thread

Otherwise the following actions are p erformed

a A new frame is allo cated on top of the metho d activation stack

8

If the current p ort is the distinguish ed toplevel p ort these messages can b e toplevel calls or sends Other wise these messages will b e recursive calls

MULTIPORTED OBJECT SOLUTION

b A new lo cally unique p ort number P is generated p erhaps by simply incrementing

a counter and asso ciated with the frame This p ort b ecomes the new current p ort

the set of currently acceptable messages are those addressed to P

c The appropriate metho d named by M is invoked

When a metho d completes its frame is p opp ed o the metho d activation stack The current

p ort is then set to the p ort asso ciated with the susp ended metho d currently on top of the

activation stack

Sending Messages

In the following discussion assume that an ob ject X during the invocation of its metho d H

in resp onse to a message M is sending a message M to ob ject Y The current p ort for X

Y

X

during its handling of H is denoted by P

h

M is augmented with a port binding map B that asso ciates ob ject names with com

Y M

Y

munication p orts In general the size of a p ort binding map B is prop ortional to the number

M

of distinct ob jects involved in the pro cessing of message M The pro cedure for sending M is

Y

If M is a send

Y

a Set B to nil

M

Y

Y

b Send M to Y at p ort P

Y

0

If M is a call compute the destination p ort and the p ort binding map to b e sent with

Y

M

a The destination p ort p is computed by searching for the p ort asso ciated with Y in

Y

the p ort binding map B from message M If Y B then set p to P

M M

0

9 X

b Set B to b e the same as B extended or changed to map X P

M M

h Y

c Send M to Y at p ort p saving the appropriate information to match up the reply

Y

from Y

d If M is one of several concurrent calls p erform the remaining calls After p erform

Y

ing the last call susp end the current thread p ending replies

9 This extension or change is done at most once p er metho d invocation not once p er call

Extension for Multiple Lo cks

Extension for Multiple Lo cks

Some languages such as Concurrent Smalltalk Dal supp ort the addition of explicit lo cks

for ob ject metho ds as a general mechanism for The multiported ob ject

solution for recursion deadlo ck can b e adapted to work with such languages

Basically the notion of a current port is extended to a current p ort set each lo ck has an

asso ciated current p ort Port binding maps asso ciate ob ject names with communication p ort

sets The accept predicate is mo died to accept a message if and only if it is addressed to the

current set of p orts When an incoming message is accepted a new metho d activation frame is

allo cated and an asso ciated unique p ort number is generated for every lo ck that the metho d

acquires When a call message is sent the current p ort binding map is extended or changed

to map self to the current p ort set

Summary

In summary an ob ject creates a p ort for each metho d invocation This p ort is used exclusively

for replies and recursive calls The p ort name is propagated in the p ort binding maps of call

messages to ob jects that p erform computations as subtasks on b ehalf of the current metho d

Each call is addressed to a sp ecic destination p ort and is accepted by an ob ject only if its p ort

matches the p ort asso ciated with the current metho d Section presents an example using the

multiported ob ject approach to avoid recursion deadlo ck

NamedThreads Solution

The essential elements of named threads are based on action ids from Argus Lis Lis a

language for robust distributed computing The namedthreads approach to avoiding recursion

deadlo ck assigns each thread a unique identier that travels with it through every ob ject and

message Every ob ject has a current owner which is its currently executing thread and every

message has a name which is that of the thread that carries it In a recursive call the name

of the message matches the name of the owner This avoids the deadlo ck that results from

attempting to reacquire access to the state

The simplest cases o ccur in systems without concurrent calls In such situations a thread

is given a unique name that it keeps for the duration of its existence Up on acquiring access

to the ob jects state the thread marks itself as the owner of the ob ject using its name or

thread id Up on recursion the thread id of the message is checked against the thread id of the

owner If the ids match the incoming message has access to the state Because the new task

NAMEDTHREADS SOLUTION

can determine that it already has access it do es not wait for the current task to nish thus

avoiding deadlo ck

The essential elements of named threads originated in Argus Lis a language for robust

distributed computing Argus uses transactions to provide fault tolerance a transaction either

completes correctly or if ab orted has no eect on the state of the system A transaction often

involves several ob jects p ossibly on dierent machines and several threads within an ob ject

The techniques used to provide fault tolerance over many machines are quite complex and are

not all relevant to recursion deadlo ck Hidden in those techniques are the use of action ids

up on which thread ids are based Lis

Concurrent Calls

Most concurrent ob jectoriented languages allow a single thread to create multiple threads

This wreaks havoc with the simple threadid solution presented ab ove As discussed in Section

two requirements must b e met for the desired semantics descendants must b e able to acquire

lo cks held by their ancestors and mutual exclusion must b e provided among siblings These

requirements lead to the following convention for naming threads

Up on creation a thread is given a unique identier This could b e done by using a com

bination of the id of the creating ob ject and some timedep endent integer such as a simple

counter As exp ected the diculties arise with concurrent calls A set of concurrent blo cking

calls will b e referred to as a call group When a thread forks subthreads we extend its thread

id for every member of its call group The extension is dierent for every resulting thread For

example if thread t p erforms three concurrent calls the three new threads are t t and

t If t then spawns a twomember call group there are six threads in total t t t

t t and t Note that each thread has a unique thread id and that a thread id enco des

all of the threads ancestors A thread is an ancestor of another thread exactly when its id is a

prex of the others id

The use of named threads requires some extensions to the basic ob ject mo del First the

ob ject lo ck must have an owner This eld holds the name of the currently executing thread and

is referred to as owner Second there must b e a stack of p ending call messages as explained

b elow referred to as ownerStack Finally each message must have a eld that contains its thread id

Message Acceptance

Message Acceptance

The namedthreads approach employs the following accept predicate a message is accepted if

and only if it is a descendant of owner That is owner must b e a prex of the thread id asso ciated

with the message to b e accepted The accept predicate changes every time owner changes The

owner eld initially contains nil which yields a predicate that accepts all messages Accepted

messages are handled as follows

If the message is a reply then it is a resp onse to a call spawned by the current owner

If it did not match the current owner it would not have b een accepted The blo cked

thread is resumed

Otherwise the message is a recursive call In this case the current owner is pushed onto

the stack ownerStack The thread named by the id of the message b ecomes the new

owner and the metho d for the message executes

Cho osing the Next Thread

Once a thread is started no new messages are accepted until the thread either ends or p erforms

a call When the thread ends the next thread is chosen as follows

The previous owner is p opp ed o of ownerStack This changes the accept predicate

which could make previously unacceptable messages acceptable

The next message is chosen based on the new predicate There must eventually b e a

message namely the matching reply to the p ending call

Sending Messages

If a thread p erforms a call the ob ject starts accepting messages Because the thread owns the

lo ck only descendant messages or the reply will b e accepted A send do es not pass on the

thread id leaving the id eld of the message empty Thus metho ds executed in resp onse to

sends start new threads

When concurrent calls are made the thread id of each member of the call group is extended

by a unique number All of the members are descendants of the original thread but no member

is an ancestor of another member This guarantees that at most one member of the call group

can have access to an ob ject at any given time The spawning thread retains ownership of

the lo ck until one of the concurrent calls recurses or until all the replies are received and the metho d completes

AN ILLUSTRATIVE EXAMPLE

Extension for Multiple Lo cks

As in the multiported ob ject solution the namedthread solution can b e mo died to handle

multiple lo cks p er ob ject Each ob ject has a set of lo cks and a metho d requires a particular

subset in order to execute Each lo ck has an owner eld and a stack of owners As in the

singlelo ck case the owner eld contains the name of the thread that holds the lo ck A message

is accepted if it can obtain all of the lo cks needed by the corresp onding metho d Every lo ck

the metho d needs must b e either free or owned by an ancestor If the required subset can b e

obtained the current thread b ecomes the new owner of every lo ck in the subset The previous

owners are pushed onto the corresp onding stacks Up on release of a lo ck the previous owner

is restored

Summary

In summary recursion is detected by enco ding ancestry in thread ids Recursive calls are de

scendants of the blo cked call and are allowed to execute Names are extended when concurrent

calls are made providing mutual exclusion among the resulting threads An example is given

in the next section

An Illustrative Example

Consider a doquery metho d dened for a node ob ject that is connected to other no des in a

graph When invoked on a no de N this metho d queries each of N s children concurrently and

then returns a function of their replies The children compute their replies in the same way As

is common in sequential implementations a no de ob ject marks itself visited the rst time it is

queried and the doquery metho d returns immediately if an ob ject has already b een visited

To illustrate our solutions we examine this abstract concurrent query on part of

a larger graph Note that the call tree is isomorphic to the graph calls are made along the

directed edges

Figure a presents a graph that do es not involve recursion Figure b depicts a query

p erformed in this graph Ob ject X queries ob ject W which concurrently queries ob jects Y

and Z All of the queries complete and X returns the result Figure c presents a graph that

involves recursion the corresp onding query in gure d suers from recursion deadlo ck Since

X is blo cked waiting for the query to W to complete the query from W to X never executes

The metho d at W will not complete until X replies and X will not reply until the metho d at

W completes The following two subsections illustrate how the solutions eliminate recursion

(a) (b)

X X

Y Y

W W

Z Z

(c) (d) (e)

X X X

LOCKED ! Y Y Y

W W W

Z Z Z

Figure Graph fragments and calling patterns in the abstract query example In the calling

pattern diagrams call and reply messages are represented by solid and hollow arrowheads

resp ectively a A nonrecursive graph fragment b Call pattern in the nonrecursive graph

fragment X calls W which concurrently calls Y and Z c A recursive graph fragment

d Call pattern in the recursive graph fragment X calls W which concurrently calls X and

Y resulting in deadlo ck e A deadlo ckfree call chain which uses the solution techniques presented in the pap er

AN ILLUSTRATIVE EXAMPLE

deadlo ck in this example

A MultiPorted Ob ject Solution

The following steps depicted in Figure e trace the messagepassing activity for the example

W

presented ab ove Assume that ob jects W Y and Z are initially idle with current p orts P

0

Y Z

P and P resp ectively Assume that X calls W while its current frame is X with asso ciated

5

0 0

X

p ort P

5

W 10 X

X calls doquery at W on p ort P using the p ort binding map B fX P g

0 5

W

W receives X s call W starts a new frame W with asso ciated p ort P W concurrently

1

1

X W

calls X and Y using B fX P W P g The call to X is sent to X s p ort

5 1

X Y

P and the call to Y is sent to Y s p ort P

5 0

Concurrently

Y

a Y receives W s call Y starts a new frame Y with asso ciated p ort P Y replies to

1

1

W and ends frame Y

1

b X receives W s call Note that this is a recursive call involving the path of ob jects

X

X W X X accepts the message since it is addressed to X s current p ort P

5

X

X replies to W and then ends X starts a new frame X with asso ciated p ort P

6

6

frame X restoring X as the current frame

6 5

W receives the replies from X and Y

W computes the return value as a function of the information returned from X and Y

and sends a reply containing this value to X W then ends frame W restoring W as

1 0

the current frame

A NamedThreads Solution

This example can b e used to illustrate the namedthreads technique as well Ob jects will b e

annotated with their current owner X t implies that ob ject X is owned by thread t

X x calls W invoking metho d doquery This leads to W x

10

The p ort binding map B would contain additional entries if the current call is part of a larger call chain For clarity only those entries relevant to the calls in the depicted graph fragment are listed

W x concurrently calls X x and Y The message to X x has an id of x and the

message to Y has an id of x

Concurrently

a Y receives the call from W x Note that W is owned by x but the calling thread

is x This implies Y x The result is calculated and returned to W x After the

reply Y is again unowned that is Y

b X x receives the call with message id x from W x This is a recursive call

Since x the current owner of X is an ancestor of the calling thread x the call is

accepted The current owner x is pushed on to ownerStack and x b ecomes the

new owner X x replies to W x and the previous owner is p opp ed o the stack

This implies X x

W x receives the replies from X and Y

W computes the return value of doquery based on the replies The result is returned to

X x and W is again unowned The ownership is then X x Y and W

Analysis and Comparison

The multiported ob ject and namedthread solutions aect the underlying system in three ma jor

areas maintenance of a call stack overhead for message sending and message acceptance and

an increase in message length The impact is negligible when using only sends but may b e

signicant in the presence of blo cking calls

A send message incurs negligible overhead b ecause there is no call stack little extra work

for handling messages and no increase in message length For the case of blo cking calls each

ob ject maintains a stack of p ending calls In the multiport solution this is the stack of frames

while in the namedthreads solution it is the stack of owners For general recursion the size of

the p ending call stack is unbounded The height of the stack at X dep ends on the number of

recursive calls in the call chain that is the number of calls to X For singleob ject recursion this

is the depth of the call chain while for multipleob ject recursion the height will b e smaller than

the length of the call chain The stack is not a side eect of these solutions it is fundamental to

recursion Just as a stack supp orts recursive pro cedures in conventional sequential languages

the stacks used here supp ort recursive call messages

ANALYSIS AND COMPARISON

Comparative Overhead

For the general case is it useful to dene two metrics for call chains object depth and split

depth The ob ject depth is the number of distinct ob jects in a call chain Thus if X calls Y

calls Z the ob ject depth is three while if X calls Y calls X the ob ject depth is two The

split depth measures the number of splits in a call chain An unsplit thread is dened to have

a split depth of one Thus if X calls Y the split depth at Y is one while if X concurrently

calls Y and Z the split depth at Y is two one for the original thread and one for the split at

X Using the namedthreads notation introduced in section the split depth is the number

of elds in the id x has a split depth of three

The solutions dier in the p erformance of choosing destinations for calls and accepting

messages For multiported ob jects choosing a destination for a call requires scanning the p ort

binding map to identify the exact destination The average time for this scan is prop ortional

to the length of the p ort binding map which is the same as the ob ject depth of the call

11

chain Thus the time for lo cating the destination is prop ortional to the ob ject depth For the

namedthreads solution the destination is known and the cost is constant

The cost of message acceptance has a dual b ehavior The multiport solution checks the

validity of the p ort with a single comparison The namedthreads solution must compare the

id of the message and the id of the owner In the worst case this comparison is prop ortional

to the length of the owner id Since the length of the owner grows with each split the cost of

the acceptance test is prop ortional to the split depth Note that if the ob ject is unowned the

message is a send or the id starts with a dierent ob ject then the test completes immediately

In summary the multiport solution requires time prop ortional to the ob ject depth for choosing

a destination but can accept messages in constant time On the other hand the named threads

solution requires time prop ortional to the split depth for accepting a message but can lo cate

message destinations in constant time

Message length is also aected dierently by the two solutions For multiported ob jects

the message is extended by the p ort binding map the length of the extension is prop ortional to

the ob ject depth For named threads the message is extended by the id of the calling thread

the length of the extension is prop ortional to the split depth

11

More complex data structures such as hash tables could reduce this lo okup to constant time asymptoti

cally However this would probably b e worse in practice due to b oth higher constant factors and larger space requirements

Example Calling Patterns

X 1 X X

X 2 X k X Y Z Y X 3

(a) (b) (c) (d)

Figure Calling patterns for comparing ob ject depth and split depth Arrows denote calls

and arcs joining arrows signify concurrent calls

Example Calling Patterns

Since the p erformance of the multiport solution dep ends on ob ject depth and that of the

namedthreads solution dep ends on split depth their relative merit dep ends on the call chains

encountered in a given system Several p ossible call chains are shown in Figure

The most common case of recursion is direct recursion represented by the call chain in

Figure a Only one ob ject and one thread are involved so b oth the ob ject depth and the

split depth are one Both solutions have low overhead for this case

A more general form of recursion is shown in Figure b The call chain is a cycle of k

ob jects For k this reduces to simple mutual recursion Since there are k ob jects involved

the ob ject depth is k regardless of how many times the call chain lo ops around the cycle Since

there are no concurrent calls the split depth is one Note that the overhead is the same if the

last call is not recursive the split depth is one and the ob ject depth is k The overhead for the

multiport solution is prop ortional to k while the overhead for the namedthreads solution is

constant The namedthreads approach is sup erior when there are many ob jects involved and

few concurrent calls

The multiport solution is sup erior in the opp osite case few ob jects and many concurrent

calls Figure c depicts a call chain with only two ob jects each of which makes a pair of

concurrent calls This kind of call tree might o ccur in a system that pro cesses data structures

with two dierent types of no des For example consider a computation applied to a binary

tree in which X handles all of the right no des and Y handles all of the left no des Because there are only two ob jects involved the ob ject depth is two regardless of the height of the call

CONCLUSIONS

tree Performance is much worse for the named threads solution After k pairs of concurrent

calls the split depth is k for threads that are the leaves of the call tree Thus the overhead

for the multiport technique is constant while the overhead for the namedthreads solution is

prop ortional to k

In summary the relative overhead of these solutions dep ends on the ratio of ob ject depth

to split depth Systems with recursion among small groups of ob jects and many concurrent

calls would p erform b etter using the multiported ob ject technique Systems with recursion

among many ob jects and few concurrent calls would p erform b etter using the namedthreads

technique In many applications call chains involve few ob jects and few concurrent calls in

which case b oth solutions p erform well

A Hybrid Mo del Dierentiating Recursive Calls

Since the additional overhead in the prop osed solutions stems from the requirements of recursive

calls it may b e useful to dierentiate calls that are allowed to recurse from those that are not

Note that if a call is not allowed to recurse the situation is identical to current ob ject systems

with one exception nonrecursive calls must propagate the recursion information if p erformed

in resp onse to a call that is allowed to recurse This mixed mo del yields b etter p erformance

when a programmer or compiler is certain that recursion cannot o ccur However deadlo ck

results if a nonrecursive call do es recurse

General Ob ject Deadlo ck

Although the techniques presented eliminate deadlo ck due to recursion the general deadlo ck

problem remains quite serious Figure d depicts a call chain that may lead to deadlo ck

Ob ject X concurrently calls ob jects Y and Z which in turn call each other Deadlo ck o ccurs if

Y is blo cked waiting on Z and Z is blo cked waiting on Y In this case deadlo ck can b e avoided

by serializing the calls at X Unfortunately avoiding deadlo ck in general is quite dicult

Thus although blo cking calls provide clean simple semantics it is generally safer to use sends

wherever p ossible But using sends without eliminating blo cking is no b etter than using calls

the fundamental problem is blo cking

Conclusions

Current ob ject systems place severe limits on the use of recursion reducing expressive p ower

The two techniques presented allow fully general recursion in a manner that is transparent to

the user The multiport solution uses p orts to distinguish recursive calls placing the burden

on the sender to identify the correct p ort The named threads solution names each path in

the call tree enco ding ancestors in the name The test for ancestry is used to detect recursive

calls placing the burden on the receiver to identify ancestors The relative overhead of these

solutions is dep endent on application call graphs in particular on the ratio of ob ject depth to

split depth Call graphs with many ob jects and relatively few concurrent calls p erform b etter

with the namedthreads solution while the multiport solution leads to b etter p erformance in

the opp osite case

Recursion is a p owerful and imp ortant programming technique that causes deadlo ck in

most concurrent ob jectoriented systems The solutions presented in this pap er provide simple

eective systemlevel supp ort for general recursion They can b e used by designers and imple

mentors of concurrent ob jectoriented systems to avoid severe restrictions on the expression of

recursion

Acknowledgements

We are grateful to Barbara Liskov William Weihl Adrian Colbro ok Chris Dellaro cas Sanjay

Ghemawat Bob Grub er Wilson Hsieh Ken Kahn and Paul Wang for their comments and

assistance

References

Agh Gul Agha Actors A Model of Concurrent Computation in Distributed Systems MIT

Press Cambridge MA

Ame Pierre America POOLT A Parallel ObjectOriented Language In Akinori

Yonezawa and Mario Tokoro eds ObjectOriented Concurrent Programming MIT

Press

Bos Jan van den Bos and Chris Lara PROCOL A Parallel Object Language with Pro

tocols Pro ceedings of the Fourth ACM Conference on Ob jectOriented Programming

Systems Languages and Applications OOPSLA Octob er

Chi Andrew A Chien Concurrent Aggregates CA An ObjectOriented Language for

FineGrained MessagePassing Machines PhD thesis Massachusetts Institute of

Technology July

Dal William J Dally A VLSI Architecture for Concurrent Data Structures Kluwer Aca

demic Publishers

REFERENCES

Gli Virgil D Gligor and Susan H Shattuck On Deadlock Detection in Distributed Systems

IEEE Transactions on Software Engineering September

Gol Adele Goldb erg and David Robson Smal ltalk The Language and its Implementa

tion AddisonWesley Reading MA

Had Bruce K Haddon Nested Monitor Cal ls Op erating Systems Review vol no

Octob er

Kah Kenneth Kahn Eric Dean Tribble Mark S Miller and Daniel G Bobrow Vulcan

Logical Concurrent Objects In Ehud Shapiro Concurrent Prolog Col lected Papers

MIT Press

Kah Kenneth Kahn Objects A Fresh Look Pro ceedings of the Third Europ ean Conference

on Ob jectOriented Programming ECOOP Cambridge University Press July

Lie Henry Lieb erman Using prototypical objects to implement shared behavior in object

oriented systems Pro ceedings of the First ACM Conference on Ob jectOriented Pro

gramming Systems Languages and Applications OOPSLA September

Lie Henry Lieb erman Concurrent ObjectOriented Programming in Act In Akinori

Yonezawa and Mario Tokoro eds ObjectOriented Concurrent Programming MIT

Press

Lis Barbara Liskov Implementation of Argus Pro ceedings of the th ACM Symp osium

on Op erating Systems Principles November

Lis Barbara Liskov Distributed Programming in Argus Communications of the ACM vol

no March

Lis Andrew Lister The problem of nested monitor calls Op erating Systems Review vol

no July

Man Carl R Manning Acore The Design of a Core Actor Language and its Compiler

Masters thesis Massachusetts Institute of Technology August

Sin Mukesh Singhal Deadlock Detection in Distributed Systems IEEE Computer Novem

b er

Str Bjarne Stroustrup The C Programming Language AddisonWesley Reading MA

Tom Chris Tomlinson and Vineet Singh Inheritance and Synchronization with Enabled

Sets Pro ceedings of the Fourth ACM Conference on Ob jectOriented Programming

Systems Languages and Applications OOPSLA Octob er

Yon Akinori Yonezawa Etsuya Shibayama Toshihiro Takada and Yasuaki Honda Mod

el ling and Programming in an ObjectOriented Concurrent Language ABCL In Aki

nori Yonezawa and Mario Tokoro eds ObjectOriented Concurrent Programming MIT Press