From wagnerj@iris.ucdavis.edu  Mon Jun 26 00:18:51 1989
Received: from clover.ucdavis.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA01181; Mon, 26 Jun 89 00:18:51 MST
Received: from iris.ucdavis.edu by clover.ucdavis.edu (5.59/UCD.EECS.1.10)
	id AA01126; Mon, 26 Jun 89 00:18:27 PDT
Received: by iris (1.2/3.14)
	id AA21073; Mon, 26 Jun 89 00:15:36 pdt
Date: Mon, 26 Jun 89 00:15:36 pdt
From: wagnerj@iris.ucdavis.edu (John Michael Wagner)
Message-Id: <8906260715.AA21073@iris>
To: info-sr@arizona.edu

I am trying to port SR to the Sun 4, working with Dr. Ron Olsson.
The SPARC architecture is new to me, as is assembly.  The major
routines, possibly the only routines, I need to port are, of
course, the run-time support routines for sr_build_context,
etc.  The Mips is also a RISC machine, but totally different; I
thought it might be of help, but I don't think that will be the case.
My major stumbling block is, at this time, which registers need to
be saved.  Everything else is rather trivial.  Perhaps there
is someone else interested in this port who knows Sun 4 assembly
and, more specifically, the C/assembly interface.  Any help/
suggestions/comments would be appreciated.  E-mail me at
wagnerj@iris.ucdavis.edu
Thanks in advance for any/all replies!
-John Wagner


From gmt  Thu Jul 27 10:24:41 1989
Date: Thu, 27 Jul 89 10:24:41 MST
From: "Gregg Townsend" <gmt>
Message-Id: <8907271724.AA06369@megaron.arizona.edu>
Received: by megaron.arizona.edu (5.59-1.7/15)
	id AA06369; Thu, 27 Jul 89 10:24:41 MST
To: info-sr
Subject: announcing SR version 1.1

