CSc 520 - Principles of Programming Languages
32 : Control Structures -- Coroutines

Christian Collberg

Department of Computer Science

University of Arizona

1 Coroutines

2 Coroutines vs. threads

3 Example

4 Example...

var us, cfs: coroutine; 

coroutine update_screen() {
   ...
   detach
   loop {
      ... transfer(cfs) ...
   }
}

coroutine check_file_system() {  ... }

main () { ... }

5 Coroutines...

coroutine check_file_system() {
   ...
   detach
   for all files do {
      ... transfer(cfs) 
      ... transfer(cfs) 
         ... transfer(cfs) ...
   }
}

main () {
   us := new update_screen();
   cfs := new check_file_system();
   transfer(us);
}


Coroutines in Modula-2


6 Coroutines in Modula-2

PROCEDURE NEWPROCESS(
   proc: PROC;                (* The procedure     *)
   addr: ADDRESS;             (* The stack         *)
   size: CARDINAL;            (* The stack size    *)
   VAR new: ADDRESS);         (* The coroutine     *)
PROCEDURE TRANSFER(
   VAR source: ADDRESS;       (* Current coroutine *)
   VAR destination: ADDRESS); (* New coroutine     *)

7 Coroutines in Modula-2...

VAR crparams: CoroutineParameters;
    source: ADDRESS; (* current coroutine is called by this *)
    newcr: ADDRESS; (* coroutine just created by NEWPROCESS *)

PROCEDURE Coroutine;
   VAR myparams: CoroutineParameters;
BEGIN
   myparams := crparams;
   TRANSFER(newcr, source); (* return to calling coroutine *)
   (* rest of coroutine *)
END Coroutine;

PROCEDURE Setup(params: CoroutineParameters; proc: PROC);
BEGIN
   NEWPROCESS(proc, addr, size, newcr);
   crparams := params; TRANSFER(source, newcr);
END Setup;


Coroutines in Ruby


8 Coroutines in Ruby

class Coroutine
   # Creates a coroutine. The associated block 
   # does not run yet.
   def initialize(&block)

   # Starts the block. It's an error to call 
   # this method on a coroutine that has 
   # already been started.
   def start

   # Switches context to another coroutine. You 
   # need to call this method on the current coroutine.
  def switch(coroutine)

9 Coroutines in Ruby

   ...

   # Returns true if the associated block is  
   # started and has not yet finished
   def running?

   # Returns true if the associated block is 
   # finished
  def finished?
end

10 Example

$c1 = Coroutine::new do
  for i in 'a'..'z' do
    printf "%s ", i
    $c1.switch($c2)
  end
end

$c2 = Coroutine::new do
  for i in 1..26 do
    printf "%i ", i
    $c2.switch($c1)
  end
end

11 Example...

Running the example:

$c1.start
printf "\n"
yields the result
a 1 b 2 c 3 d 4 e 5 f 6 g 7 h 8 i 9 j 10 
k 11 l 12 m 13 n 14 o 15 p 16 q 17 r 18 
s 19 t 20 u 21 v 22 w 23 x 24 y 25 z 26

12 Iterators using coroutines

$result = 0
def iterate(arr,other)
   c = Coroutine::new do
      i = 0
      while i < arr.length
         $result = arr[i]
         i += 1
         c.switch(other)
      end
   end
   return c
end

13 Iterators using coroutines...

main = Coroutine::new do
   a = [1,2,3]
   iter = iterate(a,main)
   while not iter.finished?
      main.switch(iter)
      printf "%i ", $result
   end
   printf "\n"
end


Implementing coroutines


14 Implementing coroutines

15 Implementing coroutines...

16 Implementing coroutines...

current_coroutine := ...
PC := ...
SP := 

transfer(C) {
   push R1,R2,RA
   *current_coroutine := SP
   current_coroutine := C
   SP := *C
   pop R1,R2,RA
   return
}

17 Step 1: Coroutine C2 is running

transfer1

18 Step 2: Control is transferred to C2

transfer2

19 Readings and References



Christian Collberg 2008-04-09