Common Lisp Actor System

Naveen Sundar G February 20, 2010

Contents

1 Introduction 2 1.1 Prerequisites ...... 2

2 Overview 2

3 Tutorial 3 3.1 Stateless Actors ...... 3 3.2 Actors with State ...... 3 3.3 ...... 4

4 Syntax 4

5 Dynamic Change of Behavior 5

6 Examples 6 6.1 Join ...... 6 6.2 Reference Cell ...... 7 6.3 ...... 8 6.4 Dining Philosophers ...... 9

7 More Resources 10

8 Future Work 10 1 Introduction

This document describes a simple to use Actor extension for Common Lisp. The Actor Model is a concurrent model of in which actors, which are inde- pendent computational processes, are the basic units of computation. Computation proceeds by message passing across actors. For more on the Actor model of compu- tation please see [A+86, Var10]. In the CLAS extension for Common Lisp each actor get its own thread of execution which can be reused. My implementation has been inspired by the SALSA Actor-based distributed :

http://wcl.cs.rpi.edu/salsa/

CLAS has been tested on examples found in [Var10]. The current state of the software is experimental, but I hope to improve it and add distrubtion and mobility. The code for these examples can be found in the source distribution. This manual contains a brief tutorial, an explanation of the syntax of CLAS , shows how to change the behavior of actors dynamically and explains the examples to some extent.

1.1 Prerequisites CLAS requires the Bordeaux-Threads package to work. The package along with in- structions for installation can be found at:

http://common-lisp.net/project/bordeaux-threads/.

2 Overview

Creating an actor class or template is similar to defining a function. • ( defactor Actor Class ( s t a− t ) ( message vars ) behavior−next)

Creating an actor instance is done using the following syntax. This can be • thought of as coarsely equivalent to the new operator in Java. ( setq my actor (Actor Class (:state var 1 va lue 1 . . . − : state− var n value− n ) ) ) −

2 Sending a message • ( send my actor message arg1 ... message argn ) −

3 Tutorial

3.1 Stateless Actors A simple printer actor class with no state can be created as : ( defactor printer () (val) (pr val) next) A new instance is initialized as : ( s e t f print actor (printer)) − An asynchronous message can be sent to this actor as : ( send print actor ”hello ,world”) ; ” hello , world− ”

