diff --git a/lib/process_shared.rb b/lib/process_shared.rb index 1d625d6..2ef9257 100644 --- a/lib/process_shared.rb +++ b/lib/process_shared.rb @@ -28,4 +28,5 @@ end require 'process_shared/binary_semaphore' require 'process_shared/mutex' require 'process_shared/condition_variable' +require 'process_shared/monitor' diff --git a/lib/process_shared/monitor.rb b/lib/process_shared/monitor.rb new file mode 100644 index 0000000..51ea44a --- /dev/null +++ b/lib/process_shared/monitor.rb @@ -0,0 +1,31 @@ +require 'process_shared' +require 'process_shared/mutex' + +module ProcessShared + class Monitor < Mutex + def initialize + super + @lock_count = 0 + end + + def lock + if locked_by == ::Process.pid + @lock_count += 1 + else + super + end + end + + def unlock + if locked_by == ::Process.pid + if @lock_count > 0 + @lock_count -= 1 + else + super + end + else + super + end + end + end +end diff --git a/lib/process_shared/mutex.rb b/lib/process_shared/mutex.rb index 6de5d12..1aab1ed 100644 --- a/lib/process_shared/mutex.rb +++ b/lib/process_shared/mutex.rb @@ -94,7 +94,7 @@ module ProcessShared end end - private + protected def locked_by with_internal_lock do diff --git a/spec/process_shared/monitor_spec.rb b/spec/process_shared/monitor_spec.rb new file mode 100644 index 0000000..e62b3d6 --- /dev/null +++ b/spec/process_shared/monitor_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' +require 'process_shared' + +module ProcessShared + describe Monitor do + + include LockBehavior + + before :each do + @lock = Monitor.new + end + + it 'raises exception when unlocked by other process' do + pid = Kernel.fork do + @lock.lock + sleep 0.2 + @lock.unlock + Kernel.exit! + end + + sleep 0.1 + proc { @lock.unlock }.must_raise(ProcessError) + + ::Process.wait(pid) + end + + it 'raises nothing with nested lock' do + @lock.lock + @lock.lock + @lock.unlock + @lock.unlock + end + end +end