123456789_123456789_123456789_123456789_123456789_

Module: Sync_m

Relationships & Source Files
Namespace Children
Exceptions:
Err
Extension / Inclusion / Inheritance Descendants
Included In:
Defined in: lib/sync.rb

Overview

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

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Class Method Details

.append_features(cl)

[ GitHub ]

  
# File 'lib/sync.rb', line 90

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)

[ GitHub ]

  
# File 'lib/sync.rb', line 78

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)

[ GitHub ]

  
# File 'lib/sync.rb', line 98

def Sync_m.extend_object(obj)
  super
  obj.sync_extend
end

Instance Attribute Details

#sync_ex_count (rw)

[ GitHub ]

  
# File 'lib/sync.rb', line 247

attr_accessor :sync_ex_count

#sync_ex_locker (rw)

[ GitHub ]

  
# File 'lib/sync.rb', line 246

attr_accessor :sync_ex_locker

#sync_exclusive?Boolean (readonly)

[ GitHub ]

  
# File 'lib/sync.rb', line 125

def sync_exclusive?
  sync_mode == EX
end

#sync_locked?Boolean (readonly)

accessing

[ GitHub ]

  
# File 'lib/sync.rb', line 117

def sync_locked?
  sync_mode != UN
end

#sync_mode (rw)

[ GitHub ]

  
# File 'lib/sync.rb', line 241

attr_accessor :sync_mode

#sync_sh_locker (rw)

[ GitHub ]

  
# File 'lib/sync.rb', line 245

attr_accessor :sync_sh_locker

#sync_shared?Boolean (readonly)

[ GitHub ]

  
# File 'lib/sync.rb', line 121

def sync_shared?
  sync_mode == SH
end

#sync_upgrade_waiting (rw)

[ GitHub ]

  
# File 'lib/sync.rb', line 244

attr_accessor :sync_upgrade_waiting

#sync_waiting (rw)

[ GitHub ]

  
# File 'lib/sync.rb', line 243

attr_accessor :sync_waiting

Instance Method Details

#initialize(*args) (private)

[ GitHub ]

  
# File 'lib/sync.rb', line 267

def initialize(*args)
  super
  sync_initialize
end

#sync_extend

[ GitHub ]

  
# File 'lib/sync.rb', line 103

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_initialize (private)

[ GitHub ]

  
# File 'lib/sync.rb', line 256

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_inspect

[ GitHub ]

  
# File 'lib/sync.rb', line 249

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)

[ GitHub ]

  
# File 'lib/sync.rb', line 137

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_synchronize(mode = EX)

[ GitHub ]

  
# File 'lib/sync.rb', line 230

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)

locking methods.

[ GitHub ]

  
# File 'lib/sync.rb', line 130

def sync_try_lock(mode = EX)
  return unlock if mode == UN
  @sync_mutex.synchronize do
    sync_try_lock_sub(mode)
  end
end

#sync_try_lock_sub(m) (private)

[ GitHub ]

  
# File 'lib/sync.rb', line 272

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

#sync_unlock(m = EX)

[ GitHub ]

  
# File 'lib/sync.rb', line 165

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