3.2 Actors with State A simple reference cell actor class can be created as follows : ( defactor cell (c) ( message) ( cond ((get ? message ) ( send (cust message) c)) (( set? message ) ( s e t f c (contents message)))) next) c holds the state of the actor. A new instance with value -1 is initialized as : ( s e t f c e l l actor (cell :c 1)) − − An asynchronous message can be sent to this actor as : ( send c e l l a c t o r ( make get print actor ) ; 1 − − − − The value of the cell is sent to the print actor which then prints it. See section 6.2 for a full implementation.

3 3.3 Message passing The code below typed into the repl illustrates use of default state variables and the message sending syntax which is similar to function calls in Lisp. We create an actor class linear which takes the linear combination of its message components x , y with its state variables a and b , ax + by and sends it to cust actor. Note we do not set the state variable b, and therefore it assumes its default value 1. CL USER> ( defactor linear (a (b 1)) (x y cust) − ( send cust (+ ( a x ) ( b y ) ) ) ) ;LINEAR ∗ ∗ CL USER> ( s e t f lin actor (linear :a 2 )) ;(#− ;# NIL) CL USER> ( send lin actor 1 2 print −actor ) ; 4− − −

4 Syntax

The syntax of CLAS uses LISP s-expressions. The main macros, functions and key- words of CLAS are summarized in this section.

behav : • arguments : [state message &body body] Create a behavior that has state state, message format message and behavior specified by body

defactor : macro • arguments : [name state message &body body] Create an actor named name that has state state, message format message and behavior specified by body

send: function • arguments : [actor message] Send actor actor message message.

self: constant keyword • Refers to own actor.

next: constant keyword • Used to change behavior dynamically. Set by default to current behavior.

4 me: constant keyword • Refers to own behavior. This is meant to be an easy replacement of Y- combinators. Not to be used explicitly by the user.

make-actor : function • arguments : [behav] Creates an actor and returns a reference to the actor with behavior specified by behav. Not supposed to be used by the CLAS user.

5 Dynamic Change of Behavior

CLAS supports dynamic behavior by changing the behavior λ itself as formulated in the Actor Calculus. For example a cell actor is changed to a print actor as follows. ( send c e l l a c t o r ( make set 1) : next (behav () (val) (pr val) next )) − − − Behavior change is real behavior change and not a change of state variables as can be seen from above.

5 6 Examples

This section discusses examples from the Chapter 2 of [Var10] implemented in CLAS .

6.1 Join Continuation Lines 4 7 in the listing 6.1 below contain the class template for a join continuation actor which− becomes sink at the end of computation. Join Continuation for Tree Product

1 ( defun left (tree) ( first t r e e ) ) 2 ( defun right (tree) ( second t r e e ) ) 3 ; Join 4 ( defactor joincont (customer (firstnum nil)) (message) 5 ( i f ( n u l l firstnum ) 6 ( progn ( s e t f firstnum message) next) 7 ( progn ( send customer ( firstnum message)) #’sink))) ∗ 8 9 ( defactor treeprod () (customer tree) 10 ( i f ( atom t r e e ) 11 ( send customer tree) 12 ( let ((newcust (joincont :customer customer)) 13 (lp (treeprod)) 14 (rp (treeprod))) 15 ( send lp newcust (left tree)) 16 ( send rp newcust (right tree)))) 17 next)

Create a new tree product actor ( s e t f tree actor (treeprod)) − Send message to the tree product actor, and send the result back to a printing actor. ( send tree actor print actor ’((2 3) ((4 5) (10 2)))) 2400 − −

6 6.2 Reference Cell A simple reference cell actor class can be built as shown below: Reference Cell

1 ( defactor cell (c) ( message) 2 ( cond ((get ? message ) ( send (cust message) c)) 3 (( set? message ) ( s e t f c (contents message)))) 4 next) 5 6 ( defun make set (val) ‘(”set” ,val)) − 7 ( defun make get (cust) ‘(”get” ,cust)) − 8 9 ( defun get? (message) ( equal ( first message) ”get”)) 10 ( defun set? (message) ( equal ( first message) ”set”)) 11 12 ( defun cust (message) ( second message ) ) 13 ( defun contents (message) ( second message ) )

A new instance with value 7 is initialized as : ( s e t f c e l l actor (cell :c 0)) − Messages can be sent as follows: ( let ((a (cell :c 0))) ( send a ( make set 7 ) ) ( send a ( make−set 2 ) ) ( send a ( make−get print actor ) ) ) − −

7 6.3 Mutual Exclusion A actor class and a customer actor class are shown in listing 6.3

Mutual Exclusion

1 ( defactor sem ((h nil)) (m) 2 ( i f ( get ? m) 3 ( i f ( n u l l h) 4 ( progn ( send ( cust m) t ) 5 ( s e t f h ( cust m) ) 6 next) 7 ( progn ( send (cust m) nil) 8 next )) 9 (if (release? m) 10 ( progn ( s e t f h n i l ) next) 11 next ))) 12 13 ( defactor customer (semaphore) (m) 14 ( i f m 15 (progn (pr ”Critical code”) 16 ( send semaphore (make release ) ) ) − 17 ( send semaphore (make get s e l f ))) − 18 next) 19 20 ( defun make release () ‘(”release” )) − 21 ( defun make get (cust) ‘(”get” ,cust)) − 22 23 ( defun get? (message) ( equal ( first message) ”get”)) 24 ( defun release? (message) ( equal ( f i r s t message) ”release”)) 25 26 ( defun cust (message) ( second message ) )

Two actors trying to enter a critical region can be modeled as ( let ( ( s ( sem ) ) (a1 (customer :semaphore s)) (a2 (customer :semaphore s))) ( send a1 n i l ) ( send a2 n i l ) )

8 6.4 Dining Philosophers The philosopher actor class and the chopstick actor class are show in listing 6.4

Mutual Exclusion

1 ( defactor phil (l r (sticks 0)) (m) 2 ( i f ( zerop s t i c k s ) 3 ( progn 4 (pr ”Got one”) 5 ( i n c f s t i c k s ) next) 6 ( progn 7 (pr ”Got both”) 8 ( send l ( make drop s e l f ))( send r ( make drop s e l f )) − − 9 (pr ”Dropped”) 10 ( send l ( make pick s e l f ))( send r ( make pick s e l f )) − − 11 ( s e t f s t i c k s 0) next ))) 12 13 ( defactor chopstick ((h nil) (w nil)) (m) 14 (if (pick? m) 15 ( i f ( n u l l h) 16 ( progn ( send ( get phil m) n i l ) − 17 ( s e t f h ( get phil m) w nil) − 18 next) 19 ( progn ( s e t f w ( get phil m) ) − 20 next ))) 21 (if (drop? m) 22 ( i f ( n u l l w) 23 ( progn ( s e t f w n i l h n i l ) 24 next) 25 ( progn ( send w n i l ) 26 ( s e t f h w w n i l ) ) ) ) 27 next) 28 29 ( defun make drop (cust) ‘(”drop” ,cust)) − 30 ( defun make pick (cust) ‘(”pick” ,cust)) − 31 ( defun pick ? ( x ) ( equal ( first x ) ” pick ” ) ) 32 ( defun drop ? ( x ) ( equal ( first x ) ”drop” ) ) 33 ( defun get phil (m) ( second m) ) −

New philosophers and chopsticks are created as follows ( let ((c1 (chopstick)) ∗ (c2 (chopstick)) (p1 (phil :l c1 :r c2)) (p2 (phil :l c2 :r c1))) ( send c1 ( make pick p1 ) ) − 9 ( send c2 ( make pick p1 ) ) ( send c1 ( make−pick p2 ) ) ( send c2 ( make−pick p2 ) ) ) −

7 More Resources

The CLAS system can be downloaded from GitHub:

http://github.com/naveensundarg/Common-Lisp-Actors

Miscellaneous stuff:

http://www.cs.rpi.edu/~govinn/clas.html This manual can be found at :

http://www.cs.rpi.edu/~govinn/actors.pdf

8 Future Work

I plan to implement distribution and mobility of actors in CLAS . The only major issue, that I foresee, is of Common Lisp objects, but this can be overcome by explicitly stating which objects are serializable.

References

[A+86] G.A. Agha et al. Actors: a model of concurrent computation in distributed systems. MIT press Cambridge, MA, 1986.

[Var10] C. Varela. : A Foundational Approach. MIT Press, 2010.

10