A revised implementation of the SR programming language is now available from
the University of Arizona by anonymous FTP or by mail.  The new version is a
little faster, a little more robust, and a lot more portable.  Some minor
changes and enhancements have also been made to the language itself.
[I'll post the release notes as a separate message.]

SR (Synchronizing Resources) is designed for writing distributed programs.
The main language constructs are resources and operations.  Resources
encapsulate processes and variables they share; operations provide the primary
mechanism for process interaction.  SR provides a novel integration of the
mechanisms for invoking and servicing operations.  Consequently, all of local
and remote procedure call, rendezvous, message passing, dynamic process
creation, multicast, and semaphores are supported.  An overview of the
language and implementation appeared in the January, 1988, issue of TOPLAS
(ACM Transactions on Programming Languages and Systems 10,1, 51-86).

SR has been used at a number of universities and labs for course work
and research projects involving concurrent programming.  It has been
used in concurrent programming courses to reinforce concepts with
small programming projects and with larger projects such as replicated
databases, distributed simulations, and parts of distributed operating
systems such as file systems and command interpreters.  SR has also
been used as a tool in several masters theses and to implement larger
systems such as a system for mixed language programming, one for
distributed implementation of graph algorithms, experiments with load
balancing algorithms, and experiments with upcall program structures.

SR now runs on any of these machines:
    Vax  (BSD Unix, or Ultrix with gcc)
    Sun 2, Sun 3, or Sun 4
    Decstation 3100
    NeXT
    Hewlett Packard 9000 (series 300 and 800)
    Encore Multimax  (Umax)
An SR program runs on one or more networked machines of the same architecture.

SR is available by anonymous FTP from Arizona.EDU (128.196.128.118 or
192.12.69.1).  SR tar(1) files are available in the sr subdirectory;
be sure to transfer files in binary (image) mode.  The files are:

    sr.tar	The SR programming language, including source code,
		documentation, checkout programs, and examples.

    vs.tar	Extended verification suite, needed only if you're going to
		modify the system or port it to a new architecture.

The same files are also available in compress(1) form as sr.tar.Z and vs.tar.Z. 
If you pick up a copy of SR by FTP, please let us know by email to
"sr-project@Arizona.EDU".  This address can also be used for any questions or
comments.  Via uucp, you can reach us at uunet!arizona!sr-project.

SR is available by mail on 1/2" magnetic tape or 1/4" Sun cartridge.  For
details and an order blank, contact the SR project at the email address above;
or call (602) 621-2018; or send a letter to:

    SR Project
    Department of Computer Science
    University of Arizona
    Tucson, AZ  85721

An electronic mailing list is in place for discussing SR topics.  You can
join by sending your email address to "info-sr-request@Arizona.EDU".

From gmt  Thu Jul 27 10:28:47 1989
Date: Thu, 27 Jul 89 10:28:47 MST
From: "Gregg Townsend" <gmt>
Message-Id: <8907271728.AA06740@megaron.arizona.edu>
Received: by megaron.arizona.edu (5.59-1.7/15)
	id AA06740; Thu, 27 Jul 89 10:28:47 MST
To: info-sr
Subject: SR 1.1 release notes



              Release Notes for SR Version 1.1


                       Gregg Townsend

               Department of Computer Science
                 The University of Arizona

                       July 24, 1989


     This document surveys the  changes  introduced  between
Version  1.0 and Version 1.1 of the SR Programming Language.
The revised language is  described  more  precisely  in  the
reference manual.


New Platforms

     SR now supports a wider  variety  of  system  architec-
tures.   New systems include the Decstation 3100, the Sun 4,
the NeXT  computer  system,  and  the  Hewlett-Packard  9000
(series  300  and  800).   SR can now also run on Vax Ultrix
systems if the GNU C compiler is available.  As a result  of
the  modifications  these systems required, additional ports
should be considerably easier.


Incompatible Language Changes

     Signatures.  Scalars are no longer considered  compati-
ble with arrays, even if the size is the same.  For example,
an integer vector of length 1 is no  longer  interchangeable
with  a  simple  integer.   The new restriction is partially
enforced at this time and we anticipate stricter checking in
the future.

     Character Literals.   Single  quotes  now  designate  a
character  literal  instead  of  a  string  literal.  Double
quotes still define a string literal.  A  character  literal
has type char and contains only one character.  For example,
'x' and '\n' are character literals, while "x\n" is still  a
string literal.

     String literals must be replaced by character  literals
in  certain  situations.  A string can no longer be assigned
to a simple char variable nor passed as an argument  to  the
char() conversion function, so
        var c    : char := "X"
        var z[3] : char := ([3] char("z"))

become
        var c    : char := 'X'
        var z[3] : char := ([3] 'z')


Language Extensions

     Operation Declarations.   For  consistency  with  other
declarations, the syntax for operation declarations has been
extended.  The forms op a, b, c: optypename and  op  x(...),
y(...), z(...) are now accepted.

     Semaphores.  A new sem keyword allows explicit declara-
tion  of  semaphores.   New P(name) and V(name) builtins are
also provided.  These abbreviations provide no  new  facili-
ties  but  sometimes  allow  a  clearer  expression  of  the
programmer's intentions.  Diagnostics are still in terms  of
the underlying implementation as special operations.

     Processes.  SR now allows the specification of quantif-
iers  when  declaring processes, for example process p (i:=1
to 3) declares an array of processes.

     Co Statements.  A send statement is now allowed as  the
invocation part of a co statement.

     Input Statements.  An else clause is now  allowed,  and
will  be executed if no invocation is selectable.  st is now
allowed as an alternative to and for introducing a synchron-
ization expression.

     Pointers.  Pointer arithmetic, similar to  that  of  C,
has been added.  Pointers can now be printed using write and
writes.  A generic pointer type ptr any has been added.

     New Timing Functions.  age() returns the  elapsed  time
since  creation  of  the current virtual machine.  nap(msec)
suspends the current SR process for a specified interval.


Commands and Tools

     srl now accepts .a files as command arguments to  allow
linking with user libraries of C functions.

     srl no longer creates a re-srl file.  The  re-srl  file
caused more confusion than it was worth.

     srm has a new -s option to produce a smarter Makefile.

     srgrind is a new script that uses vgrind to  format  SR
code for troff.

     An SR editing mode for GNU Emacs is now provided.


Internal Improvements

     Numerous bugs, notably some involving virtual machines,
have been fixed.

     I/O waiting is handled  much  more  intelligently,  and
periodic  timer  interrupts are no longer used.  Among other
things, these changes improve the performance  of  multiple-
virtual-machine programs.

     Code has been added to prevent a process in a CPU  loop
from shutting out all others.

     Smarter code generation has improved the performance of
in statements.


Documentation and Examples

     The updated reference manual, Report on the SR Program-
ming  Language,  Version 1.1, is included.  The installation
guide and other documents were also  revised.   The  porting
guide was completely rewritten.

     PostScript  versions  of  the  documentation  are   now
included in the distribution.

     Some new programs have been added in the examples  sub-
directory.   One of these is a working version of the ``Din-
ing Philosophers'' program from the SR Overview.


Acknowledgements

     Many of these changes are due the  efforts  of  outside
contributors.   In  particular,  we thank Ron Olsson, Carole
McNamee, John Wagner, and Greg Whitehead at  the  University
of  California  at  Davis;  and David Jacobson, Ulrike Glav-
itsch, Luigi Semenzato, and Joe Park at Hewlett-Packard.

From aprakash@dost.eecs.umich.edu  Wed Aug 16 12:18:01 1989
Received: from dost.eecs.umich.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA10381; Wed, 16 Aug 89 12:18:01 MST
Received: by dost.eecs.umich.edu (5.57/umich-5.5)
	id AA02462; Wed, 16 Aug 89 15:07:23 EDT
Date: Wed, 16 Aug 89 15:07:23 EDT
From: aprakash@dost.eecs.umich.edu (Atul Prakash)
Message-Id: <8908161907.AA02462@dost.eecs.umich.edu>
To: info-sr@arizona.edu
Subject: Unexpected deadlock in dining philosopher code?
Cc: aprakash@dost.eecs.umich.edu


I was running the dining philosopher solution in examples/dining directory
with a slight modification on my DEC 3100 and it seems to run into 
an unexpected deadlock. The only modification is to run the 
program on multiple virtual machines, with each virtual machine 
running one philosopher and one
servant. On completing the specified number of iterations, the philosophers
are supposed to print out a message "philosopher id wishes to end". On
most runs, this message is successfully printed out by each philosopher. 
However, at times,
it is not and I have no explanation. As far as I can make out, the program
is not supposed to deadlock. I am a new user of SR and I want
to find out where the bug is -- in SR, in Ultrix, or in the program. Any 
explanations for this behavior?

-- Atul Prakash
(aprakash@zip.eecs.umich.edu)

Here is the CODE I used followed by a SCRIPT of one of the sample runs:

--------- modified code for dining.sr -----------------------


##  Distributed Dining Philosophers
#   %W% %G%
#
#   Based on the example in "An Overview of the SR Language and Implementation",
#   by Greg Andrews, Ron Olsson, and a cast of thousands, in the January, 1988
#   issue of TOPLAS (ACM Transactions on Programming Languages and Systems 10,1,
#   51-86).
#
#   The algorithm is from Chandy and Misra's "Drinking Philosophers Problem",
#   which appeared in the October, 1984, issue of TOPLAS (6,4, 632-646).
#
#   usage:  a.out n s	(for n philosophers and s sessions)



#   Abstract operations define two types of servant operations.

resource PhilOps		# services provided to the philosopher
    op getforks()  {call}
    op relforks()
end


resource ServOps		# messages exchanged among servants
    op needL()	{send}		# requests for a fork
    op needR()	{send}
    op passL()	{send}		# passing a fork to a neighbor
    op passR()	{send}
end



#   Servants do all the work.  There's one for each philosopher.

resource Servant
    extend PhilOps, ServOps
    op links(l,r : cap ServOps)			# init neighbor links
    op forks(haveL, dirtyL, haveR, dirtyR : bool)	# init fork values

body Servant(id : int)
    var l, r : cap ServOps
    var haveL, dirtyL, haveR, dirtyR : bool
    op hungry()	{send}
    op eat()	{send}

    proc getforks()
	write("philosopher", id, "is hungry")
	send hungry()     # let server know philosopher is hungry
	receive eat()     # wait for permission to eat
    end



    process server
	receive links(l,r)
	receive forks(haveL,dirtyL,haveR,dirtyR)
	write("servant",id,"is executing")
    	do true->
	    in hungry() ->
		# ask for forks I do not have -- note: I ask my right
		# neighbor for his left fork, and my left neighbor for
		# his right fork
		    if ~haveR -> send r.needL() fi
		    if ~haveL -> send l.needR() fi
		# wait until I have both forks
		    do ~(haveL & haveR) ->
			in passL() -> haveL := true; dirtyL := false
			[] passR() -> haveR := true; dirtyR := false
			[] needR() & dirtyR ->
				haveR := false; dirtyR := false
				send r.passL()
			[] needL() & dirtyL ->
				haveL := false; dirtyL := false
				send l.passR()
			ni
		    od
		# let my philosopher eat; wait for him to finish
		    send eat(); dirtyL := true; dirtyR := true
		    receive relforks()
	    [] needR() ->   
		# right neighbor needs his left fork, which is my right fork
		    haveR := false; dirtyR := false
		    send r.passL()
	    [] needL() ->
		# left neighbor needs his right fork, which is my left fork
		    haveL := false; dirtyL := false
		    send l.passR()

	    ni
	od
    end server

end Servant



#  The Philosopher resource is simple.

resource Philosopher
    import PhilOps

body Philosopher(myservant : cap PhilOps; id, t : int)

    process phil
	write("philosopher", id, "is beginning")
	fa i := 1 to t ->
	    myservant.getforks()
	    write("philosopher",id,"is eating")		# eat
	    myservant.relforks()
	    write("philosopher",id,"is thinking")	# think
	af
	write("philosopher", id, "wishes to end")
    end

end Philosopher




#  The main resource starts everything up.

resource Main
    import Philosopher, PhilOps, ServOps, Servant

body Main()
    initial
	var n := 5
	var t := 3
	getarg(1,n)	# get number of philosophers, if specified
	getarg(2,t)	# get session count, if specified
	
  	var s[1:n]  : cap Servant
  	var si[1:n] : cap ServOps
	var pi[1:n] : cap PhilOps
	var p[1:n]  : cap Philosopher
	var vmcap[1:n] : cap vm

	# create five virtual machines, one for each servant and
	#  philosopher pair.
	  fa i := 1 to n ->
		vmcap[i] := create vm() on 0
	  af

	# create each servant and philosopher
  	  fa i := 1 to n ->
	    s[i] := create Servant(i) on vmcap[1]
	    si[i].needL := s[i].needL		# build ServantOp cap
	    si[i].needR := s[i].needR
	    si[i].passL := s[i].passL
	    si[i].passR := s[i].passR

	    pi[i].getforks := s[i].getforks	# build PhilosopherOp cap
	    pi[i].relforks := s[i].relforks
	    p[i] := create Philosopher(pi[i],i,t) on vmcap[1]
	  af
	# give each Servant its links to neighboring Servants
	  send s[1].links(si[n],si[2])
          fa i := 2 to n-1 -> send s[i].links(si[i-1],si[i+1]) af
	  send s[n].links(si[n-1],si[1])
	# initialize each Servant's forks
	#   note:  this must be asymmetric or deadlock could result
	send s[1].forks(true,false,true,false)
	fa i := 2 to n-1 ->  send s[i].forks(false,false,true,false) af
	send s[n].forks(false,false,false,false)
    end

end Main

------------------------ A script that ends in a deadlock -------------


% dining
philosopher 1 is beginning
philosopher 1 is hungry
philosopher 2 is beginning
philosopher 2 is hungry
philosopher 3 is beginning
philosopher 3 is hungry
philosopher 4 is beginning
philosopher 4 is hungry
philosopher 5 is beginning
philosopher 5 is hungry
servant 1 is executing
philosopher 1 is eating
servant 2 is executing
servant 3 is executing
philosopher 1 is thinking
philosopher 2 is eating
philosopher 1 is hungry
servant 4 is executing
philosopher 2 is thinking
philosopher 3 is eating
servant 5 is executing
philosopher 2 is hungry
philosopher 3 is thinking
philosopher 4 is eating
philosopher 3 is hungry
philosopher 4 is thinking
philosopher 5 is eating
philosopher 4 is hungry
philosopher 5 is thinking
philosopher 5 is hungry

---- All the processes hang at this point ------






From olsson@ivy.ucdavis.edu  Wed Aug 16 17:28:06 1989
Received: from clover.ucdavis.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA24595; Wed, 16 Aug 89 17:28:06 MST
Received: from ivy.ucdavis.edu by clover.ucdavis.edu (5.59/UCD.EECS.1.11)
	id AA00566; Wed, 16 Aug 89 17:24:29 PDT
Received: by ivy.ucdavis.edu (3.2/3.14)
	id AA11648; Wed, 16 Aug 89 16:35:07 PDT
Date: Wed, 16 Aug 89 16:35:07 PDT
From: olsson@ivy.ucdavis.edu (Ron Olsson)
Message-Id: <8908162335.AA11648@ivy.ucdavis.edu>
To: aprakash@dost.eecs.umich.edu, info-sr@arizona.edu
In-Reply-To: Atul Prakash's message of Wed, 16 Aug 89 15:07:23 EDT <8908161907.AA02462@dost.eecs.umich.edu>
Subject: Unexpected deadlock in dining philosopher code?

   Date: Wed, 16 Aug 89 15:07:23 EDT
   From: aprakash@dost.eecs.umich.edu (Atul Prakash)

   I was running the dining philosopher solution in examples/dining
   directory with a slight modification on my DEC 3100 and it seems to
   run into an unexpected deadlock. The only modification is to run
   the program on multiple virtual machines, with each virtual machine
   running one philosopher and one servant. On completing the
   specified number of iterations, the philosophers are supposed to
   print out a message "philosopher id wishes to end". On most runs,
   this message is successfully printed out by each philosopher.
   However, at times, it is not and I have no explanation. As far as I
   can make out, the program is not supposed to deadlock. I am a new
   user of SR and I want to find out where the bug is -- in SR, in
   Ultrix, or in the program. Any explanations for this behavior?

The problem is that the implementation of SR does not detect
deadlock/termination in multiple vm programs.  Specifically, each
server on the different vm's blocks on its input statement; if our
implementation were smart, it would detect that the program is
quiescent and shut everything down.

The reason you get different output from different executions is that
some output is not being flushed.  If you add a `flush(stdout)'
statement to the philosopher code right before its end, you'll get the
same output every time.

One way to modify the program so it halts is for each philosopher to
notify the main resource when it has finished; the main resource can
then execute a stop statement to terminate everything.  I've attached
the modified program below.  Let us know whether it works for you.
BTW, distributed deadlock/termination detection is on our Wishlist,
although it probably won't be implemented for at least 6 months.

(Thanks to Greg Andrews for recognizing the cause of this problem;
I'm answering since his machine is down.)

##  Distributed Dining Philosophers
#   %W% %G%
#
#   Based on the example in "An Overview of the SR Language and Implementation",
#   by Greg Andrews, Ron Olsson, and a cast of thousands, in the January, 1988
#   issue of TOPLAS (ACM Transactions on Programming Languages and Systems 10,1,
#   51-86).
#
#   The algorithm is from Chandy and Misra's "Drinking Philosophers Problem",
#   which appeared in the October, 1984, issue of TOPLAS (6,4, 632-646).
#
#   usage:  a.out n s	(for n philosophers and s sessions)



#   Abstract operations define two types of servant operations.

resource PhilOps		# services provided to the philosopher
    op getforks()  {call}
    op relforks()
end


resource ServOps		# messages exchanged among servants
    op needL()	{send}		# requests for a fork
    op needR()	{send}
    op passL()	{send}		# passing a fork to a neighbor
    op passR()	{send}
end



#   Servants do all the work.  There's one for each philosopher.

resource Servant
    extend PhilOps, ServOps
    op links(l,r : cap ServOps)			# init neighbor links
    op forks(haveL, dirtyL, haveR, dirtyR : bool)	# init fork values

body Servant(id : int)
    var l, r : cap ServOps
    var haveL, dirtyL, haveR, dirtyR : bool
    op hungry()	{send}
    op eat()	{send}

    proc getforks()
	write("philosopher", id, "is hungry")
	send hungry()     # let server know philosopher is hungry
	receive eat()     # wait for permission to eat
    end



    process server
	receive links(l,r)
	receive forks(haveL,dirtyL,haveR,dirtyR)
	write("servant",id,"is executing")
    	do true->
	    in hungry() ->
		# ask for forks I do not have -- note: I ask my right
		# neighbor for his left fork, and my left neighbor for
		# his right fork
		    if ~haveR -> send r.needL() fi
		    if ~haveL -> send l.needR() fi
		# wait until I have both forks
		    do ~(haveL & haveR) ->
			in passL() -> haveL := true; dirtyL := false
			[] passR() -> haveR := true; dirtyR := false
			[] needR() & dirtyR ->
				haveR := false; dirtyR := false
				send r.passL()
			[] needL() & dirtyL ->
				haveL := false; dirtyL := false
				send l.passR()
			ni
		    od
		# let my philosopher eat; wait for him to finish
		    send eat(); dirtyL := true; dirtyR := true
		    receive relforks()
	    [] needR() ->   
		# right neighbor needs his left fork, which is my right fork
		    haveR := false; dirtyR := false
		    send r.passL()
	    [] needL() ->
		# left neighbor needs his right fork, which is my left fork
		    haveL := false; dirtyL := false
		    send l.passR()

	    ni
	od
    end server

end Servant



#  The Philosopher resource is simple.

resource Philosopher
    import PhilOps

body Philosopher(myservant : cap PhilOps; id, t : int; done: cap())

    process phil
	write("philosopher", id, "is beginning")
	fa i := 1 to t ->
	    myservant.getforks()
	    write("philosopher",id,"is eating")		# eat
	    myservant.relforks()
	    write("philosopher",id,"is thinking")	# think
	af
	write("philosopher", id, "wishes to end")
	send done()
    end

end Philosopher




#  The main resource starts everything up.

resource Main
    import Philosopher, PhilOps, ServOps, Servant

body Main()
    initial
	var n := 5
	var t := 3
	getarg(1,n)	# get number of philosophers, if specified
	getarg(2,t)	# get session count, if specified
	
  	var s[1:n]  : cap Servant
  	var si[1:n] : cap ServOps
	var pi[1:n] : cap PhilOps
	var p[1:n]  : cap Philosopher
	var vmcap[1:n] : cap vm
	op done()

	# create five virtual machines, one for each servant and
	#  philosopher pair.
	  fa i := 1 to n ->
		vmcap[i] := create vm() on 0
	  af

	# create each servant and philosopher
  	  fa i := 1 to n ->
	    s[i] := create Servant(i) on vmcap[1]
	    si[i].needL := s[i].needL		# build ServantOp cap
	    si[i].needR := s[i].needR
	    si[i].passL := s[i].passL
	    si[i].passR := s[i].passR

	    pi[i].getforks := s[i].getforks	# build PhilosopherOp cap
	    pi[i].relforks := s[i].relforks
	    p[i] := create Philosopher(pi[i],i,t,done) on vmcap[1]
	  af
	# give each Servant its links to neighboring Servants
	  send s[1].links(si[n],si[2])
          fa i := 2 to n-1 -> send s[i].links(si[i-1],si[i+1]) af
	  send s[n].links(si[n-1],si[1])
	# initialize each Servant's forks
	#   note:  this must be asymmetric or deadlock could result
	send s[1].forks(true,false,true,false)
	fa i := 2 to n-1 ->  send s[i].forks(false,false,true,false) af
	send s[n].forks(false,false,false,false)
	# wait for philosophers to finish; then stop.
	  fa i := 1 to n -> receive done()  af
	  stop
    end

end Main

From aprakash@dost.eecs.umich.edu  Thu Aug 17 08:30:51 1989
Received: from dost.eecs.umich.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA06162; Thu, 17 Aug 89 08:30:51 MST
Received: by dost.eecs.umich.edu (5.57/umich-5.5)
	id AA03332; Thu, 17 Aug 89 11:19:40 EDT
Message-Id: <8908171519.AA03332@dost.eecs.umich.edu>
To: olsson@ivy.ucdavis.edu (Ron Olsson)
Cc: aprakash@zip.eecs.umich.edu, info-sr@arizona.edu
Subject: Re: Unexpected deadlock in dining philosopher code? 
In-Reply-To: Your message of Wed, 16 Aug 89 16:35:07 -0700.
             <8908162335.AA11648@ivy.ucdavis.edu> 
Date: Thu, 17 Aug 89 11:19:36 EDT
From: aprakash@dost.eecs.umich.edu


I get the "deadlock" problem even with the new code Ron Olsson sent recently 
for multiple virtual machine version of dining philosophers with 
termination detection.

I had also initially thought that lack of deadlock detection  may be 
the problem and had tried
fixing it unsuccesfully with termination detection earlier (I used a 
less elegant solution though then Ron Olsson sent) but avoided 
including it in my previous mail as it did not affect the problem.

You have to run the program several times in order to reproduce the
deadlock. On my machine (3100 running Ultrix), it occurs on 
the average of once every five executions.

Below is the script from a correct run and an erroneous run 
with Ron Olsson's code.
I think it blocks at pretty much the same point whether there is
termination detection or not.

-- Atul Prakash
(aprakash@zip.eecs.umich.edu)

-------------- script for correct execution -------------------------------

%dining
philosopher 5 is hungry
servant 1 is executing
philosopher 1 is eating
servant 2 is executing
servant 3 is executing
philosopher 1 is thinking
philosopher 2 is eating
philosopher 1 is hungry
servant 4 is executing
philosopher 2 is thinking
philosopher 3 is eating
philosopher 2 is hungry
servant 5 is executing
philosopher 3 is thinking
philosopher 4 is eating
philosopher 1 is eating
philosopher 3 is hungry
philosopher 4 is thinking
philosopher 1 is thinking
philosopher 5 is eating
philosopher 2 is eating
philosopher 4 is hungry
philosopher 1 is hungry
philosopher 5 is thinking
philosopher 2 is thinking
philosopher 3 is eating
philosopher 5 is hungry
philosopher 2 is hungry
philosopher 3 is thinking
philosopher 4 is eating
philosopher 1 is eating
philosopher 3 is hungry
philosopher 4 is thinking
philosopher 1 is thinking
philosopher 5 is eating
philosopher 2 is eating
philosopher 4 is hungry
philosopher 1 wishes to end
philosopher 5 is thinking
philosopher 2 is thinking
philosopher 3 is eating
philosopher 5 is hungry
philosopher 2 wishes to end
philosopher 3 is thinking
philosopher 4 is eating
philosopher 3 wishes to end
philosopher 4 is thinking
philosopher 5 is eating
philosopher 4 wishes to end
philosopher 5 is thinking
philosopher 5 wishes to end

The program successfully terminates here and you get the Unix prompt.

--------- script for incorrect execution
%dining
philosopher 1 is beginning
philosopher 1 is hungry
philosopher 2 is beginning
philosopher 2 is hungry
philosopher 3 is beginning
philosopher 3 is hungry
philosopher 4 is beginning
philosopher 4 is hungry
philosopher 5 is beginning
philosopher 5 is hungry
servant 1 is executing
philosopher 1 is eating
servant 2 is executing
servant 3 is executing
philosopher 1 is thinking
philosopher 2 is eating
philosopher 1 is hungry
servant 4 is executing
philosopher 2 is thinking
philosopher 3 is eating
servant 5 is executing
philosopher 2 is hungry
philosopher 3 is thinking
philosopher 4 is eating
philosopher 3 is hungry
philosopher 4 is thinking
philosopher 5 is eating
philosopher 4 is hungry
philosopher 5 is thinking
philosopher 5 is hungry

The program hangs here and has to be killed. Couple of things to notice
here for this run.  First notice that everyone is supposed to eat three 
times (the default); however, 1 has only once. So, we are not 
at termination point.  Further, at this point 5 is supposed to pass 
its forks to 1 or 4 and so either 1 or 4 should be able to eat. However, 
that is not happening.

From jacobson%cello@hplabs.hp.com  Fri Aug 18 06:59:32 1989
Received: from hplms2.hpl.hp.com by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA06562; Fri, 18 Aug 89 06:59:32 MST
Received: from cello.HPL.HP.COM (cello.hpl.hp.com) by hplms2.hp.com; Fri, 18 Aug 89 06:55:57 pdt
Received: by cello.HPL.HP.COM; Thu, 17 Aug 89 21:08:30 pdt
Date: Thu, 17 Aug 89 21:08:30 pdt
From: David Jacobson <jacobson%cello@hplabs.hp.com>
Message-Id: <8908180408.AA10346@cello.HPL.HP.COM>
To: info-sr@arizona.edu, jacobson%cello@hplabs.hp.com
Subject: Dining philosopher problems

When I run the Ron Olssson's code for the philosophers on an HP
9000s800 (actually an 835) running HP-UX version 3.10 there are two
problems.  After the first round where the philosophers begin, each
philosopher just runs in isolation.  (This is running with the default
5 philosophers and 3 rounds.)  In addition, about every 5 times or
so, it stops early, just terminating normally.  (It does not need to
be killed as others have reported.  A script of one such run follows.

-- David Jacobson
   HP Labs
------------------------
philosopher 1 is beginning
philosopher 1 is hungry
philosopher 2 is beginning
philosopher 2 is hungry
philosopher 3 is beginning
philosopher 3 is hungry
philosopher 4 is beginning
philosopher 4 is hungry
philosopher 5 is beginning
philosopher 5 is hungry
servant 1 is executing
philosopher 1 is eating
philosopher 1 is thinking
philosopher 1 is hungry
philosopher 1 is eating
philosopher 1 is thinking
philosopher 1 is hungry
philosopher 1 is eating
philosopher 1 is thinking
philosopher 1 wishes to end
servant 2 is executing
philosopher 2 is eating
philosopher 2 is thinking
philosopher 2 is hungry
philosopher 2 is eating
philosopher 2 is thinking
philosopher 2 is hungry
philosopher 2 is eating
philosopher 2 is thinking
philosopher 2 wishes to end
servant 3 is executing
philosopher 3 is eating
philosopher 3 is thinking
philosopher 3 is hungry
philosopher 3 is eating
philosopher 3 is thinking
philosopher 3 is hungry
philosopher 3 is eating
philosopher 3 is thinking
philosopher 3 wishes to end
servant 4 is executing

From deng@chaos.sunysb.edu  Fri Aug 18 07:16:04 1989
Received: from chaos.sunysb.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA07389; Fri, 18 Aug 89 07:16:04 MST
Received:  by chaos.sunysb.edu (3.2/25-eef)
	id AA05156; Fri, 18 Aug 89 10:04:26 EDT
Date: Fri, 18 Aug 89 10:04:26 EDT
From: Yuefan Deng <deng@chaos.sunysb.edu>
Message-Id: <8908181404.AA05156@chaos.sunysb.edu>
To: info-sr@arizona.edu, jacobson%cello@hplabs.hp.com
Subject: Re:  Dining philosopher problems

Could you all change my address from deng@cmcl2.nyu.edu to
deng@chaos.sunysb.edu. Thanks in advance.

y deng

From jacobson%cello@hplabs.hp.com  Fri Aug 18 09:21:31 1989
Received: from hplms2.hpl.hp.com by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA14754; Fri, 18 Aug 89 09:21:31 MST
Received: from cello.HPL.HP.COM (cello.hpl.hp.com) by hplms2.hp.com; Fri, 18 Aug 89 09:17:50 pdt
Received: by cello.HPL.HP.COM; Fri, 18 Aug 89 09:17:31 pdt
Date: Fri, 18 Aug 89 09:17:31 pdt
From: David Jacobson <jacobson%cello@hplabs.hp.com>
Message-Id: <8908181617.AA18157@cello.HPL.HP.COM>
To: info-sr@arizona.edu
Cc: jacobson%cello@hplabs.hp.com
Subject: Dining philosophers

I added a little bit of code to the loop that collects the done
messages to print out which philosopher was done.  Now on an
HP9000s800 the philosophers proceed somewhat irregularly, instead of
philosopher 1 eating all 3 times, then philosopher 2, etc.  Observe
the new code at the end.  (See below for 2 more statements that were
added, though.)

However, sometimes I got a deadlock in which all 5 philosopher's are
hungry.  (A script follows.)  I traced the problem to a bug in the sr
code for the servant.  When a philosopher is hungry, her servant is
willing to yield a dirty fork to a neighboring servant.  The servant
should ask for it back, though, and the code forgot to do that.  

I've added calls to needL and needR, as shown in the code at the end.
(They were not there in the code that generated the log shown below.)
Now things seem to work ok.  (We still have the bug mentioned in my
previous message, though.)

  -- David Jacobson

---------------------------------
This log code comes from a revision of Ron Olsson's code with an added write 
statement in the collector of the done messages to identify the philosopher
that is done.  

philosopher 1 is beginning
philosopher 1 is hungry
philosopher 2 is beginning
philosopher 2 is hungry
philosopher 3 is beginning
philosopher 3 is hungry
philosopher 4 is beginning
philosopher 4 is hungry
philosopher 5 is beginning
philosopher 5 is hungry
servant 1 is executing
philosopher 1 is eating
servant 2 is executing
servant 3 is executing
philosopher 1 is thinking
philosopher 2 is eating
philosopher 1 is hungry
servant 4 is executing
philosopher 2 is thinking
philosopher 3 is eating
servant 5 is executing
philosopher 2 is hungry
philosopher 3 is thinking
philosopher 4 is eating
philosopher 3 is hungry
philosopher 4 is thinking
philosopher 5 is eating
philosopher 4 is hungry
philosopher 5 is thinking
philosopher 5 is hungry

The program hung at this point and had to be killed.
---------------------------------------
##  Distributed Dining Philosophers
#   %W% %G%
#
#   Based on the example in "An Overview of the SR Language and Implementation",
#   by Greg Andrews, Ron Olsson, and a cast of thousands, in the January, 1988
#   issue of TOPLAS (ACM Transactions on Programming Languages and Systems 10,1,
#   51-86).
#
#   The algorithm is from Chandy and Misra's "Drinking Philosophers Problem",
#   which appeared in the October, 1984, issue of TOPLAS (6,4, 632-646).
#
#   usage:  a.out n s	(for n philosophers and s sessions)



#   Abstract operations define two types of servant operations.

resource PhilOps		# services provided to the philosopher
    op getforks()  {call}
    op relforks()
end


resource ServOps		# messages exchanged among servants
    op needL()	{send}		# requests for a fork
    op needR()	{send}
    op passL()	{send}		# passing a fork to a neighbor
    op passR()	{send}
end



#   Servants do all the work.  There's one for each philosopher.

resource Servant
    extend PhilOps, ServOps
    op links(l,r : cap ServOps)			# init neighbor links
    op forks(haveL, dirtyL, haveR, dirtyR : bool)	# init fork values

body Servant(id : int)
    var l, r : cap ServOps
    var haveL, dirtyL, haveR, dirtyR : bool
    op hungry()	{send}
    op eat()	{send}

    proc getforks()
	write("philosopher", id, "is hungry")
	send hungry()     # let server know philosopher is hungry
	receive eat()     # wait for permission to eat
    end



    process server
	receive links(l,r)
	receive forks(haveL,dirtyL,haveR,dirtyR)
	write("servant",id,"is executing")
    	do true->
	    in hungry() ->
		# ask for forks I do not have -- note: I ask my right
		# neighbor for his left fork, and my left neighbor for
		# his right fork
		    if ~haveR -> send r.needL() fi
		    if ~haveL -> send l.needR() fi
		# wait until I have both forks
		    do ~(haveL & haveR) ->
			in passL() -> haveL := true; dirtyL := false
			[] passR() -> haveR := true; dirtyR := false
			[] needR() & dirtyR ->
				haveR := false; dirtyR := false
				send r.passL()
				send r.needL()  # ask for fork back
			[] needL() & dirtyL ->
				haveL := false; dirtyL := false
				send l.passR()
				send l.needR()  # ask for fork back
			ni
		    od
		# let my philosopher eat; wait for him to finish
		    send eat(); dirtyL := true; dirtyR := true
		    receive relforks()
	    [] needR() ->   
		# right neighbor needs his left fork, which is my right fork
		    haveR := false; dirtyR := false
		    send r.passL()
	    [] needL() ->
		# left neighbor needs his right fork, which is my left fork
		    haveL := false; dirtyL := false
		    send l.passR()

	    ni
	od
    end server

end Servant



#  The Philosopher resource is simple.

resource Philosopher
    import PhilOps

body Philosopher(myservant : cap PhilOps; id, t : int; done: cap(n : int))

    process phil
	write("philosopher", id, "is beginning")
	fa i := 1 to t ->
	    myservant.getforks()
	    write("philosopher",id,"is eating")		# eat
	    myservant.relforks()
	    write("philosopher",id,"is thinking")	# think
	af
	write("philosopher", id, "wishes to end")
	send done(id)
    end

end Philosopher




#  The main resource starts everything up.

resource Main
    import Philosopher, PhilOps, ServOps, Servant

body Main()
    initial
	var n := 5
	var t := 3
	getarg(1,n)	# get number of philosophers, if specified
	getarg(2,t)	# get session count, if specified
	
  	var s[1:n]  : cap Servant
  	var si[1:n] : cap ServOps
	var pi[1:n] : cap PhilOps
	var p[1:n]  : cap Philosopher
	var vmcap[1:n] : cap vm
        op done(n:int)
        var j : int

	# create five virtual machines, one for each servant and
	#  philosopher pair.
	  fa i := 1 to n ->
		vmcap[i] := create vm() on 0
	  af

	# create each servant and philosopher
  	  fa i := 1 to n ->
	    s[i] := create Servant(i) on vmcap[1]
	    si[i].needL := s[i].needL		# build ServantOp cap
	    si[i].needR := s[i].needR
	    si[i].passL := s[i].passL
	    si[i].passR := s[i].passR

	    pi[i].getforks := s[i].getforks	# build PhilosopherOp cap
	    pi[i].relforks := s[i].relforks
	    p[i] := create Philosopher(pi[i],i,t,done) on vmcap[1]
	  af
	# give each Servant its links to neighboring Servants
	  send s[1].links(si[n],si[2])
          fa i := 2 to n-1 -> send s[i].links(si[i-1],si[i+1]) af
	  send s[n].links(si[n-1],si[1])
	# initialize each Servant's forks
	#   note:  this must be asymmetric or deadlock could result
	send s[1].forks(true,false,true,false)
	fa i := 2 to n-1 ->  send s[i].forks(false,false,true,false) af
	send s[n].forks(false,false,false,false)
	# wait for philosophers to finish; then stop.
	fa i := 1 to n -> 
	   receive done(j)  
	   write("Recvd done from philosopher ",j)
	af
	stop
    end

end Main

From olsson@ivy.ucdavis.edu  Fri Aug 18 10:28:00 1989
Received: from clover.ucdavis.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA20365; Fri, 18 Aug 89 10:28:00 MST
Received: from ivy.ucdavis.edu by clover.ucdavis.edu (5.59/UCD.EECS.1.11)
	id AA12493; Fri, 18 Aug 89 10:24:00 PDT
Received: by ivy.ucdavis.edu (3.2/3.14)
	id AA16450; Fri, 18 Aug 89 10:23:24 PDT
Date: Fri, 18 Aug 89 10:23:24 PDT
From: olsson@ivy.ucdavis.edu (Ron Olsson)
Message-Id: <8908181723.AA16450@ivy.ucdavis.edu>
To: jacobson%cello@hplabs.hp.com, info-sr@arizona.edu
In-Reply-To: David Jacobson's message of Fri, 18 Aug 89 09:17:31 pdt <8908181617.AA18157@cello.HPL.HP.COM>
Subject: Dining philosophers

Yes, the code in examples/dining has the bug you describe.  The
overview paper has it right, but we lost something in the translation.
Thanks for finding that.

From gmt  Fri Aug 18 15:14:36 1989
Date: Fri, 18 Aug 89 15:14:36 MST
From: "Gregg Townsend" <gmt>
Message-Id: <8908182214.AA08300@megaron.arizona.edu>
Received: by megaron.arizona.edu (5.59-1.7/15)
	id AA08300; Fri, 18 Aug 89 15:14:36 MST
To: info-sr
Subject: SR under Vax Ultrix 3.1

We have found that SR Version 1.1 builds and runs properly under Vax Ultrix
version 3.1 using the standard C compiler, cc.

This contrasts with Ultrix version 2, where cc couldn't handle SR, and so
the use of gcc was required.  Now, nothing special is needed.

    Gregg Townsend / Computer Science Dept / Univ of Arizona / Tucson, AZ 85721
    +1 602 621 4325      gmt@Arizona.EDU       110 57 16 W / 32 13 45 N / +758m

From aprakash@dost.eecs.umich.edu  Mon Aug 21 07:43:27 1989
Received: from dost.eecs.umich.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA20868; Mon, 21 Aug 89 07:43:27 MST
Received: by dost.eecs.umich.edu (5.57/umich-5.5)
	id AA05035; Mon, 21 Aug 89 10:32:16 EDT
Message-Id: <8908211432.AA05035@dost.eecs.umich.edu>
To: olsson@ivy.ucdavis.edu (Ron Olsson)
Cc: jacobson%cello@hplabs.hp.com, info-sr@arizona.edu
Subject: Re: Dining philosophers 
In-Reply-To: Your message of Fri, 18 Aug 89 10:23:24 -0700.
             <8908181723.AA16450@ivy.ucdavis.edu> 
Date: Mon, 21 Aug 89 10:32:13 EDT
From: aprakash@dost.eecs.umich.edu

You are welcome. It will be interesting to see what the bug is. 
Incidently, that raises a larger question of how does one go about debugging 
a program in SR, based on program translation to a different language?
Debugging multiple virtual machine programs is hard with dbx even for
programs written in C, but can -g option with dbx be somehow
used (with some manual mapping of SR names to C names, etc.) in 
stepping through a single virtual machine SR program via a debugger? This
technique was used quite successfully earlier for C++ programs that 
were translated to C (before C++ debuggers became available). 

-- Atul
(aprakash@zip.eecs.umich.edu)

From jacobson%cello@hplabs.hp.com  Fri Aug 25 09:58:10 1989
Received: from hplms2.hpl.hp.com by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA10959; Fri, 25 Aug 89 09:58:10 MST
Received: from cello.HPL.HP.COM (cello.hpl.hp.com) by hplms2.hp.com; Fri, 25 Aug 89 08:36:20 pdt
Received: by cello.HPL.HP.COM; Fri, 25 Aug 89 08:36:16 pdt
Date: Fri, 25 Aug 89 08:36:16 pdt
From: David Jacobson <jacobson%cello@hplabs.hp.com>
Message-Id: <8908251536.AA27066@cello.HPL.HP.COM>
To: info-sr@arizona.edu
Subject: Circular importation in resource specs.

There are a number of times when I have two resources that need to
import each other's specs.  For example, there might be a dictionary
resource that exports operations for mapping strings to capabilities
for foo_servers.  Foo_servers export an operation that returns
capabilies for dictionaries.

The obvious specs are these

resource dictionary
   import foo_server
   op insert(key:string(*);value cap foo_server)
   op lookup(key:string(*)) returns value cap_fooserver
end

resource foo_server
   import dictionary
   op mumble() returns x:cap dictionary
end

However, SR does not like circularity of importation.  Does anyone out
there have any suggestions about how to get around this problem?

  -- David Jacobson


From greg  Fri Aug 25 14:29:16 1989
Received: from paloverde.arizona.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA27982; Fri, 25 Aug 89 14:29:16 MST
Date: Fri, 25 Aug 89 14:29:11 MST
From: "Greg Andrews" <greg>
Message-Id: <8908252129.AA05094@paloverde.arizona.edu>
Received: by paloverde.arizona.edu; Fri, 25 Aug 89 14:29:11 MST
In-Reply-To: <8908251536.AA27066@cello.HPL.HP.COM>
To: info-sr@arizona.edu, jacobson%cello@hplabs.hp.com
Subject: Re:  Circular importation in resource specs.

    From: David Jacobson <jacobson%cello@hplabs.hp.com>
    To: info-sr@arizona.edu
    Subject: Circular importation in resource specs.
    
    There are a number of times when I have two resources that need to
    import each other's specs.  For example, there might be a dictionary
    resource that exports operations for mapping strings to capabilities
    for foo_servers.  Foo_servers export an operation that returns
    capabilies for dictionaries.
    
    The obvious specs are these
    
    resource dictionary
       import foo_server
       op insert(key:string(*);value cap foo_server)
       op lookup(key:string(*)) returns value cap_fooserver
    end
    
    resource foo_server
       import dictionary
       op mumble() returns x:cap dictionary
    end
    
    However, SR does not like circularity of importation.  Does anyone out
    there have any suggestions about how to get around this problem?
    
      -- David Jacobson
    
Lots of students ask the same question!  There are two solutions.
If there are just a few operations that one resource needs from
the other, put optype declarations in a global that both
resources import and have caps for the appropriate optypes.
The resources then talk to each other to get the capabilities
bound to the appropriate operations.  Better yet, have a third
resource create both the dictionary and foo_server, then have
it give each the appropriate operation capabilities for the other.

The second approach is to use abstract resources to encapsulate
the subset of operations of dictionary and foo_server that the
other needs.  These are compiled before the concrete resources,
which can then import the abstract resources and have caps for them.
Getting caps bound to the actual operations is done as above,
typically by a third resource.  See the on-line decentralized
dining philosophers program for an example.

Because many people would like mutual imports, we are going to
bite the implementation bullet and allow it in Version 2.0
of SR, which we are starting to work on.  That version won't
be available for about a year, though, since we several other
language extensions in mind and are just getting started.

-- Greg Andrews

From jacobson%cello@hplabs.hp.com  Fri Aug 25 15:10:52 1989
Received: from hplms2.hpl.hp.com by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA01086; Fri, 25 Aug 89 15:10:52 MST
Received: from cello.HPL.HP.COM (cello.hpl.hp.com) by hplms2.hp.com; Fri, 25 Aug 89 15:07:15 pdt
Received: from localhost by cello.HPL.HP.COM; Fri, 25 Aug 89 15:07:12 pdt
To: "Greg Andrews" <greg@arizona.edu>
Cc: info-sr@arizona.edu
Subject: Re: Circular importation in resource specs. 
In-Reply-To: Your message of "Fri, 25 Aug 89 14:29:11 MST."
             <8908252129.AA05094@paloverde.arizona.edu> 
Date: Fri, 25 Aug 89 15:07:10 PDT
Message-Id: <28744.620086030@cello>
From: jacobson%cello@hplabs.hp.com

Thank you for your reply to my query.  But I think you answered a
slightly different question than I asked.  

In my example, the caps are for entire resources.  (I'm trying to use
resources as abstract data types.  So a cap is is used to name an
instance of the ADT.)  You have described how to pass capabilities for
*operations* around.  Note that the dining philosophers solutions
passes around capabilities for things like needL, needR, passL, passR,
getforks, and relforks that are operations that take no parameters and
return no results -- in particular no capabilities for resources.

The only solution that I can see is to have a combined common abstract
type, dict_foo, then, branching two ways, extend and implement it.

resource dict_foo
   # dictionary ops
   op insert(key:string(*);value cap dict_foo)
   op lookup(key:string(*)) returns value cap dict_foo
   # foo_server ops
   op mumble () returns x cap dict_foo
end

resource dictionary
   extend dict_foo
body dictionary()
   # instance data
   proc insert ...
   proc lookup ...
   proc mumble()
      write(stderr,"This is really a dictionary, you shouldn't call mumble")
      stop
   end
end

# and similarly for foo_server

  -- David Jacobson

From greg  Fri Aug 25 15:41:13 1989
Received: from paloverde.arizona.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA02874; Fri, 25 Aug 89 15:41:13 MST
Date: Fri, 25 Aug 89 15:41:06 MST
From: "Greg Andrews" <greg>
Message-Id: <8908252241.AA05330@paloverde.arizona.edu>
Received: by paloverde.arizona.edu; Fri, 25 Aug 89 15:41:06 MST
In-Reply-To: <28744.620086030@cello>
To: greg@arizona.edu, jacobson%cello@hplabs.hp.com
Subject: Re: Circular importation in resource specs.
Cc: info-sr@arizona.edu

David is correct in his comments and shows how to
program around the lack of mutual imports.  As I
said earlier, we will eventually support mutual import
to simplify the kind of mutual resource interaction
David described.

From csc319@computing.lancaster.ac.uk  Mon Oct  9 12:27:15 1989
Received: from rvax.ccit.arizona.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA11528; Mon, 9 Oct 89 12:27:15 MST
Received: from UKACRL.BITNET by rvax.ccit.arizona.edu; Mon, 9 Oct 89 11:59 MST
Received: from RL.IB by UKACRL.BITNET (Mailer X1.25) with BSMTP id 5243; Mon,
 09 Oct 89 16:37:07 BST
Date: Mon, 9 Oct 89 15:37:59 GMT
From: csc319@computing.lancaster.ac.uk
Subject: Change of Address
To: info-sr@arizona.edu
Via:        UK.AC.LANCS.COMP;  9 OCT 89 16:37:02 BST
Message-Id: <9299.8910091537@dcl-ugrad.comp.lancs.ac.uk>

Please could you change my mail address from:
 
		csc220@comp.lancs.ac.uk.
 
to:
 
		csc319@comp.lancs.ac.uk.
 
 
		Thanks
			Graham (Dean)

From djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU  Wed Oct 11 18:55:22 1989
Received: from ucbvax.Berkeley.EDU by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA08298; Wed, 11 Oct 89 18:55:22 MST
Received: from awesome.Berkeley.EDU by ucbvax.Berkeley.EDU (5.61/1.37)
	id AA02634; Wed, 11 Oct 89 18:55:12 -0700
Received: from localhost by awesome.berkeley.edu (4.0/SMI-4.0)
	id AA11305; Wed, 11 Oct 89 18:56:50 PDT
Message-Id: <8910120156.AA11305@awesome.berkeley.edu>
To: info-sr@arizona.edu
Subject: novice question
Date: Wed, 11 Oct 89 18:56:48 -0700
From: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU


   I just installed SR on our SUNs and the first program I've tried,
   aside from existing examples, has me quite befuddled.

   What I want to do is create a "master" on the local SUN, and start
   a "slave" on each SUN named on the command line.  The "slaves" do
   some trivial computation and then report to the "master" that
   they are done.  The "master" waits for everyone to report back and
   then stops.

   The file "remote.sr" is at the end of this message.  Here is what
   happens.


   % srm
   % make
   sr -c remote.sr
   srl -o a.out master slave main
   % a.out awesome totally
   Slaves will be on:
   awesome
   totally
   makeslaves active
   makemaster active

   I am the master  2  slaves!
   waiting ...
   RTS warning: 3 blocked process during termination
   %


   It would appear that none of the sends or receives succeed.
   Any suggestions?

thanks,
 David Jones
 djones@awesome.berkeley.edu



----------- cut here ------------------

resource master
   op handshake(id:int)
body master(n:int)
   initial
      var  num			:int

      write("I am the master of ",n," slaves!")
      fa i:=1 to n ->
	 write("waiting ...")
	 flush(stdout)
	 receive handshake(num)
	 write("slave ",num," is done")
      af
      write("everyone is done.")
      flush(stdout)
      stop
   end
end master


resource slave
   import master
   op number() returns n:int
body slave(m:cap master)
   external gethostname(res s:string(*); namelen:int)

   var  h		:string(64)
   var  myid		:int

   initial
      gethostname(h,maxlength(h))
      myid:=mymachine()
   end

   process v
      writes("Slave on host ",h," running.\n")
      flush(stdout)
      nap(1000)
      write("Slave on host ",h," done.\n")
      flush(stdout)
      send m.handshake(myid)
   end

   proc number() returns n
      n:=myid
      write("slave.number(",n,")")
      flush(stdout)
   end number
end slave


resource main
   import master
   import slave
   op who_is_master(m:cap master) {send}
body main()
   var  n			:int

   initial
      var s			:string(100)

      n:=numargs()
      write("Slaves will be on: ")
      fa i:=1 to n ->
	 getarg(i,s)
	 write(s)
      af
      flush(stdout)
   end

   process makeslaves
      var s			:string(100)
      var remote		:cap vm
      var mastercap		:cap master
      var slavecap[1:n]		:cap slave

      write("makeslaves active")
      flush(stdout)
      receive who_is_master(mastercap)
      write("about to create slaves\n")
      flush(stdout)
      fa i := 1 to n ->
	 getarg(i,s)
	 locate(i,s)
	 remote:=create vm() on i
	 if (remote = null) ->
	    write(stderr,"can't create vm on",s,"\n")
	    flush(stderr)
	 [] else ->
	    write("creating slave on ",s,"\n")
	    flush(stdout)
	    slavecap[i]:=create slave(mastercap) on remote
	    if (slavecap[i] = null) ->
	       write("create slave on host ",s,", machine ",i," failed.\n")
	       flush(stdout)
	    [] else ->
	       write("slave ",i," has machine id ",slavecap[i].number())
	       flush(stdout)
	    fi
	 fi
      af
      write("all slaves created")
      flush(stdout)
      nap(30000)
   end makeslaves

   process makemaster
      var  mastercap		: cap master

      write("makemaster active\n")
      flush(stdout)
      mastercap:=create master(n) on myvm()
      if (mastercap = null) ->
	 write("failed to create a master\n")
	 flush(stdout)
	 stop
      fi
      write("master created\n")
      flush(stdout)
      send who_is_master(mastercap)
   end makemaster

end main

From olsson@ivy.ucdavis.edu  Wed Oct 11 20:59:20 1989
Received: from clover.ucdavis.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA13131; Wed, 11 Oct 89 20:59:20 MST
Received: from ivy.ucdavis.edu by clover.ucdavis.edu (5.59/UCD.EECS.1.11)
	id AA11806; Wed, 11 Oct 89 21:01:30 PDT
Received: by ivy.ucdavis.edu (3.2/3.14)
	id AA15487; Wed, 11 Oct 89 20:58:14 PDT
Date: Wed, 11 Oct 89 20:58:14 PDT
From: olsson@ivy.ucdavis.edu (Ron Olsson)
Message-Id: <8910120358.AA15487@ivy.ucdavis.edu>
To: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU
Cc: info-sr@arizona.edu
In-Reply-To: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU's message of Wed, 11 Oct 89 18:56:48 -0700 <8910120156.AA11305@awesome.berkeley.edu>
Subject: novice question

   Date: Wed, 11 Oct 89 18:56:48 -0700
   From: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU

      I just installed SR on our SUNs and the first program I've tried,
      aside from existing examples, has me quite befuddled.
      ...
      It would appear that none of the sends or receives succeed.

The problem is simple.  main creates master by

	 mastercap:=create master(n) on myvm()

Recall, however, that a create statement doesn't terminate until the
initial code in the resource instance it is creating completes.  The
essence of that code is

      initial
	 fa i:=1 to n -> 
	    receive handshake(num)
	 af
	 write("everyone is done.")
	 stop
      end

But n>=1 and no slaves exist to send the master any handshakes, so
master hangs on the receive, thereby causing main to hang.  (The
reason no servants exist is that main's create statement has not yet
terminated, so main hasn't created the servants.)

Two easy fixes:

(1) change initial in master to be a process.  Then, master's initial
code is empty (except the implicit send to create that new process),
which terminates, allowing the create to terminate.

or (2) put a reply in master's initial.  I.e., 

      initial
	 reply  # **** allower creator to continue
	 fa i:=1 to n -> 
	    receive handshake(num)
	 af
	 write("everyone is done.")
	 stop
      end

I think (1) is clearer.

BTW, not such a novice problem.  I do this myself sometimes, and I've
seen a number of other people do the same.  We should put it on our
common problem list.

From mcnamee@iris.ucdavis.edu  Thu Oct 12 11:21:39 1989
Received: from clover.ucdavis.edu by megaron (5.59-1.7/15) via SMTP
	id AA19609; Thu, 12 Oct 89 11:21:39 MST
Received: from iris.ucdavis.edu by clover.ucdavis.edu (5.59/UCD.EECS.1.11)
	id AA16179; Thu, 12 Oct 89 11:23:42 PDT
Received: by iris (5.57/3.14)
	id AA19802; Thu, 12 Oct 89 11:20:48 PDT
Date: Thu, 12 Oct 89 11:20:48 PDT
From: mcnamee@iris.ucdavis.edu (Carole McNamee)
Message-Id: <8910121820.AA19802@iris>
To: info-sr@arizona.edu
Subject: random number generator

Does anyone have an SR random number generator that produces "reasonable
sequences" ?
Thanks
C. McNamee

From gmt  Thu Oct 12 17:48:24 1989
Date: Thu, 12 Oct 89 17:48:24 MST
From: "Gregg Townsend" <gmt>
Message-Id: <8910130048.AA14749@megaron.arizona.edu>
Received: by megaron.arizona.edu (5.59-1.7/15)
	id AA14749; Thu, 12 Oct 89 17:48:24 MST
In-Reply-To: <8910121820.AA19802@iris>
To: mcnamee@iris.ucdavis.edu
Subject: Re:  random number generator
Cc: info-sr

    From: mcnamee@iris.ucdavis.edu (Carole McNamee)
    Date: Thu, 12 Oct 89 11:20:48 PDT
    
    Does anyone have an SR random number generator that produces
    "reasonable sequences" ?
	

If you're just looking to obtain random numbers in an SR program,
the easiest thing is to call the C library.  For example:

	resource x ()
		external getpid ()		returns n: int
		external random ()		returns n: int
		external srandom (seed: int)
	initial
		srandom(getpid())
		fa i := 1 to 10 -> write(random()) af
	end
	end

From mcnamee@iris.ucdavis.edu  Fri Oct 13 13:50:43 1989
Received: from clover.ucdavis.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA20715; Fri, 13 Oct 89 13:50:43 MST
Received: from iris.ucdavis.edu by clover.ucdavis.edu (5.59/UCD.EECS.1.11)
	id AA23715; Fri, 13 Oct 89 13:52:59 PDT
Received: by iris (5.57/3.14)
	id AA16577; Fri, 13 Oct 89 11:58:25 PDT
Date: Fri, 13 Oct 89 11:58:25 PDT
From: mcnamee@iris.ucdavis.edu (Carole McNamee)
Message-Id: <8910131858.AA16577@iris>
To: gmt@arizona.edu, mcnamee@iris.ucdavis.edu
Subject: Re:  random number generator
Cc: info-sr@arizona.edu

Thanks for your response, unfortunately my question wasn't specific enough.
I need to be able to control the seed as I would like many processes to be
able to call the generator and I would like to guarrantee that each process
gets the same sequence each time it executes.  

From djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU  Tue Oct 17 10:22:53 1989
Received: from ucbvax.Berkeley.EDU by megaron (5.59-1.7/15) via SMTP
	id AA23606; Tue, 17 Oct 89 10:22:53 MST
Received: from awesome.Berkeley.EDU by ucbvax.Berkeley.EDU (5.61/1.38)
	id AA07466; Tue, 17 Oct 89 10:22:52 -0700
Received: from localhost by awesome.berkeley.edu (4.0/SMI-4.0)
	id AA18864; Tue, 17 Oct 89 10:24:23 PDT
Message-Id: <8910171724.AA18864@awesome.berkeley.edu>
To: info-sr@arizona.edu
Subject: compute server
Date: Tue, 17 Oct 89 10:24:21 -0700
From: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU


I have a few questions about SR, all relating to creating a "compute server".

First, here's an overview of what I'd like to set up.

The main machine M starts a compute server resource C and some number of
computing tasks A.  (These may actually be on different computers)
Each A has two processes.  One which does some computing and the another
which queries C to find another A which is "idle".  C keeps a list
of which A's are idle.


Questions:

(1)  How can an active resource determine its own capability?
     ie, how do I assign the proper value to "me" in the example below

resource X
body X
   var me : cap X

end X


(2)  What is the easiest way to cope with resources that are interdependent,
     ie resources that want to "import" each other.
     Is the following the only solution?

resource A_stub
   op something()
end A_stub

resource B
   import A_stub
body B
end B

resource A
   extend A_stub
   import B
body A
end A


(3) Is there some SR mechanism for "broadcasting"?  An alternative to the
    "compute server" would be that each A wanting to locate an idle A could
    just broadcast a request, and accept the first reply.  If this can
    be done, can it be done efficiently? (ie so resources don't have to keep
    responding to requests to say it is not idle)

(4) Below is an example (attempted) implementation and its output.
If you have the patience ...
Does anyone have any clues why it fails?  Also, any style suggestions would
be appreciated.  When I run the resulting program, there are two outcomes.

(source in ab.sr at the end)
awesome% srm
awesome% make
sr -c ab.sr
srl -o a.out compute ab main

awesome% a.out fugitive totally >& TMP
awesome% TMP
main: AB will be on: 
fugitive
totally
make: active
awesome : compute server ready
awesome : compute server starts
awesome : compute_idler starts
awesome : compute.number( 0 )
make: compute created, machine ID is  0
make: about to create AB
make: creating AB on  fugitive
fugitive : ab initial
make: AB  1  has machine id  1
fugitive : ap_spawner, waiting for my cap
fugitive : ab_server
fugitive : ab.number( 1 )
[vm 2] RTS abort: attempting to invoke operation that no longer exists

awesome% a.out fugitive totally
main: AB will be on: 
fugitive
totally
make: active
awesome : compute server ready
awesome : compute server starts
awesome : compute_idler starts
awesome : compute.number( 0 )
make: compute created, machine ID is  0
make: about to create AB
make: creating AB on  fugitive
fugitive : ab initial
fugitive : ap_spawner, waiting for my cap
fugitive : ab_server
make: AB  1  has machine id  1
fugitive : ab.number( 1 )
srx: can't connect to vm 32 -- not yet initialized

---------------------------- ab.sr ----------------------------
/* AB */

resource ab_basics
   op ab_reply(m:cap ab_basics) 
   op ab_yourcap(m:cap ab_basics)
   op ab_work(h:string(100); m:cap ab_basics)
   op ab_work_done()
   op number() returns n : int
   external gethostname(res name:string(*); namelen:int)
end ab_basics

resource compute
   import ab_basics
   op	compute_request(m:cap ab_basics)
   op	compute_done(m:cap ab_basics)
   op	compute_unlock()
   op	compute_lock()
   op	compute_machines(m[1:*]:cap ab_basics)
   op	number() returns n:int
   external gethostname(res name:string(*); namelen:int)
body compute(n:int)
   var	h			:string(100)
   var	machine[1:n]		:cap ab_basics
   var	idle[1:n]		:int
   var	n_idle			:int
   var	index			:int

   initial
      call gethostname(h,maxlength(h))
      fa i:=1 to n ->
	 idle[i]:=1
      af
      index:=1
      n_idle:=n
      write(h,": compute server ready") flush(stdout)
   end

   proc number() returns n
      n:=mymachine()
      write(h,": compute.number(",n,")") flush(stdout)
      flush(stdout)
   end number

   process compute_lock_server
      do (true) ->
         send compute_unlock()
         receive compute_lock()
      od
   end compute_lock_server

   process compute_server
      var r			:cap ab_basics

      write(h,": compute server starts") flush(stdout)
      receive compute_machines(machine)
      write(h,": compute server knows machines") flush(stdout)
      do (true) ->
         do (n_idle < 1) ->
	    write(h,": computer server sleeping") flush(stdout)
	    nap(5000)
         od
         receive compute_request(r)
	 receive compute_unlock()
         fa i:=1 to n ->
	    if (idle[index] > 0) ->
	       send r.ab_reply(machine[i])
	       idle[i]:=0
	    fi
	    index++
	    if (index > n) ->
	       index:=1
	    fi
	 af
	 send compute_lock()
      od
   end compute_server

   process compute_idler
      var m			:cap ab_basics

      write(h,": compute_idler starts") flush(stdout)
      do (true) ->
         receive compute_done(m)
	 receive compute_unlock()
	 fa i:=1 to n ->
	    if (m = machine[i]) ->
	       write(h,": compute idler, ",i," becomes idle\n") flush(stdout)
	       idle[i]:=1
	       exit
	    fi
	 af
	 send compute_lock()
      od
   end compute_idler

end compute


resource ab
   extend ab_basics
   import compute
body ab(c:cap compute)
   var	h			:string(100)
   var	mycap			:cap ab

   initial
      gethostname(h,maxlength(h))
      write(h,": ab initial") flush(stdout)
      flush(stdout)
   end

   proc number() returns n
      n:=mymachine()
      write(h,": ab.number(",n,")") flush(stdout)
      flush(stdout)
   end number

   process ab_spawner
      var m			:cap ab

      write(h,": ap_spawner, waiting for my cap") flush(stdout)
      receive ab_yourcap(mycap)
      write(h,": ab_spawner, sleeping") flush(stdout)
      nap(4000)
      send c.compute_request(mycap)
      receive ab_reply(m)
      send m.ab_work(h,mycap)
      receive ab_work_done()
      send c.compute_done(m)
   end ab_spawner

   process ab_server
      var host			:string(100)
      var m			:cap ab

      write(h,": ab_server") flush(stdout)
      do (true) ->
         receive ab_work(host,m)
         write(h,": ab_server gets work from ",host," - sleeping") flush(stdout)
	 nap(10000)
	 send m.ab_work_done()
         write(h,": ab_server done") flush(stdout)
      od
   end ab_server

   final
      write(h,": ab final") flush(stdout)
   end
end ab


resource main
   import compute
   import ab
body main()
   var  n			:int
   var	ab_cap[1:n]		:cap ab

   initial
      var s			:string(100)

      n:=numargs()
      write("main: AB will be on: ")
      fa i:=1 to n ->
	 getarg(i,s)
	 write(s)
      af
      flush(stdout)
   end

   process make
      var s			:string(100)
      var remote		:cap vm
      var c			:cap compute

      write("make: active") flush(stdout)
      c:=create compute(n) on myvm()
      if (c = null) ->
	 write("make: failed to create a compute") flush(stdout)
	 stop
      fi
      write("make: compute created, machine ID is ",c.number()) flush(stdout)
      write("make: about to create AB") flush(stdout)
      fa i := 1 to n ->
	 getarg(i,s)
	 locate(i,s)
	 remote:=create vm() on i
	 if (remote = null) ->
	    write(stderr,"make_ab: can't create vm on",s) flush(stderr)
	 [] else ->
	    write("make: creating AB on ",s) flush(stdout)
	    ab_cap[i]:=create ab(c) on remote
	    if (ab_cap[i] = null) ->
	       write("make: create AB on host ",s,", machine ",i," failed.")
	       flush(stdout)
	    [] else ->
	       write("make: AB ",i," has machine id ",ab_cap[i].number())
	       flush(stdout)
	       send ab_cap[i].ab_yourcap(ab_cap[i])
	       write("make: AB notified of its cap")
	    fi
	 fi
      af
      write("make: all AB created, sleeping") flush(stdout)
      nap(10000)
      write("make: telling server which machines") flush(stdout)
      send c.compute_machines(ab_cap)
   end make

   final
      write("main: cleanup") flush(stdout)
   end
end main


From olsson@ivy.ucdavis.edu  Wed Oct 18 12:02:27 1989
Received: from clover.ucdavis.edu by megaron (5.59-1.7/15) via SMTP
	id AA13484; Wed, 18 Oct 89 12:02:27 MST
Received: from ivy.ucdavis.edu by clover.ucdavis.edu (5.59/UCD.EECS.1.11)
	id AA22058; Tue, 17 Oct 89 21:03:21 PDT
Received: by ivy.ucdavis.edu (3.2/3.14)
	id AA27368; Tue, 17 Oct 89 20:59:31 PDT
Date: Tue, 17 Oct 89 20:59:31 PDT
From: olsson@ivy.ucdavis.edu (Ron Olsson)
Message-Id: <8910180359.AA27368@ivy.ucdavis.edu>
To: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU
Cc: info-sr@arizona.edu
In-Reply-To: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU's message of Tue, 17 Oct 89 10:24:21 -0700 <8910171724.AA18864@awesome.berkeley.edu>
Subject: compute server

   Date: Tue, 17 Oct 89 10:24:21 -0700
   From: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU
   ...
   Questions:

   (1)  How can an active resource determine its own capability?
	ie, how do I assign the proper value to "me" in the example below

   resource X
   body X
      var me : cap X

   end X

me := myresource()  (See section 7.5 in the report.)

   (2)  What is the easiest way to cope with resources that are interdependent,
	ie resources that want to "import" each other.
	Is the following the only solution?

Maybe not the only one, but a reasonable one.  There was a discussion
on info-sr about 2 months ago on this topic; I'll send it to you.
That is a lacking in SR -- something we are remedying in version 2.

   (3) Is there some SR mechanism for "broadcasting"?  An alternative to the
       "compute server" would be that each A wanting to locate an idle A could
       just broadcast a request, and accept the first reply.  If this can
       be done, can it be done efficiently? (ie so resources don't have to keep
       responding to requests to say it is not idle)

I didn't take time to look at your application in detail.  However,
you might use a co statement, e.g.,

	co (i := 1 to N) Acap[i].try -> got := i; exit  oc

That will broadcast a request to all in Acap, and continue when one of
them replies, recording that index in got.  (You might then use
Acap[got].otherop(...) to invoke otherop in Acap[got].)

   (4) Below is an example (attempted) implementation and its output.
   If you have the patience ...
   Does anyone have any clues why it fails?

I see one big problem, but I haven't tried running a corrected version.

   resource main
      import compute
      import ab
   body main()
      var  n			:int
      var	ab_cap[1:n]		:cap ab

ab_cap is allocated with the current value of n, which at this point
is garbage.  (It isn't initialized until below in initial.)

      initial
	 var s			:string(100)

	 n:=numargs()
	 write("main: AB will be on: ")
	 fa i:=1 to n ->
	    getarg(i,s)
	    write(s)
	 af
	 flush(stdout)
      end

Two possible fixes:

(1) change declaration of n to (and delete assignment to n in initial)

	var n :int := numargs()

(2) move declaration of ab_cap to process make (i.e., after initial
has executed and set n).

I didn't try running your program with these fixes, so it might have
other problems too.

From djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU  Thu Oct 19 10:11:57 1989
Received: from ucbvax.Berkeley.EDU by megaron (5.59-1.7/15) via SMTP
	id AA19777; Thu, 19 Oct 89 10:11:57 MST
Received: from awesome.Berkeley.EDU by ucbvax.Berkeley.EDU (5.61/1.38)
	id AA07152; Thu, 19 Oct 89 10:11:34 -0700
Received: from localhost by awesome.berkeley.edu (4.0/SMI-4.0)
	id AA21372; Wed, 18 Oct 89 15:18:22 PDT
Message-Id: <8910182218.AA21372@awesome.berkeley.edu>
To: info-sr@arizona.edu
Subject: trouble passing "capabilities" 
Date: Wed, 18 Oct 89 15:18:21 -0700
From: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU


I am having trouble passing "capabilities" around between processes
in different resources.  The following example is a stripped version
of a larger one in which several active resources query a "compute server"
and are returned the "capability" of an idle resource (machine), to which
some work can be sent.


----- synopsis of what is in "simple.sr" at end of this message -----

MAIN creates B
MAIN creates A (telling it who B is)
MAIN informs B who A is

B pings A to check it is there

A asks B for some "other" A which it can ping

B replies to A

A tries to ping and fails.

The value returned to A seems invalid, despite the fact that B just used it
in the same way A is trying to.


----- output -----

% a.out awesome totally

make: b created
make: a created
a_caller: waiting for a reply to request
make: informing b
a: I got pinged
b_server: received request
a_caller: about to ping machine returned by b
b_server: replied
[vm 3] RTS abort: attempting to invoke null operation

(does "vm 3" give a clue?  As far as I can tell, 0, 1, 2 are active, not 3.)
%

----- simple.sr -----

resource a_stub
   op a_reply(a_stub_cap:cap a_stub)
   op a_ping()
end a_stub

resource b
   import a_stub
   op b_request(a_stub_cap:cap a_stub)
   op b_inform(a_stub_cap:cap a_stub)
body b()
   process b_server
      var a_stub_cap		:cap a_stub
      var remote		:cap a_stub

      receive b_inform(a_stub_cap)
      call a_stub_cap.a_ping()
      receive b_request(remote)
      write("b_server: received request") flush(stdout) nap(1000)
      send remote.a_reply(a_stub_cap)
      write("b_server: replied") flush(stdout) nap(1000)
   end b_server 
end b


resource a
   extend a_stub
   import b
body a(b_cap:cap b)

   proc a_ping()
      write("a: I got pinged") flush(stdout) nap(1000)
   end a_ping

   process a_caller
      var other			:cap a

      send b_cap.b_request(myresource())
      write("a_caller: waiting for a reply to request") flush(stdout) nap(1000)
      receive a_reply(other)
      write("a_caller: about to ping machine returned by b") flush(stdout) nap(1000)
      call other.a_ping()
      write("a_caller: other A appears to be alive") flush(stdout)
   end a_caller
end a


resource main
   import a
   import b
body main()
   initial
      if (numargs() != 2) ->
	 stop
      fi
   end

   process make
      var hostname		:string(100)
      var a_cap			:cap a
      var b_cap			:cap b
      var remote		:cap vm

      getarg(1,hostname)
      locate(1,hostname)
      remote:=create vm() on 1
      if (remote = null) ->
	 write("make: can't create vm on ",hostname) flush(stdout)
	 stop
      fi
      b_cap:=create b() on remote
      if (b_cap = null) ->
	 write("make: can't create B on ",hostname) flush(stdout)
	 stop
      fi
      write("make: b created") flush(stdout) nap(1000)

      getarg(2,hostname)
      locate(2,hostname)
      remote:=create vm() on 2
      if (remote = null) ->
	 write("make: can't create vm on ",hostname) flush(stdout)
	 stop
      fi
      a_cap:=create a(b_cap) on remote
      if (a_cap = null) ->
	 write("make: can't create A on ",hostname) flush(stdout)
	 stop
      fi
      write("make: a created") flush(stdout) nap(1000)

      write("make: informing b") flush(stdout) nap(1000)
      send b_cap.b_inform(a_cap)
   end make
end main


From olsson@ivy.ucdavis.edu  Fri Oct 20 11:27:55 1989
Received: from clover.ucdavis.edu by megaron (5.59-1.7/15) via SMTP
	id AA10089; Fri, 20 Oct 89 11:27:55 MST
Received: from ivy.ucdavis.edu by clover.ucdavis.edu (5.59/UCD.EECS.1.11)
	id AA11898; Fri, 20 Oct 89 11:30:26 PDT
Received: by ivy.ucdavis.edu (3.2/3.14)
	id AA05185; Fri, 20 Oct 89 11:26:20 PDT
Date: Fri, 20 Oct 89 11:26:20 PDT
From: olsson@ivy.ucdavis.edu (Ron Olsson)
Message-Id: <8910201826.AA05185@ivy.ucdavis.edu>
To: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU
Cc: info-sr@arizona.edu
In-Reply-To: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU's message of Wed, 18 Oct 89 15:18:21 -0700 <8910182218.AA21372@awesome.berkeley.edu>
Subject: trouble passing "capabilities" 

   Date: Wed, 18 Oct 89 15:18:21 -0700
   From: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU

   I am having trouble passing "capabilities" around between processes
   ...

You've discovered a new bug, sorry to say.  It seems to be caused by
extending a resource that contains a capability for itself.  In your
program that happens

   resource a_stub
      op a_reply(a_stub_cap:cap a_stub)
      op a_ping()
   end a_stub
   ...
   resource a
      extend a_stub
      import b
   body a(b_cap:cap b)
      process a_caller
	 var other			:cap a
	 send b_cap.b_request(myresource())
	 write("a_caller: waiting for a reply to request") ...
	 receive a_reply(other)
	 write("a_caller: about to ping machine returned by b") ...
	 call other.a_ping()
	 write("a_caller: other A appears to be alive") flush(stdout)
      end a_caller
   end a

The exact problem is that we generate bad code for `receive
a_reply(other)'; it doesn't set other's value correctly.  In
particular, we don't copy into other, so by chance other's value is
null and the program dies on the call.

The workaround is to not use the extend.  Replace extend with the
equivalent definitions (and change caps for the extended resource to
caps for the current one).  E.g., change your program to the following.

resource a_stub
   op a_reply(a_stub_cap:cap a_stub)
   op a_ping()
end a_stub

resource b
   import a_stub
   op b_request(a_stub_cap:cap a_stub)
   op b_inform(a_stub_cap:cap a_stub)
body b()
   process b_server
      var a_stub_cap		:cap a_stub
      var remote		:cap a_stub

      receive b_inform(a_stub_cap)
      call a_stub_cap.a_ping()
      receive b_request(remote)
      write("b_server: received request") flush(stdout) nap(1000)
      send remote.a_reply(a_stub_cap)
      write("b_server: replied") flush(stdout) nap(1000)
   end b_server 
end b


resource a
#   extend a_stub
   op a_reply(a_stub_cap:cap a)
   op a_ping()
   import b
body a(b_cap:cap b)
   proc a_ping()
      write("a: I got pinged") flush(stdout) nap(1000)
   end a_ping
   process a_caller
      var other	:cap a
      send b_cap.b_request(myresource())
      write("a_caller: waiting for a reply to request") flush(stdout) nap(1000)
      receive a_reply(other)
#
# bogus generated code uses memcpy(_,_,0) to copy into other for receive.
#
      write("a_caller: about to ping machine returned by b") flush(stdout) nap(1000)
if other = noop -> write("other is noop")
[] other = null -> write("other is null")
[] else -> write("other is ok")
fi
      call other.a_ping()
      write("a_caller: other A appears to be alive") flush(stdout)
   end a_caller
end a


resource main
   import a
   import b
body main()
   process make
      var a_cap	:cap a
      var b_cap	:cap b
      b_cap:=create b()
      write("make: b created") flush(stdout) nap(1000)
      a_cap:=create a(b_cap)
      write("make: a created") flush(stdout) nap(1000)
      send b_cap.b_inform(a_cap)
      write("make: b informed") flush(stdout) nap(1000)
   end make
end main


From gmt  Thu Oct 26 17:43:29 1989
Date: Thu, 26 Oct 89 17:43:29 MST
From: "Gregg Townsend" <gmt>
Message-Id: <8910270043.AA13081@megaron.arizona.edu>
Received: by megaron.arizona.edu (5.59-1.7/15)
	id AA13081; Thu, 26 Oct 89 17:43:29 MST
To: info-sr
Subject: New Context Switch Code for Sun-4 Systems

Several ill-defined runtime problems have been reported when running SR
on the SPARC (Sun4) architecture.  The context switching code (rts/sparc.s)
is believed to be responsible.

Below is an alternate implementation of context switching for Sun4 systems.
This code uses the Sun lightweight process library and should be used in
place of the current assembly language code.

Use of this code requires three minor changes in the SR source file hierarchy:

    1.	Install the code below in a new file "rts/sunlwp.c".

    2.  Edit "rts/Makefile" and change the first mention of "machine.o"
	(in the definition of OBJ) to "sunlwp.o".

    3.  Edit "srl/gen.c" and insert a line
		*argp++ = "-llwp";
	five lines before the end of file, immediately before the line
		*argp++ = 0;

After making those changes, just build or rebuild SR in the usual manner
as described in the installation documentation.

This code will also run on Sun3 systems, but we do not recommend installing
it there because it is slower than the existing code.

    Gregg Townsend / Computer Science Dept / Univ of Arizona / Tucson, AZ 85721
    +1 602 621 4325     gmt@cs.arizona.edu     110 57 16 W / 32 13 45 N / +761m


---------------------- cut here, save as rts/sunlwp.c  ----------------------



/*  sunlwp.c - SR context switching routines using Sun lightweight processes  */



#include <stdio.h>
#include <lwp/lwp.h>
#include <lwp/stackdep.h>

#define CON_MAGIC 2079447381	/* an arbitrary (and unlikely) magic number */

#define GOOD_PRI 2		/* priority for real threads */
#define KILL_PRI 1		/* priority for the killer thread */
#define KILL_STK 512		/* stack size for killer thread */

#define lwcall(text,retval) if ((retval) != 0) lwerror (text);



typedef struct {		/* context header: */
    thread_t tid;		/*   thread id for lwp library */
    int magic;			/*   magic number for integrity checking */
} con_hdr, *con_ptr;


static con_ptr curr;		/* current context pointer */

static void startup(), initkiller(), killer(), lwerror();




/*************************  EXTERNAL ROUTINES  *************************/



/*  sr_build_context - create a new SR process context.
 *
 *  We put a context header (see above) at the beginning of the space
 *  and use the rest for the lwp stack.
 */

void
sr_build_context (entry, context, size, arg1, arg2, arg3, arg4)
void (*entry)();
char *context;
int size;
int arg1, arg2, arg3, arg4;
{
    static int first = 1;		/* first-call flag */
    con_ptr cp = (con_ptr) context;	/* context pointer */

    /* initialize a few things the first time we're called */
    if (first) {
	lwcall("set maxpri", pod_setmaxpri (GOOD_PRI));	/* set priority range */
	initkiller ();					/* init killer thread */
	first = 0;					/* note init done */
    }

    cp = (con_ptr) context;		/* get context block pointer */
    if (cp->magic == CON_MAGIC)		/* if reusing stack, kill previous */
	lwcall("destroy lwp", lwp_destroy (cp->tid));
    lwcall("create lwp",		/* create new thread */
	lwp_create (&cp->tid, startup, GOOD_PRI, LWPSUSPEND + LWPNOLASTRITES,
	    context + size, 5, entry, arg1, arg2, arg3, arg4));
    cp->magic = CON_MAGIC;		/* set magic word for stack checking */
}



/*  sr_chg_context() - switch to a different SR process  */

void
sr_chg_context (context)
char *context;
{
    con_ptr cp = (con_ptr) context;

    if (curr != 0 && curr->magic != CON_MAGIC)	/* check curr stk looks good */
	sr_stk_overflow ();
    if (cp == curr)			/* nothing to do on change to self */
	return;
    if (cp->magic != CON_MAGIC)		/* check that new stack looks good */
	sr_stk_corrupted ();
    lwcall("resume", lwp_resume (cp->tid));	/* unsuspend new process */
    curr = cp;					/* remember current pointer */
    lwcall("suspend", lwp_suspend (SELF));	/* suspend self, yield to new */
}



/*  sr_check_stk() - check for stack overflow.
 *
 *  We check to see if the magic word has been overwritten.
 *  This isn't foolproof, but it will catch some errors.
 */

void
sr_check_stk ()
{
    if (curr->magic != CON_MAGIC)
	sr_stk_overflow ();
}




/*************************  INTERNAL ROUTINES  *************************/



/*  startup() - call the entry point of a newly created SR process.
 *
 *  If it ever returns, signal stack underflow.
 */

static void
startup (entry, arg1, arg2, arg3, arg4)
void (*entry)();
int arg1, arg2, arg3, arg4;
{
    (*entry) (arg1, arg2, arg3, arg4);
    sr_stk_underflow ();
}



/*  initkiller() - set up a thread to catch exit calls.
 *
 *  The problem is that exit() is caught by the lwp library and doesn't
 *  really exit; so, we create a low-priority killer thread that will do so.
 *  If the executing SR process exits, the killer thread will get control
 *  because all other SR processes are still suspended.
 */

static void
initkiller ()
{
    thread_t tid;
    static char killstk[KILL_STK];

    lwcall("create killer",
	lwp_create (&tid, killer, KILL_PRI, LWPNOLASTRITES,
	    killstk + KILL_STK, 0));
}



/*  killer() - the actual code executed by the killer thread.  */

static void
killer ()
{
    pod_exit (pod_getexit ());
}



/*  lwerror(text) - abort with message from lightweight process error  */

static void
lwerror (text)
char *text;
{
    fprintf (stderr, "lwp error: ");
    lwp_perror (text);
    pod_exit (1);
}

From bina@acsu.buffalo.edu  Sun Nov  5 13:07:08 1989
Received: from autarch.acsu.buffalo.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA01515; Sun, 5 Nov 89 13:07:08 MST
Received: by autarch.acsu.buffalo.edu (4.0/1.35)
	id AA12226; Sun, 5 Nov 89 15:07:06 EST
Date: Sun, 5 Nov 89 15:07:06 EST
From: bina@acsu.buffalo.edu (Bina Ramamurthy)
Message-Id: <8911052007.AA12226@autarch.acsu.buffalo.edu>
To: info-sr@cs.arizona.edu
Subject: want info


I am an instructor at SUNY Buffalo. I am interested in knowing
whether you are using SR in any of your regular undergraduate
courses like operating systems, computer architecture.

Could you also give me list of all the courses using SR and
the hardware set up (what king machines etc.) you are using
it on?

bina

bina@gort.cc.buffalo.edu

From greg  Sun Nov  5 19:11:10 1989
Received: from paloverde.cs.arizona.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA13131; Sun, 5 Nov 89 19:11:10 MST
Date: Sun, 5 Nov 89 19:10:59 MST
From: "Greg Andrews" <greg>
Message-Id: <8911060210.AA08615@paloverde>
Received: by paloverde; Sun, 5 Nov 89 19:10:59 MST
In-Reply-To: <8911052007.AA12226@autarch.acsu.buffalo.edu>
To: bina@acsu.buffalo.edu
Subject: Re:  want info
Cc: info-sr

We are not yet using SR in any undergraduate courses.
(We just began an undergraduate major this year so do
not have as many undergraduate courses as we eventually
will.)

SR is used for all programming projects in our
course on concurrent programming.  It is also used -- typically
at student discretion -- in graduate courses on operating
systems, networks, and parallel algorithms.  It has also been
used in a course on logic programming (two students used SR
to implement an interpreter for a variant of concurrent Prolog).
By student discretion I mean that use of SR is not required;
instead some students who already know it choose to do their
course projects in SR.

For your information, Ron Olsson and I are writing a book
"Concurrent Programming in SR" to be published in 1991 by
Benjamin/Cummings.  If you are interested in using SR for
classroom projects, this should make it a *lot* easier on
you and your students.  Also, we will have a second (much
improved naturally) version of SR out in a year -- and the
book will describe that version.

-- Greg Andrews

From bina@cs.Buffalo.EDU  Mon Nov  6 08:02:16 1989
Received: from gort.cs.Buffalo.EDU by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA08071; Mon, 6 Nov 89 08:02:16 MST
Received: by gort.cs.Buffalo.EDU (5.61/1.01)
	id AA19585; Mon, 6 Nov 89 10:02:17 -0500
Date: Mon, 6 Nov 89 10:02:17 -0500
From: bina@cs.Buffalo.EDU (Bina Ramamurthy)
Message-Id: <8911061502.AA19585@gort.cs.Buffalo.EDU>
To: bina@acsu.buffalo.edu, greg@cs.arizona.edu
Subject: Re:  want info
Cc: info-sr@cs.arizona.edu

Thanks. Let me try the version of SR we have and then
write to you if I have any questions.

bina

From djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU  Sat Nov 18 01:04:00 1989
Received: from ucbvax.Berkeley.EDU by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA12117; Sat, 18 Nov 89 01:04:00 MST
Received: from awesome.Berkeley.EDU by ucbvax.Berkeley.EDU (5.61/1.39)
	id AA17598; Sat, 18 Nov 89 00:03:19 -0800
Received: from localhost by awesome.berkeley.edu (4.0/SMI-4.0)
	id AA09410; Sat, 18 Nov 89 00:05:23 PST
Message-Id: <8911180805.AA09410@awesome.berkeley.edu>
To: info-sr@arizona.edu
Subject: string(*) vs string(100)
Date: Sat, 18 Nov 89 00:05:22 -0800
From: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU

What is the difference between :
	op ping(from:string(*); to:string(*))
and
	op ping(from:string(100); res to:string(100))


when they will be implemented as

	var myhost:string(100)
	initial
	   gethostname(myhost,maxlength(myhost))
	end initial
	proc ping(from,to)
	   write("pinged by",from)
	   to:=myhost
	end ping


	...
	var other_host:string(100)
	call other_machine.ping(myhost,other_host)
	write(other_host,"is alive")

David Jones
djones@awesome.berkeley.edu

From olsson@ivy.ucdavis.edu  Sat Nov 18 02:17:02 1989
Received: from clover.ucdavis.edu by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA16340; Sat, 18 Nov 89 02:17:02 MST
Received: from ivy.ucdavis.edu by clover.ucdavis.edu (5.59/UCD.EECS.1.11)
	id AA03245; Sat, 18 Nov 89 01:18:32 PST
Received: by ivy.ucdavis.edu (3.2/3.14)
	id AA27610; Sat, 18 Nov 89 01:16:47 PST
Date: Sat, 18 Nov 89 01:16:47 PST
From: olsson@ivy.ucdavis.edu (Ron Olsson)
Message-Id: <8911180916.AA27610@ivy.ucdavis.edu>
To: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU
Cc: info-sr@cs.arizona.edu
In-Reply-To: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU's message of Sat, 18 Nov 89 00:05:22 -0800 <8911180805.AA09410@awesome.berkeley.edu>
Subject: string(*) vs string(100)

   Date: Sat, 18 Nov 89 00:05:22 -0800
   From: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU

   What is the difference between :
	   op ping(from:string(*); to:string(*))
   and
	   op ping(from:string(100); res to:string(100))
   ...

The effect should be the same in your example ...  provided that
ping's 2nd parameter in the first declaration is made a res parameter
too; otherwise, it won't get copied back.  (And the name of ping's 2nd
parameter is changed so it isn't a reserved word.)

(I'm not sure I completely understood your question.  If not, let me know.)

From djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU  Sat Nov 18 03:10:42 1989
Received: from ucbvax.Berkeley.EDU by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA20136; Sat, 18 Nov 89 03:10:42 MST
Received: from awesome.Berkeley.EDU by ucbvax.Berkeley.EDU (5.61/1.39)
	id AA22727; Sat, 18 Nov 89 02:10:00 -0800
Received: from localhost by awesome.berkeley.edu (4.0/SMI-4.0)
	id AA10157; Sat, 18 Nov 89 02:12:03 PST
Message-Id: <8911181012.AA10157@awesome.berkeley.edu>
To: info-sr@arizona.edu
Subject: possible bug in SR compiler involving ENUM
Date: Sat, 18 Nov 89 02:12:01 -0800
From: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU


Included below is "bug.sr".  It is trimmed down from a much larger
application I was working on, and so makes little sense on its own.
On our setup, this causes a segmentation fault when you try:
% sr -c bug.sr

A little poking in the compiler seems to suggest that it is
processing the line:
	send o_cap.hello(mycap,x)

At this point, is checking (I think) that "mycap" which is "cap a" is
compatible with "cap a_stub" by checking their structural equivalence.

It tries to see if the two "e_type"s of "a" and "a_stub" are the same
and ends up charging off the list, since it expects it to be NULL terminated,
but it is not.  It does not check the "s_size", which seems to record
the number of enumeration literals in the type.  The s_size *does* seem
to be consulted in decl.c.

The relevant code is in sr/sr/sigcmp.c, around lines 70-80


----------------- bug.sr ----------------

resource a_stub
   type e_type = enum (alpha, beta, gamma)
   op function()
end a_stub


resource other
   import a_stub

   op hello(a_cap:cap a_stub; x:e_type)
body other()

   process listener
      var a_cap	:cap a_stub
      var y:e_type
      receive hello(a_cap,y)
   end listener

end other


resource a
   type e_type = enum (alpha, beta, gamma)
   op function()

   import other
body a(o_cap:cap other)
   var mycap	:cap a

   initial
      mycap:=myresource()
   end initial

   proc function()
   end function

   process server
      var x:e_type
      x:=beta
      send o_cap.hello(mycap,x)
   end server
end a


resource main
body main()
end main

From djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU  Sat Nov 18 05:03:05 1989
Received: from ucbvax.Berkeley.EDU by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA25581; Sat, 18 Nov 89 05:03:05 MST
Received: from awesome.Berkeley.EDU by ucbvax.Berkeley.EDU (5.61/1.39)
	id AA28473; Sat, 18 Nov 89 04:02:24 -0800
Received: from localhost by awesome.berkeley.edu (4.0/SMI-4.0)
	id AA11281; Sat, 18 Nov 89 04:04:28 PST
Message-Id: <8911181204.AA11281@awesome.berkeley.edu>
To: info-sr@arizona.edu
Subject: probable SR runtime bug, memory not freed
Date: Sat, 18 Nov 89 04:04:22 -0800
From: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU


For certain SR programs, I have noticed their SIZE continually increases
during runtime and if left long enough, there is a "[vm N] out of memory" error.
Perhaps buffers (for send/receive to remote machines?) are being
allocated, but never freed.

Has anyone else noticed this?

Dave
djones@awesome.berkeley.edu

From djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU  Mon Nov 20 02:25:42 1989
Received: from ucbvax.Berkeley.EDU by megaron.arizona.edu (5.59-1.7/15) via SMTP
	id AA07942; Mon, 20 Nov 89 02:25:42 MST
Received: from awesome.Berkeley.EDU by ucbvax.Berkeley.EDU (5.61/1.39)
	id AA15573; Mon, 20 Nov 89 01:24:57 -0800
Received: from localhost by awesome.berkeley.edu (4.0/SMI-4.0)
	id AA16511; Mon, 20 Nov 89 01:27:05 PST
Message-Id: <8911200927.AA16511@awesome.berkeley.edu>
To: info-sr@arizona.edu
Subject: re: memory allocation bug at run time?
Date: Mon, 20 Nov 89 01:27:02 -0800
From: djones%awesome.Berkeley.EDU@ucbvax.Berkeley.EDU

The following example is a simple case of two processes (on different machines)
sending messages to each other.  Using "ps", or "top", one can watch the
process size slowly, but continuously, rising ... until we get an
"out of memeory" error.

I tried to check alloc's and free's (with setenv SRXDEBUG FFFFF), but
I didn't learn anything.

awesome% srm
awesome% make
awesome% a.out totally 

----------------- membug.sr ------------------------

/* Memory allocation bug exerciser */

resource main_stub
   op done()
end main_stub

resource ab
   op ab_work()
   import main_stub
body ab(m:cap main_stub)
   process ab_server
      do (true) ->
         receive ab_work()
	 send m.done()
      od
   end ab_server
end ab


resource main
   op done()
   import ab
body main()
   var  n			:int

   initial
      n:=numargs()
      if (n != 1) ->
	 write("give exatcly one host name")
	 flush(stdout)
	 stop
      fi
   end

   process make
      var s			:string(100)
      var ab_cap		:cap ab
      var remote		:cap vm

      getarg(1,s)
      locate(1,s)
      remote:=create vm() on 1
      ab_cap:=create ab(myresource()) on remote
      do (true) ->
         send ab_cap.ab_work()
	 receive done()
      od
   end make
end main


From gmt  Mon Nov 20 11:02:36 1989
Date: Mon, 20 Nov 89 11:02:36 MST
From: "Gregg Townsend" <gmt>
Message-Id: <8911201802.AA08638@megaron.arizona.edu>
Received: by megaron.arizona.edu (5.59-1.7/15)
	id AA08638; Mon, 20 Nov 89 11:02:36 MST
To: djones@awesome.berkeley.edu
Subject: bug reports
Cc: info-sr

Thank you for the bug reports.

We're aware of several problems in both of those areas: signature checking
in the compiler and memory allocation at runtime.  We hope to fix those
in the next version of the SR system, and will retain your test programs
to help verify this.

In general, bug reports should be addressed to sr-project@cs.arizona.edu,
unless there's a reason for the whole info-sr list to see them.

    Gregg Townsend / Computer Science Dept / Univ of Arizona / Tucson, AZ 85721
    +1 602 621 4325     gmt@cs.arizona.edu     110 57 16 W / 32 13 45 N / +758m


