process_shared 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. data/COPYING +19 -0
  2. data/ChangeLog +0 -0
  3. data/README.rdoc +69 -0
  4. data/ext/libpsem/bsem.c +188 -0
  5. data/ext/libpsem/bsem.h +32 -0
  6. data/ext/libpsem/constants.c +22 -0
  7. data/ext/libpsem/constants.h +18 -0
  8. data/ext/libpsem/extconf.rb +36 -0
  9. data/ext/libpsem/mempcpy.c +7 -0
  10. data/ext/libpsem/mempcpy.h +13 -0
  11. data/ext/libpsem/mutex.c +15 -0
  12. data/ext/libpsem/mutex.h +14 -0
  13. data/ext/libpsem/psem.c +15 -0
  14. data/ext/libpsem/psem.h +43 -0
  15. data/ext/libpsem/psem_error.c +46 -0
  16. data/ext/libpsem/psem_error.h +11 -0
  17. data/ext/libpsem/psem_posix.c +130 -0
  18. data/ext/libpsem/psem_posix.h +10 -0
  19. data/ext/pthread_sync_helper/extconf.rb +9 -0
  20. data/ext/pthread_sync_helper/pthread_sync_helper.c +43 -0
  21. data/ext/semaphore.c +623 -0
  22. data/lib/process_shared.rb +6 -0
  23. data/lib/process_shared/abstract_semaphore.rb +50 -0
  24. data/lib/process_shared/bounded_semaphore.rb +43 -0
  25. data/lib/process_shared/condition_variable.rb +27 -0
  26. data/lib/process_shared/libc.rb +36 -0
  27. data/lib/process_shared/libpsem.bundle +0 -0
  28. data/lib/process_shared/libpsem.so +0 -0
  29. data/lib/process_shared/mutex.rb +103 -0
  30. data/lib/process_shared/posix_call.rb +29 -0
  31. data/lib/process_shared/process_error.rb +3 -0
  32. data/lib/process_shared/psem.rb +109 -0
  33. data/lib/process_shared/rt.rb +21 -0
  34. data/lib/process_shared/semaphore.rb +60 -0
  35. data/lib/process_shared/shared_memory.rb +45 -0
  36. data/lib/process_shared/thread.rb +30 -0
  37. data/lib/process_shared/with_self.rb +20 -0
  38. data/lib/scratch.rb +300 -0
  39. data/spec/process_shared/bounded_semaphore_spec.rb +48 -0
  40. data/spec/process_shared/libc_spec.rb +9 -0
  41. data/spec/process_shared/mutex_spec.rb +74 -0
  42. data/spec/process_shared/psem_spec.rb +136 -0
  43. data/spec/process_shared/semaphore_spec.rb +76 -0
  44. data/spec/process_shared/shared_memory_spec.rb +36 -0
  45. data/spec/spec_helper.rb +35 -0
  46. metadata +139 -0
