From 41b6777638152889f5d11395c0a18f4e7f24cbcc Mon Sep 17 00:00:00 2001 From: Marc Siegel Date: Fri, 27 Dec 2013 13:38:23 -0500 Subject: [PATCH 1/3] Fix SharedMemoryIO#read for binary data on Ruby 1.9+ --- lib/process_shared/shared_memory_io.rb | 1 + spec/process_shared/shared_memory_io_spec.rb | 36 ++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 spec/process_shared/shared_memory_io_spec.rb diff --git a/lib/process_shared/shared_memory_io.rb b/lib/process_shared/shared_memory_io.rb index a21a8a0..dee31fb 100644 --- a/lib/process_shared/shared_memory_io.rb +++ b/lib/process_shared/shared_memory_io.rb @@ -198,6 +198,7 @@ module ProcessShared def read(length = nil, buffer = nil) length ||= (mem.size - pos) buffer ||= '' + buffer.force_encoding('ASCII-8BIT') unless RUBY_VERSION.start_with?('1.8') actual_length = [(mem.size - pos), length].min actual_length.times do diff --git a/spec/process_shared/shared_memory_io_spec.rb b/spec/process_shared/shared_memory_io_spec.rb new file mode 100644 index 0000000..7fcb26a --- /dev/null +++ b/spec/process_shared/shared_memory_io_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' +require 'process_shared' + +module ProcessShared + describe SharedMemoryIO do + + describe '#read' do + def binary(s) + (RUBY_VERSION == '1.8.7') ? s : s.force_encoding('ASCII-8BIT') + end + + def output_for(input) + mem = SharedMemory.new(16) + mem.put_bytes(0, input, 0, input.bytesize) + io = SharedMemoryIO.new(mem) + io.read(input.bytesize) + end + + it 'returns correct binary data for plain ASCII string' do + input = 'Hello' + output_for(input).must_equal binary(input) + end + + it 'returns correct binary data for UTF-8 string' do + input = 'Mária' + output_for(input).must_equal binary(input) + end + + it 'returns correct binary data for explicitly binary data' do + input = "\x00\xD1\x9B\x86\x00" + output_for(input).must_equal binary(input) + end + end + + end +end From 4518e6fdad2d85bf8dacddcd73192d394dd7ec56 Mon Sep 17 00:00:00 2001 From: Marc Siegel Date: Fri, 27 Dec 2013 15:15:07 -0500 Subject: [PATCH 2/3] Fix ConditionVariable#signal to only post if semaphore has waiters This fixes a bug where calls to #signal would end up "over-posting" the semaphore, causing subsequent waits to return immediately until the semaphore value is back down to zero. --- lib/process_shared/condition_variable.rb | 4 +++- spec/process_shared/condition_variable_spec.rb | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/process_shared/condition_variable.rb b/lib/process_shared/condition_variable.rb index 0fd42b4..bf4d17c 100644 --- a/lib/process_shared/condition_variable.rb +++ b/lib/process_shared/condition_variable.rb @@ -16,7 +16,9 @@ module ProcessShared end def signal - @sem.post + @internal.synchronize do + @sem.post unless @waiting.read_int.zero? + end end def wait(mutex, timeout = nil) diff --git a/spec/process_shared/condition_variable_spec.rb b/spec/process_shared/condition_variable_spec.rb index 7ffcaba..8631503 100644 --- a/spec/process_shared/condition_variable_spec.rb +++ b/spec/process_shared/condition_variable_spec.rb @@ -63,5 +63,19 @@ module ProcessShared (Time.now.to_f - start).must be_gte(0.1) } end + + it 'correctly handles #signal when no waiters' do + mutex = Mutex.new + cond = ConditionVariable.new + + # fix for bug: #wait not waiting after unmatched call to #signal + cond.signal + + mutex.synchronize { + start = Time.now.to_f + cond.wait(mutex, 0.1) + (Time.now.to_f - start).must be_gte(0.1) + } + end end end From 14fa8662f56ff93dc70a0154350d392a4b3a29e9 Mon Sep 17 00:00:00 2001 From: Marc Siegel Date: Fri, 27 Dec 2013 15:21:01 -0500 Subject: [PATCH 3/3] Fix test on 1.9.x by adding magic file encoding comment --- spec/process_shared/shared_memory_io_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/process_shared/shared_memory_io_spec.rb b/spec/process_shared/shared_memory_io_spec.rb index 7fcb26a..2c31173 100644 --- a/spec/process_shared/shared_memory_io_spec.rb +++ b/spec/process_shared/shared_memory_io_spec.rb @@ -1,3 +1,7 @@ +# encoding: UTF-8 +# ^^^ +# NOTE: This magic comment is necessary for the UTF-8 string literal below +# on Ruby 1.9.x require 'spec_helper' require 'process_shared'