lib/sync.rb


DEFINITIONS

This source file includes following functions.


   1  #
   2  #   sync.rb - 2 phase lock with counter
   3  #       $Release Version: 1.0$
   4  #       $Revision: 1.4 $
   5  #       $Date: 2001/06/06 14:19:33 $
   6  #       by Keiju ISHITSUKA(keiju@ishitsuka.com)
   7  #
   8  # --
   9  #  Sync_m, Synchronizer_m
  10  #  Usage:
  11  #   obj.extend(Sync_m)
  12  #   or
  13  #   class Foo
  14  #       include Sync_m
  15  #       :
  16  #   end
  17  #
  18  #   Sync_m#sync_mode
  19  #   Sync_m#sync_locked?, locked?
  20  #   Sync_m#sync_shared?, shared?
  21  #   Sync_m#sync_exclusive?, sync_exclusive?
  22  #   Sync_m#sync_try_lock, try_lock
  23  #   Sync_m#sync_lock, lock
  24  #   Sync_m#sync_unlock, unlock
  25  #
  26  #   Sync, Synchronicer:
  27  #       include Sync_m
  28  #   Usage:
  29  #   sync = Sync.new
  30  #
  31  #   Sync#mode
  32  #   Sync#locked?
  33  #   Sync#shared?
  34  #   Sync#exclusive?
  35  #   Sync#try_lock(mode) -- mode = :EX, :SH, :UN
  36  #   Sync#lock(mode)     -- mode = :EX, :SH, :UN
  37  #   Sync#unlock
  38  #   Sync#synchronize(mode) {...}
  39  #   
  40  #
  41  
  42  unless defined? Thread
  43    fail "Thread not available for this ruby interpreter"
  44  end
  45  
  46  module Sync_m
  47    RCS_ID='-$Header: /src/ruby/lib/sync.rb,v 1.4 2001/06/06 14:19:33 keiju Exp $-'
  48    
  49    # lock mode
  50    UN = :UN
  51    SH = :SH
  52    EX = :EX
  53    
  54    # exceptions
  55    class Err < StandardError
  56      def Err.Fail(*opt)
  57        fail self, sprintf(self::Message, *opt)
  58      end
  59      
  60      class UnknownLocker < Err
  61        Message = "Thread(%s) not locked."
  62        def UnknownLocker.Fail(th)
  63          super(th.inspect)
  64        end
  65      end
  66      
  67      class LockModeFailer < Err
  68        Message = "Unknown lock mode(%s)"
  69        def LockModeFailer.Fail(mode)
  70          if mode.id2name
  71            mode = id2name
  72          end
  73          super(mode)
  74        end
  75      end
  76    end
  77    
  78    def Sync_m.define_aliases(cl)
  79      cl.module_eval %q{
  80        alias locked? sync_locked?
  81        alias shared? sync_shared?
  82        alias exclusive? sync_exclusive?
  83        alias lock sync_lock
  84        alias unlock sync_unlock
  85        alias try_lock sync_try_lock
  86        alias synchronize sync_synchronize
  87      }
  88    end
  89    
  90    def Sync_m.append_features(cl)
  91      super
  92      unless cl.instance_of?(Module)
  93        # do nothing for Modules
  94        # make aliases and include the proper module.
  95        define_aliases(cl)
  96      end
  97    end
  98    
  99    def Sync_m.extend_object(obj)
 100      super
 101      obj.sync_extended
 102    end
 103  
 104    def sync_extended
 105      unless (defined? locked? and
 106              defined? shared? and
 107              defined? exclusive? and
 108              defined? lock and
 109              defined? unlock and
 110              defined? try_lock and
 111              defined? synchronize)
 112        Sync_m.define_aliases(class<<self;self;end)
 113      end
 114      sync_initialize
 115    end
 116  
 117    # accessing
 118    def sync_locked?
 119      sync_mode != UN
 120    end
 121    
 122    def sync_shared?
 123      sync_mode == SH
 124    end
 125    
 126    def sync_exclusive?
 127      sync_mode == EX
 128    end
 129    
 130    # locking methods.
 131    def sync_try_lock(mode = EX)
 132      return unlock if sync_mode == UN
 133      
 134      Thread.critical = true
 135      ret = sync_try_lock_sub(sync_mode)
 136      Thread.critical = false
 137      ret
 138    end
 139    
 140    def sync_lock(m = EX)
 141      return unlock if m == UN
 142  
 143      until (Thread.critical = true; sync_try_lock_sub(m))
 144        if sync_sh_locker[Thread.current]
 145          sync_upgrade_waiting.push [Thread.current, sync_sh_locker[Thread.current]]
 146          sync_sh_locker.delete(Thread.current)
 147        else
 148          sync_waiting.push Thread.current
 149        end
 150        Thread.stop
 151      end
 152      Thread.critical = false
 153      self
 154    end
 155    
 156    def sync_unlock(m = EX)
 157      Thread.critical = true
 158      if sync_mode == UN
 159        Thread.critical = false
 160        Err::UnknownLocker.Fail(Thread.current)
 161      end
 162      
 163      m = sync_mode if m == EX and sync_mode == SH
 164      
 165      runnable = false
 166      case m
 167      when UN
 168        Thread.critical = false
 169        Err::UnknownLocker.Fail(Thread.current)
 170        
 171      when EX
 172        if sync_ex_locker == Thread.current
 173          if (self.sync_ex_count = sync_ex_count - 1) == 0
 174            self.sync_ex_locker = nil
 175            if sync_sh_locker.include?(Thread.current)
 176              self.sync_mode = SH
 177            else
 178              self.sync_mode = UN
 179            end
 180            runnable = true
 181          end
 182        else
 183          Err::UnknownLocker.Fail(Thread.current)
 184        end
 185        
 186      when SH
 187        if (count = sync_sh_locker[Thread.current]).nil?
 188          Err::UnknownLocker.Fail(Thread.current)
 189        else
 190          if (sync_sh_locker[Thread.current] = count - 1) == 0 
 191            sync_sh_locker.delete(Thread.current)
 192            if sync_sh_locker.empty? and sync_ex_count == 0
 193              self.sync_mode = UN
 194              runnable = true
 195            end
 196          end
 197        end
 198      end
 199      
 200      if runnable
 201        if sync_upgrade_waiting.size > 0
 202          for k, v in sync_upgrade_waiting
 203            sync_sh_locker[k] = v
 204          end
 205          wait = sync_upgrade_waiting
 206          self.sync_upgrade_waiting = []
 207          Thread.critical = false
 208          
 209          for w, v in wait
 210            w.run
 211          end
 212        else
 213          wait = sync_waiting
 214          self.sync_waiting = []
 215          Thread.critical = false
 216          for w in wait
 217            w.run
 218          end
 219        end
 220      end
 221      
 222      Thread.critical = false
 223      self
 224    end
 225    
 226    def sync_synchronize(mode = EX)
 227      begin
 228        sync_lock(mode)
 229        yield
 230      ensure
 231        sync_unlock
 232      end
 233    end
 234  
 235    attr :sync_mode, true
 236      
 237    attr :sync_waiting, true
 238    attr :sync_upgrade_waiting, true
 239    attr :sync_sh_locker, true
 240    attr :sync_ex_locker, true
 241    attr :sync_ex_count, true
 242      
 243    private
 244  
 245    def sync_initialize
 246      @sync_mode = UN
 247      @sync_waiting = []
 248      @sync_upgrade_waiting = []
 249      @sync_sh_locker = Hash.new
 250      @sync_ex_locker = nil
 251      @sync_ex_count = 0
 252    end
 253  
 254    def initialize(*args)
 255      sync_initialize
 256      super
 257    end
 258      
 259    def sync_try_lock_sub(m)
 260      case m
 261      when SH
 262        case sync_mode
 263        when UN
 264          self.sync_mode = m
 265          sync_sh_locker[Thread.current] = 1
 266          ret = true
 267        when SH
 268          count = 0 unless count = sync_sh_locker[Thread.current]
 269          sync_sh_locker[Thread.current] = count + 1
 270          ret = true
 271        when EX
 272          # in EX mode, lock will upgrade to EX lock
 273          if sync_ex_locker == Thread.current
 274            self.sync_ex_count = sync_ex_count + 1
 275            ret = true
 276          else
 277            ret = false
 278          end
 279        end
 280      when EX
 281        if sync_mode == UN or
 282          sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current) 
 283          self.sync_mode = m
 284          self.sync_ex_locker = Thread.current
 285          self.sync_ex_count = 1
 286          ret = true
 287        elsif sync_mode == EX && sync_ex_locker == Thread.current
 288          self.sync_ex_count = sync_ex_count + 1
 289          ret = true
 290        else
 291          ret = false
 292        end
 293      else
 294        Thread.critical = false
 295        Err::LockModeFailer.Fail mode
 296      end
 297      return ret
 298    end
 299  end
 300  Synchronizer_m = Sync_m
 301  
 302  class Sync
 303    #Sync_m.extend_class self
 304    include Sync_m
 305      
 306    def initialize
 307      super
 308    end
 309      
 310  end
 311  Synchronizer = Sync