(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 ;