(Latest Revision: 10/18/00)
10/18/00: Put an "else" in the wait function so processes that block won't attempt to release the lock when they are awakened.

EXAMPLE FILE: semsFromTSL




//////////////////////////////////////////////////
HOW TO IMPLEMENT SEMAPHORES WITH A TSL INSTRUCTION
PLUS A "NICE" BLOCKING SYSTEM CALL.
//////////////////////////////////////////////////

 
      (* some variables shared by all n processes *)
var waiting : array [0..n-1] of boolean ;
    lock : boolean ;
    semaphore : record
                  count : integer ;
		  queue : queueType 
                end ;


(* #################################################### *)
procedure TSL_Enter(me : process ) ;
var key : boolean ;
begin
  waiting[me] := true ;
  key := true ;
  while (waiting[me] and key) do key := Test-and-Set(lock) ;
  waiting[me] := false ;
end ;

(* #################################################### *)
procedure TSL_Exit(me : process ) ;
var j : 0 .. n-1 ;
begin
  j := me + 1 mod n ;
  while (j<>me) and (not waiting[j]) do j := j+1 mod n ;
  if   j=me                    (* if no one is waiting to get in. *)
  then lock := false           (* just un-lock the semaphore data *)
  else waiting[j] := false     (* otherwise, leave lock=true and let
                                  the next-in-line go in. *)
end ;

(* #################################################### *)
procedure InitSem (var sem : semaphore; val : integer ) ;
begin
  sem.count := val ;
  CreateQ(queue) ;
end ;

(* #################################################### *)
procedure Wait (var sem : semaphore ; me : process) ;
begin

  TSL_Enter(me) ;

  sem.count := sem.count - 1 ;
    (*
       Here we make a system call "block(me,lock)" that is
       assumed to put the process to sleep and *then* release
       the lock, by executing TSL_EXIT in behalf of the blocked
       process .  If wakeups are not "saved" by this operating
       system, the lock must not be released until after the
       process is blocked.  Why?
    *)
  if   sem.count < 0
  then block(me,lock) ;
  else TSL_Exit(me) ;
  
end ;


(* #################################################### *)
procedure Signal (var sem : semaphore ; me : process) ;
var other : ^process ;
begin

  TSL_Enter(me) ;

  sem.count := sem.count + 1 ;
  if    sem.count <= 0
  then  begin
	  Deq(sem.queue, other) ;
          wakeup(other) 
	end ;

  TSL_Exit(me) ;
  
end ;