@@ -0,0 +1,74 @@
1
+ require 'spec_helper'
2
+ require 'process_shared/mutex'
3
+ require 'process_shared/shared_memory'
4
+
5
+ module ProcessShared
6
+ describe Mutex do
7
+ it 'protects access to a shared variable' do
8
+ mutex = Mutex.new
9
+ mem = SharedMemory.new(:char)
10
+ mem.put_char(0, 0)
11
+
12
+ pids = []
13
+ 10.times do |i|
14
+ inc = (-1) ** i # half the procs increment; half decrement
15
+ pids << fork do
16
+ 10.times do
17
+ mutex.lock
18
+ begin
19
+ mem.put_char(0, mem.get_char(0) + inc)
20
+ sleep 0.001
21
+ ensure
22
+ mutex.unlock
23
+ end
24
+ end
25
+ Kernel.exit!
26
+ end
27
+ end
28
+
29
+ pids.each { |pid| ::Process.wait(pid) }
30
+
31
+ mem.get_char(0).must_equal(0)
32
+ end
33
+
34
+ it 'protects access to a shared variable with synchronize' do
35
+ mutex = Mutex.new
36
+ mem = SharedMemory.new(:char)
37
+ mem.put_char(0, 0)
38
+
39
+ pids = []
40
+ 10.times do |i|
41
+ inc = (-1) ** i # half the procs increment; half decrement
42
+ pids << fork do
43
+ 10.times do
44
+ mutex.synchronize do
45
+ mem.put_char(0, mem.get_char(0) + inc)
46
+ sleep 0.001
47
+ end
48
+ end
49
+ Kernel.exit!
50
+ end
51
+ end
52
+
53
+ pids.each { |pid| ::Process.wait(pid) }
54
+
55
+ mem.get_char(0).must_equal(0)
56
+ end
57
+
58
+ it 'raises exception when unlocked by other process' do
59
+ mutex = Mutex.new
60
+
61
+ pid = Kernel.fork do
62
+ mutex.lock
63
+ sleep 0.2
64
+ mutex.unlock
65
+ Kernel.exit!
66
+ end
67
+
68
+ sleep 0.1
69
+ proc { mutex.unlock }.must_raise(ProcessError)
70
+
71
+ ::Process.wait(pid)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,136 @@
1
+ require 'spec_helper'
2
+ require 'process_shared/psem'
3
+
4
+ module ProcessShared
5
+ describe PSem do
6
+ before do
7
+ extend PSem
8
+ end
9
+
10
+ before(:each) do
11
+ @err = FFI::MemoryPointer.new(:pointer)
12
+ end
13
+
14
+ describe '.psem_open' do
15
+ it 'opens a psem' do
16
+ psem = FFI::MemoryPointer.new(PSem.sizeof_psem_t)
17
+ psem_open(psem, "psem-test", 1, @err)
18
+ psem_unlink("psem-test", @err)
19
+ end
20
+
21
+ it 'raises excpetion if name alredy exists' do
22
+ psem1 = FFI::MemoryPointer.new(PSem.sizeof_psem_t)
23
+ psem2 = FFI::MemoryPointer.new(PSem.sizeof_psem_t)
24
+ psem_open(psem1, "psem-test", 1, @err)
25
+ proc { psem_open(psem2, "psem-test", 1, @err) }.must_raise(Errno::EEXIST)
26
+
27
+ psem_unlink("psem-test", @err)
28
+ psem_open(psem2, "psem-test", 1, @err)
29
+ psem_unlink("psem-test", @err)
30
+ end
31
+ end
32
+
33
+ describe '.psem_wait' do
34
+ before(:each) do
35
+ @psem = FFI::MemoryPointer.new(PSem.sizeof_psem_t)
36
+ psem_open(@psem, 'psem-test', 1, @err)
37
+ psem_unlink('psem-test', @err)
38
+
39
+ @int = FFI::MemoryPointer.new(:int)
40
+ end
41
+
42
+ after(:each) do
43
+ #psem_close(@psem, @err)
44
+ end
45
+
46
+ def value
47
+ psem_getvalue(@psem, @int, @err)
48
+ @int.get_int(0)
49
+ end
50
+
51
+ it 'decrements psem value' do
52
+ value.must_equal 1
53
+ psem_wait(@psem, @err)
54
+ value.must_equal(0)
55
+ end
56
+
57
+ it 'waits until another process posts' do
58
+ psem_wait(@psem, @err)
59
+
60
+ # child exits with ~ time spent waiting
61
+ child = fork do
62
+ start = Time.now
63
+ psem_wait(@psem, @err)
64
+ exit (Time.now - start).ceil
65
+ end
66
+
67
+ t = 1.5
68
+ sleep t
69
+ psem_post(@psem, @err)
70
+ _pid, status = Process.wait2(child)
71
+ status.exitstatus.must_equal 2
72
+ end
73
+ end
74
+
75
+ describe '.bsem_open' do
76
+ it 'opens a bsem' do
77
+ bsem = FFI::MemoryPointer.new(PSem.sizeof_bsem_t)
78
+ bsem_open(bsem, "bsem-test", 1, 1, @err)
79
+ bsem_unlink("bsem-test", @err)
80
+ end
81
+
82
+ it 'raises excpetion if name alredy exists' do
83
+ bsem1 = FFI::MemoryPointer.new(PSem.sizeof_bsem_t)
84
+ bsem2 = FFI::MemoryPointer.new(PSem.sizeof_bsem_t)
85
+ bsem_open(bsem1, "bsem-test", 1, 1, @err)
86
+ proc { bsem_open(bsem2, "bsem-test", 1, 1, @err) }.must_raise(Errno::EEXIST)
87
+
88
+ bsem_unlink("bsem-test", @err)
89
+ bsem_open(bsem2, "bsem-test", 1, 1, @err)
90
+ bsem_unlink("bsem-test", @err)
91
+ end
92
+ end
93
+
94
+ describe '.bsem_wait' do
95
+ before(:each) do
96
+ @bsem = FFI::MemoryPointer.new(PSem.sizeof_bsem_t)
97
+ bsem_open(@bsem, 'bsem-test', 1, 1, @err)
98
+ bsem_unlink('bsem-test', @err)
99
+
100
+ @int = FFI::MemoryPointer.new(:int)
101
+ end
102
+
103
+ after do
104
+ #bsem_close(@bsem, @err)
105
+ end
106
+
107
+ def value
108
+ bsem_getvalue(@bsem, @int, @err)
109
+ @int.get_int(0)
110
+ end
111
+
112
+ it 'decrements bsem value' do
113
+ value.must_equal 1
114
+ bsem_wait(@bsem, @err)
115
+ value.must_equal 0
116
+ end
117
+
118
+ it 'waits until another process posts' do
119
+ bsem_wait(@bsem, @err)
120
+
121
+ # child exits with ~ time spent waiting
122
+ child = fork do
123
+ start = Time.now
124
+ bsem_wait(@bsem, @err)
125
+ exit (Time.now - start).ceil
126
+ end
127
+
128
+ t = 1.5
129
+ sleep t
130
+ bsem_post(@bsem, @err)
131
+ _pid, status = Process.wait2(child)
132
+ status.exitstatus.must_equal 2
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ require 'ffi'
4
+ require 'process_shared/semaphore'
5
+ require 'process_shared/shared_memory'
6
+
7
+ module ProcessShared
8
+ describe Semaphore do
9
+ it 'coordinates access to shared object' do
10
+ nprocs = 4 # number of processes
11
+ nincrs = 1000 # each process increments nincrs times
12
+
13
+ do_increments = lambda do |mem, sem|
14
+ nincrs.times do
15
+ sem.wait
16
+ begin
17
+ val = mem.get_int(0)
18
+ # ensure other procs have a chance to interfere
19
+ sleep 0.001 if rand(100) == 0
20
+ mem.put_int(0, val + 1)
21
+ rescue => e
22
+ "#{Process.pid} die'ing because #{e}"
23
+ ensure
24
+ sem.post
25
+ end
26
+ end
27
+ end
28
+
29
+ # Make sure it fails with no synchronization
30
+ no_sem = Object.new
31
+ class << no_sem
32
+ def wait; end
33
+ def post; end
34
+ end
35
+ SharedMemory.open(FFI.type_size(:int)) do |mem|
36
+ pids = []
37
+ nprocs.times do
38
+ pids << fork { do_increments.call(mem, no_sem); exit }
39
+ end
40
+
41
+ pids.each { |p| Process.wait(p) }
42
+ # puts "mem is #{mem.get_int(0)}"
43
+ mem.get_int(0).must be_lt(nprocs * nincrs)
44
+ end
45
+
46
+ # Now try with synchronization
47
+ SharedMemory.open(FFI.type_size(:int)) do |mem|
48
+ pids = []
49
+ Semaphore.open do |sem|
50
+ nprocs.times do
51
+ pids << fork { do_increments.call(mem, sem); exit }
52
+ end
53
+ end
54
+
55
+ pids.each { |p| Process.wait(p) }
56
+ mem.get_int(0).must_equal(nprocs * nincrs)
57
+ end
58
+ end
59
+
60
+ describe '#post and #wait' do
61
+ it 'increments and decrements the value' do
62
+ Semaphore.open(0) do |sem|
63
+ 10.times do |i|
64
+ sem.post
65
+ sem.value.must_equal(i + 1)
66
+ end
67
+
68
+ 10.times do |i|
69
+ sem.wait
70
+ sem.value.must_equal(10 - i - 1)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'process_shared/shared_memory'
3
+
4
+ module ProcessShared
5
+ describe SharedMemory do
6
+ it 'shares memory across processes' do
7
+ mem = SharedMemory.new(1)
8
+ mem.put_char(0, 0)
9
+ mem.get_char(0).must_equal(0)
10
+
11
+ pid = fork do
12
+ mem.put_char(0, 123)
13
+ Kernel.exit!
14
+ end
15
+
16
+ ::Process.wait(pid)
17
+
18
+ mem.get_char(0).must_equal(123)
19
+ end
20
+
21
+ it 'initializes with type symbol' do
22
+ mem = SharedMemory.new(:int)
23
+ mem.put_int(0, 0)
24
+ mem.get_int(0).must_equal(0)
25
+
26
+ pid = fork do
27
+ mem.put_int(0, 1234567)
28
+ Kernel.exit!
29
+ end
30
+
31
+ ::Process.wait(pid)
32
+
33
+ mem.get_int(0).must_equal(1234567)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,35 @@
1
+ gem 'minitest'
2
+ require 'minitest/spec'
3
+ require 'minitest/autorun'
4
+ require 'minitest/matchers'
5
+
6
+ class RangeMatcher
7
+ def initialize(operator, limit)
8
+ @operator = operator.to_sym
9
+ @limit = limit
10
+ end
11
+
12
+ def description
13
+ "be #{operator} #{@limit}"
14
+ end
15
+
16
+ def matches?(subject)
17
+ subject.send(@operator, @limit)
18
+ end
19
+
20
+ def failure_message_for_should
21
+ "expected #{operator} #{@limit}"
22
+ end
23
+
24
+ def failure_message_for_should_not
25
+ "expected not #{operator} #{@limit}"
26
+ end
27
+ end
28
+
29
+ def be_lt(value)
30
+ RangeMatcher.new('<', value)
31
+ end
32
+
33
+ def be_lte(value)
34
+ RangeMatcher.new('<=', value)
35
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: process_shared
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Patrick Mahoney
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-12 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ffi
16
+ requirement: &19463720 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *19463720
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake-compiler
27
+ requirement: &19462580 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *19462580
36
+ - !ruby/object:Gem::Dependency
37
+ name: minitest
38
+ requirement: &19461120 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *19461120
47
+ - !ruby/object:Gem::Dependency
48
+ name: minitest-matchers
49
+ requirement: &19459840 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *19459840
58
+ description: FFI wrapper around portable semaphore library with mutex and condition
59
+ vars built on top.
60
+ email: pat@polycrystal.org
61
+ executables: []
62
+ extensions:
63
+ - ext/pthread_sync_helper/extconf.rb
64
+ - ext/libpsem/extconf.rb
65
+ extra_rdoc_files:
66
+ - README.rdoc
67
+ - ChangeLog
68
+ - COPYING
69
+ files:
70
+ - lib/scratch.rb
71
+ - lib/process_shared.rb
72
+ - lib/process_shared/abstract_semaphore.rb
73
+ - lib/process_shared/posix_call.rb
74
+ - lib/process_shared/process_error.rb
75
+ - lib/process_shared/thread.rb
76
+ - lib/process_shared/mutex.rb
77
+ - lib/process_shared/semaphore.rb
78
+ - lib/process_shared/rt.rb
79
+ - lib/process_shared/psem.rb
80
+ - lib/process_shared/with_self.rb
81
+ - lib/process_shared/condition_variable.rb
82
+ - lib/process_shared/bounded_semaphore.rb
83
+ - lib/process_shared/libc.rb
84
+ - lib/process_shared/shared_memory.rb
85
+ - lib/process_shared/libpsem.bundle
86
+ - lib/process_shared/libpsem.so
87
+ - ext/pthread_sync_helper/pthread_sync_helper.c
88
+ - ext/semaphore.c
89
+ - ext/libpsem/mempcpy.c
90
+ - ext/libpsem/psem_error.c
91
+ - ext/libpsem/bsem.c
92
+ - ext/libpsem/psem_posix.c
93
+ - ext/libpsem/psem.c
94
+ - ext/libpsem/mutex.c
95
+ - ext/libpsem/constants.c
96
+ - ext/libpsem/bsem.h
97
+ - ext/libpsem/psem_error.h
98
+ - ext/libpsem/mutex.h
99
+ - ext/libpsem/constants.h
100
+ - ext/libpsem/psem.h
101
+ - ext/libpsem/psem_posix.h
102
+ - ext/libpsem/mempcpy.h
103
+ - ext/pthread_sync_helper/extconf.rb
104
+ - ext/libpsem/extconf.rb
105
+ - spec/process_shared/psem_spec.rb
106
+ - spec/process_shared/shared_memory_spec.rb
107
+ - spec/process_shared/mutex_spec.rb
108
+ - spec/process_shared/bounded_semaphore_spec.rb
109
+ - spec/process_shared/semaphore_spec.rb
110
+ - spec/process_shared/libc_spec.rb
111
+ - spec/spec_helper.rb
112
+ - README.rdoc
113
+ - ChangeLog
114
+ - COPYING
115
+ homepage: https://github.com/pmahoney/process_shared
116
+ licenses: []
117
+ post_install_message:
118
+ rdoc_options: []
119
+ require_paths:
120
+ - lib
121
+ required_ruby_version: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ required_rubygems_version: !ruby/object:Gem::Requirement
128
+ none: false
129
+ requirements:
130
+ - - ! '>='
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ requirements: []
134
+ rubyforge_project:
135
+ rubygems_version: 1.8.10
136
+ signing_key:
137
+ specification_version: 3
138
+ summary: process-shared synchronization primitives
139
+ test_files: []