------------------------->  GNU Sather - sourcefile  <-------------------------
-- Copyright (C) 199x by International Computer Science Institute            --
-- This file is part of the GNU Sather library. It is free software; you may --
-- redistribute  and/or modify it under the terms of the GNU Library General --
-- Public  License (LGPL)  as published  by the  Free  Software  Foundation; --
-- either version 2 of the license, or (at your option) any later version.   --
-- This  library  is distributed  in the  hope that it will  be  useful, but --
-- WITHOUT ANY WARRANTY without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See Doc/LGPL for more details.       --
-- The license text is also available from:  Free Software Foundation, Inc., --
-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA                     --
-------------->  Please email comments to <bug-sather@gnu.org>  <--------------

-- this class behaves like a MUTEX, except that it never calls
-- the lock manager, is not fair and cannot be used together with other
-- locks in a lock statement (you'll get a runtime error if you try anyway)
-- To catch at least some of the errors, it is not un $MUTEX, but rather
-- under $LOCK

class FMUTEX < $LOCK is
   include LOCK_INCLUDE;
  
   private attr locked_by:THREAD_ID;
   private attr locked:INT;
   private attr ilck:LL_LOCK;

   is_locked:BOOL is return locked>0; end;
   
   private init is ilck:=#; end;
   create:SAME is 
      r::=new; 
      r.init;
      return r;
   end;

   fast_lock(tid:THREAD_ID):BOOL is
      if locked_by=tid then
         locked:=locked+1;
	 return true;
      end;
      ilck.lck;
      locked_by:=tid;
      locked:=1;
      return true;
   end;

   -- Trys to lock the MUTEX, return
   -- -1 if it failed and the else part should be executed
   -- 0  if the lock manager should be called
   -- 1  if it was successful
   fast_try(tid:THREAD_ID):INT is
      if locked_by=tid then 
         locked:=locked+1;
	 return 1; 
      end;
      if ilck.try then
         locked_by:=tid;
	 locked:=locked+1;
	 return 1;
      else 
         return -1;
      end;
   end;

   -- only one thread can call unlock  of a MUTEX at any time (anything else
   -- would be a fatal pSather error). fast_unlock returns true
   -- if the lock manager has to be notified about the change
   fast_unlock(tid:THREAD_ID):BOOL pre locked_by=tid is
      locked:=locked-1;
      if locked=0 then locked_by:=THREAD_ID::nil;ilck.unlck; end;
      return false;
   end;

   reservable(tid:THREAD_ID):BOOL is
      raise "FMUTEX cannot be used in a complex lock statement";
   end;

   reserve(tid:THREAD_ID) is
      raise "FMUTEX cannot be used in a complex lock statement";
   end;

   free(tid:THREAD_ID) is
      raise "FMUTEX cannot be used in a complex lock statement";
   end;
end;
   
-- this class behaves like a FMUTEX, except that it uses spinlocks
-- and is intended to be used for small critical regions

class FMUTEX_SPIN < $LOCK is
   include LOCK_INCLUDE;
  
   private attr locked_by:THREAD_ID;
   private attr locked:INT;
   private attr ilck:SPINLOCK;

   is_locked:BOOL is return locked>0; end;
   
   private init is ilck:=#; end;
   create:SAME is 
      r::=new; 
      r.init;
      return r;
   end;

   fast_lock(tid:THREAD_ID):BOOL is
      if locked_by=tid then
         locked:=locked+1;
	 return true;
      end;
      ilck.lck;
      locked_by:=tid;
      locked:=1;
      return true;
   end;

   -- Trys to lock the MUTEX, return
   -- -1 if it failed and the else part should be executed
   -- 0  if the lock manager should be called
   -- 1  if it was successful
   fast_try(tid:THREAD_ID):INT is
      if locked_by=tid then 
         locked:=locked+1;
	 return 1; 
      end;
      if ilck.try then
         locked_by:=tid;
	 locked:=locked+1;
	 return 1;
      else 
         return -1;
      end;
   end;

   -- only one thread can call unlock  of a MUTEX at any time (anything else
   -- would be a fatal pSather error). fast_unlock returns true
   -- if the lock manager has to be notified about the change
   fast_unlock(tid:THREAD_ID):BOOL pre locked_by=tid is
      locked:=locked-1;
      if locked=0 then locked_by:=THREAD_ID::nil;ilck.unlck; end;
      return false;
   end;

   reservable(tid:THREAD_ID):BOOL is
      raise "FMUTEX_SPIN cannot be used in a complex lock statement";
   end;

   reserve(tid:THREAD_ID) is
      raise "FMUTEX_SPIN cannot be used in a complex lock statement";
   end;

   free(tid:THREAD_ID) is
      raise "FMUTEX_SPIN cannot be used in a complex lock statement";
   end;
end;
-- vim:sw=3:nosmartindent
