# module Sync_m

A module that provides a two-phase lock with a counter.

### Constants

EX
SH
UN

  lock mode

### Attributes

sync_ex_count[RW]
sync_ex_locker[RW]
sync_mode[RW]
sync_sh_locker[RW]
sync_upgrade_waiting[RW]
sync_waiting[RW]

### Public Class Methods

append_features(cl) click to toggle source
Calls superclass method

    # File lib/sync.rb, line 86
    def Sync_m.append_features(cl)
      super
      # do nothing for Modules
      # make aliases for Classes.
      define_aliases(cl) unless cl.instance_of?(Module)
      self
    end

define_aliases(cl) click to toggle source

    # File lib/sync.rb, line 74
    def Sync_m.define_aliases(cl)
      cl.module_eval %q{
        alias locked? sync_locked?
        alias shared? sync_shared?
        alias exclusive? sync_exclusive?
        alias lock sync_lock
        alias unlock sync_unlock
        alias try_lock sync_try_lock
        alias synchronize sync_synchronize
      }
    end

extend_object(obj) click to toggle source
Calls superclass method

    # File lib/sync.rb, line 94
    def Sync_m.extend_object(obj)
      super
      obj.sync_extend
    end

new(*args) click to toggle source
Calls superclass method

    # File lib/sync.rb, line 263
    def initialize(*args)
      super
      sync_initialize
    end

### Public Instance Methods

sync_exclusive?() click to toggle source

    # File lib/sync.rb, line 121
    def sync_exclusive?
      sync_mode == EX
    end

sync_extend() click to toggle source

    # File lib/sync.rb, line 99
    def sync_extend
      unless (defined? locked? and
              defined? shared? and
              defined? exclusive? and
              defined? lock and
              defined? unlock and
              defined? try_lock and
              defined? synchronize)
        Sync_m.define_aliases(singleton_class)
      end
      sync_initialize
    end

sync_inspect() click to toggle source

    # File lib/sync.rb, line 245
    def sync_inspect
      sync_iv = instance_variables.select{|iv| /^@sync_/ =~ iv.id2name}.collect{|iv| iv.id2name + '=' + instance_eval(iv.id2name).inspect}.join(",")
      print "<#{self.class}.extend Sync_m: #{inspect}, <Sync_m: #{sync_iv}>"
    end

sync_lock(m = EX) click to toggle source

    # File lib/sync.rb, line 133
    def sync_lock(m = EX)
      return unlock if m == UN
      Thread.handle_interrupt(StandardError => :on_blocking) do
        while true
          @sync_mutex.synchronize do
            begin
              if sync_try_lock_sub(m)
                return self
              else
                if sync_sh_locker[Thread.current]
                  sync_upgrade_waiting.push [Thread.current, sync_sh_locker[Thread.current]]
                  sync_sh_locker.delete(Thread.current)
                else
                  unless sync_waiting.include?(Thread.current) || sync_upgrade_waiting.reverse_each.any?{|w| w.first == Thread.current }
                    sync_waiting.push Thread.current
                  end
                end
                @sync_mutex.sleep
              end
            ensure
              sync_waiting.delete(Thread.current)
            end
          end
        end
      end
      self
    end

sync_locked?() click to toggle source

accessing

    # File lib/sync.rb, line 113
    def sync_locked?
      sync_mode != UN
    end

sync_shared?() click to toggle source

    # File lib/sync.rb, line 117
    def sync_shared?
      sync_mode == SH
    end

sync_synchronize(mode = EX) { || ... } click to toggle source

    # File lib/sync.rb, line 226
    def sync_synchronize(mode = EX)
      Thread.handle_interrupt(StandardError => :on_blocking) do
        sync_lock(mode)
        begin
          yield
        ensure
          sync_unlock
        end
      end
    end

sync_try_lock(mode = EX) click to toggle source

locking methods.

    # File lib/sync.rb, line 126
    def sync_try_lock(mode = EX)
      return unlock if mode == UN
      @sync_mutex.synchronize do
        sync_try_lock_sub(mode)
      end
    end

sync_unlock(m = EX) click to toggle source

    # File lib/sync.rb, line 161
    def sync_unlock(m = EX)
      wakeup_threads = []
      @sync_mutex.synchronize do
        if sync_mode == UN
          Err::UnknownLocker.Fail(Thread.current)
        end

        m = sync_mode if m == EX and sync_mode == SH

        runnable = false
        case m
        when UN
          Err::UnknownLocker.Fail(Thread.current)

        when EX
          if sync_ex_locker == Thread.current
            if (self.sync_ex_count = sync_ex_count - 1) == 0
              self.sync_ex_locker = nil
              if sync_sh_locker.include?(Thread.current)
                self.sync_mode = SH
              else
                self.sync_mode = UN
              end
              runnable = true
            end
          else
            Err::UnknownLocker.Fail(Thread.current)
          end

        when SH
          if (count = sync_sh_locker[Thread.current]).nil?
            Err::UnknownLocker.Fail(Thread.current)
          else
            if (sync_sh_locker[Thread.current] = count - 1) == 0
              sync_sh_locker.delete(Thread.current)
              if sync_sh_locker.empty? and sync_ex_count == 0
                self.sync_mode = UN
                runnable = true
              end
            end
          end
        end

        if runnable
          if sync_upgrade_waiting.size > 0
            th, count = sync_upgrade_waiting.shift
            sync_sh_locker[th] = count
            th.wakeup
            wakeup_threads.push th
          else
            wait = sync_waiting
            self.sync_waiting = []
            for th in wait
              th.wakeup
              wakeup_threads.push th
            end
          end
        end
      end
      for th in wakeup_threads
        th.run
      end
      self
    end

### Private Instance Methods

sync_initialize() click to toggle source

    # File lib/sync.rb, line 252
    def sync_initialize
      @sync_mode = UN
      @sync_waiting = []
      @sync_upgrade_waiting = []
      @sync_sh_locker = Hash.new
      @sync_ex_locker = nil
      @sync_ex_count = 0

      @sync_mutex = Thread::Mutex.new
    end

sync_try_lock_sub(m) click to toggle source

    # File lib/sync.rb, line 268
    def sync_try_lock_sub(m)
      case m
      when SH
        case sync_mode
        when UN
          self.sync_mode = m
          sync_sh_locker[Thread.current] = 1
          ret = true
        when SH
          count = 0 unless count = sync_sh_locker[Thread.current]
          sync_sh_locker[Thread.current] = count + 1
          ret = true
        when EX
          # in EX mode, lock will upgrade to EX lock
          if sync_ex_locker == Thread.current
            self.sync_ex_count = sync_ex_count + 1
            ret = true
          else
            ret = false
          end
        end
      when EX
        if sync_mode == UN or
            sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current)
          self.sync_mode = m
          self.sync_ex_locker = Thread.current
          self.sync_ex_count = 1
          ret = true
        elsif sync_mode == EX && sync_ex_locker == Thread.current
          self.sync_ex_count = sync_ex_count + 1
          ret = true
        else
          ret = false
        end
      else
        Err::LockModeFailer.Fail m
      end
      return ret
    end