process_shared 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/ext/helper/extconf.rb +14 -0
  2. data/ext/helper/helper.c +70 -0
  3. data/lib/mach.rb +12 -0
  4. data/lib/mach/clock.rb +24 -0
  5. data/lib/mach/error.rb +56 -0
  6. data/lib/mach/functions.rb +342 -0
  7. data/lib/mach/host.rb +28 -0
  8. data/lib/mach/port.rb +143 -0
  9. data/lib/mach/semaphore.rb +74 -0
  10. data/lib/mach/task.rb +42 -0
  11. data/lib/mach/time_spec.rb +16 -0
  12. data/lib/process_shared.rb +17 -1
  13. data/lib/process_shared/binary_semaphore.rb +18 -7
  14. data/lib/process_shared/mach.rb +93 -0
  15. data/lib/process_shared/mach/semaphore.rb +39 -0
  16. data/lib/process_shared/posix/errno.rb +40 -0
  17. data/lib/process_shared/posix/libc.rb +78 -0
  18. data/lib/process_shared/posix/semaphore.rb +125 -0
  19. data/lib/process_shared/posix/shared_array.rb +71 -0
  20. data/lib/process_shared/posix/shared_memory.rb +82 -0
  21. data/lib/process_shared/posix/time_spec.rb +13 -0
  22. data/lib/process_shared/posix/time_val.rb +23 -0
  23. data/lib/process_shared/semaphore.rb +26 -73
  24. data/lib/process_shared/shared_array.rb +3 -1
  25. data/lib/process_shared/shared_memory.rb +10 -52
  26. data/lib/process_shared/time_spec.rb +22 -0
  27. data/spec/mach/port_spec.rb +21 -0
  28. data/spec/mach/scratch.rb +67 -0
  29. data/spec/mach/scratch2.rb +78 -0
  30. data/spec/mach/semaphore_spec.rb +60 -0
  31. data/spec/mach/task_spec.rb +31 -0
  32. data/spec/process_shared/scratch.rb +21 -0
  33. data/spec/process_shared/semaphore_spec.rb +12 -11
  34. data/spec/process_shared/shared_memory_spec.rb +1 -1
  35. metadata +46 -36
  36. data/ext/libpsem/bsem.c +0 -188
  37. data/ext/libpsem/bsem.h +0 -32
  38. data/ext/libpsem/constants.c +0 -22
  39. data/ext/libpsem/constants.h +0 -18
  40. data/ext/libpsem/extconf.rb +0 -40
  41. data/ext/libpsem/mempcpy.c +0 -7
  42. data/ext/libpsem/mempcpy.h +0 -13
  43. data/ext/libpsem/mutex.c +0 -15
  44. data/ext/libpsem/mutex.h +0 -14
  45. data/ext/libpsem/psem.c +0 -15
  46. data/ext/libpsem/psem.h +0 -45
  47. data/ext/libpsem/psem_error.c +0 -46
  48. data/ext/libpsem/psem_error.h +0 -11
  49. data/ext/libpsem/psem_posix.c +0 -160
  50. data/ext/libpsem/psem_posix.h +0 -10
  51. data/lib/process_shared/bounded_semaphore.rb +0 -46
  52. data/lib/process_shared/libc.rb +0 -36
  53. data/lib/process_shared/libpsem.bundle +0 -0
  54. data/lib/process_shared/libpsem.so +0 -0
  55. data/lib/process_shared/psem.rb +0 -113
  56. data/spec/process_shared/bounded_semaphore_spec.rb +0 -48
  57. data/spec/process_shared/libc_spec.rb +0 -9
  58. data/spec/process_shared/psem_spec.rb +0 -136
@@ -1,10 +0,0 @@
1
- #ifndef __PSEM_POSIX_H__
2
- #define __PSEM_POSIX_H__
3
-
4
- #include <semaphore.h>
5
-
6
- struct psem {
7
- sem_t *sem;
8
- };
9
-
10
- #endif /* __PSEM_POSIX_H__ */
@@ -1,46 +0,0 @@
1
- require 'process_shared/psem'
2
- require 'process_shared/semaphore'
3
-
4
- module ProcessShared
5
- # BoundedSemaphore is identical to Semaphore except that its value
6
- # is not permitted to rise above a maximum. When the value is at
7
- # the maximum, calls to #post will have no effect.
8
- class BoundedSemaphore < Semaphore
9
- # With no associated block, open is a synonym for
10
- # Semaphore.new. If the optional code block is given, it will be
11
- # passed +sem+ as an argument, and the Semaphore object will
12
- # automatically be closed when the block terminates. In this
13
- # instance, BoundedSemaphore.open returns the value of the block.
14
- #
15
- # @param [Integer] value the initial semaphore value
16
- # @param [String] name not currently supported
17
- def self.open(maxvalue, value = 1, name = nil, &block)
18
- new(maxvalue, value, name).with_self(&block)
19
- end
20
-
21
- # Create a new semaphore with initial value +value+. After
22
- # {Kernel#fork}, the semaphore will be shared across two (or more)
23
- # processes. The semaphore must be closed with {#close} in each
24
- # process that no longer needs the semaphore.
25
- #
26
- # (An object finalizer is registered that will close the semaphore
27
- # to avoid memory leaks, but this should be considered a last
28
- # resort).
29
- #
30
- # @param [Integer] value the initial semaphore value
31
- # @param [String] name not currently supported
32
- def initialize(maxvalue, value = 1, name = nil)
33
- init(PSem.sizeof_bsem_t, 'bsem', name) do |sem_name|
34
- bsem_open(sem, sem_name, maxvalue, value, err)
35
- end
36
- end
37
-
38
- protected
39
-
40
- alias_method :psem_unlink, :bsem_unlink
41
- alias_method :psem_close, :bsem_close
42
- alias_method :psem_wait, :bsem_wait
43
- alias_method :psem_post, :bsem_post
44
- alias_method :psem_getvalue, :bsem_getvalue
45
- end
46
- end
@@ -1,36 +0,0 @@
1
- require 'ffi'
2
-
3
- require 'process_shared/posix_call'
4
- require 'process_shared/psem'
5
-
6
- module ProcessShared
7
- module LibC
8
- extend FFI::Library
9
- extend PosixCall
10
-
11
- ffi_lib FFI::Library::LIBC
12
-
13
- MAP_FAILED = FFI::Pointer.new(-1)
14
- MAP_SHARED = PSem.map_shared
15
- MAP_PRIVATE = PSem.map_private
16
-
17
- PROT_READ = PSem.prot_read
18
- PROT_WRITE = PSem.prot_write
19
- PROT_EXEC = PSem.prot_exec
20
- PROT_NONE = PSem.prot_none
21
-
22
- O_RDWR = PSem.o_rdwr
23
- O_CREAT = PSem.o_creat
24
- O_EXCL = PSem.o_excl
25
-
26
- attach_variable :errno, :int
27
-
28
- attach_function :mmap, [:pointer, :size_t, :int, :int, :int, :off_t], :pointer
29
- attach_function :munmap, [:pointer, :size_t], :int
30
- attach_function :ftruncate, [:int, :off_t], :int
31
- attach_function :close, [:int], :int
32
-
33
- error_check(:mmap) { |v| v == MAP_FAILED }
34
- error_check(:munmap, :ftruncate, :close)
35
- end
36
- end
@@ -1,113 +0,0 @@
1
- require 'ffi'
2
-
3
- module ProcessShared
4
- module PSem
5
- class Error < FFI::Struct
6
- layout(:source, :int,
7
- :errno, :int)
8
- end
9
-
10
- extend FFI::Library
11
-
12
- # Workaround FFI dylib/bundle issue. See https://github.com/ffi/ffi/issues/42
13
- suffix = if FFI::Platform.mac?
14
- 'bundle'
15
- else
16
- FFI::Platform::LIBSUFFIX
17
- end
18
-
19
- ffi_lib File.join(File.expand_path(File.dirname(__FILE__)),
20
- 'libpsem.' + suffix)
21
-
22
- class << self
23
- # Replace methods in `syms` with error checking wrappers that
24
- # invoke the original psem method and raise an appropriate
25
- # error.
26
- #
27
- # The last argument is assumed to be a pointer to a pointer
28
- # where either a psem error or NULL will be stored.
29
- def psem_error_check(*syms)
30
- syms.each do |sym|
31
- method = self.method(sym)
32
-
33
- block = lambda do |*args|
34
- if method.call(*args) < 0
35
- errp = args[-1]
36
- unless errp.nil?
37
- begin
38
- err = Error.new(errp.read_pointer)
39
- errp.write_pointer(nil)
40
- if err[:source] == PSem.e_source_system
41
- raise SystemCallError.new("error in #{sym}", err[:errno])
42
- else
43
- raise "error in #{sym}: #{err.get_integer(1)}"
44
- end
45
- ensure
46
- psem_error_free(err)
47
- end
48
- end
49
- end
50
- end
51
-
52
- define_method(sym, &block)
53
- define_singleton_method(sym, &block)
54
- end
55
- end
56
- end
57
-
58
- # Generic constants
59
-
60
- int_consts = [:o_rdwr,
61
- :o_creat,
62
- :o_excl,
63
-
64
- :prot_read,
65
- :prot_write,
66
- :prot_exec,
67
- :prot_none,
68
-
69
- :map_shared,
70
- :map_private]
71
- int_consts.each { |sym| attach_variable sym, :int }
72
-
73
- # Other constants, functions
74
-
75
- attach_function :psem_error_free, :error_free, [:pointer], :void
76
-
77
- attach_variable :e_source_system, :E_SOURCE_SYSTEM, :int
78
- attach_variable :e_source_psem, :E_SOURCE_PSEM, :int
79
-
80
- attach_variable :e_name_too_long, :E_NAME_TOO_LONG, :int
81
-
82
- attach_variable :sizeof_psem_t, :size_t
83
- attach_variable :sizeof_bsem_t, :size_t
84
-
85
- # PSem functions
86
-
87
- attach_function :psem_open, [:pointer, :string, :uint, :pointer], :int
88
- attach_function :psem_close, [:pointer, :pointer], :int
89
- attach_function :psem_unlink, [:string, :pointer], :int
90
- attach_function :psem_post, [:pointer, :pointer], :int
91
- attach_function :psem_wait, [:pointer, :pointer], :int
92
- attach_function :psem_trywait, [:pointer, :pointer], :int
93
- attach_function :psem_timedwait, [:pointer, :float, :pointer], :int
94
- attach_function :psem_getvalue, [:pointer, :pointer, :pointer], :int
95
-
96
- psem_error_check(:psem_open, :psem_close, :psem_unlink, :psem_post,
97
- :psem_wait, :psem_trywait, :psem_timedwait, :psem_getvalue)
98
-
99
- # BSem functions
100
-
101
- attach_function :bsem_open, [:pointer, :string, :uint, :uint, :pointer], :int
102
- attach_function :bsem_close, [:pointer, :pointer], :int
103
- attach_function :bsem_unlink, [:string, :pointer], :int
104
- attach_function :bsem_post, [:pointer, :pointer], :int
105
- attach_function :bsem_wait, [:pointer, :pointer], :int
106
- attach_function :bsem_trywait, [:pointer, :pointer], :int
107
- attach_function :bsem_timedwait, [:pointer, :float, :pointer], :int
108
- attach_function :bsem_getvalue, [:pointer, :pointer, :pointer], :int
109
-
110
- psem_error_check(:bsem_open, :bsem_close, :bsem_unlink, :bsem_post,
111
- :bsem_wait, :bsem_trywait, :bsem_timedwait, :bsem_getvalue)
112
- end
113
- end
@@ -1,48 +0,0 @@
1
- require 'spec_helper'
2
- require 'process_shared/bounded_semaphore'
3
-
4
- module ProcessShared
5
- describe BoundedSemaphore do
6
- it 'never rises above its max value' do
7
- max = 10
8
- BoundedSemaphore.open(max) do |sem|
9
- pids = []
10
- 10.times do |i|
11
- pids << fork do
12
- 100.times do
13
- if rand(3) == 0
14
- sem.wait
15
- else
16
- sem.post
17
- end
18
- end
19
-
20
- exit i
21
- end
22
- end
23
-
24
- 100.times do
25
- sem.value.must be_lte(max)
26
- end
27
-
28
- pids.each { |pid| Process.wait(pid) }
29
- end
30
- end
31
-
32
- describe '#post and #wait' do
33
- it 'increments and decrements the value' do
34
- Semaphore.open(0) do |sem|
35
- 10.times do |i|
36
- sem.post
37
- sem.value.must_equal(i + 1)
38
- end
39
-
40
- 10.times do |i|
41
- sem.wait
42
- sem.value.must_equal(10 - i - 1)
43
- end
44
- end
45
- end
46
- end
47
- end
48
- end
@@ -1,9 +0,0 @@
1
- require 'process_shared/libc'
2
-
3
- module ProcessShared
4
- describe LibC do
5
- it 'throws exceptions with invalid args' do
6
- proc { LibC.mmap nil,2,0,0,1,0 }.must_raise(Errno::EINVAL)
7
- end
8
- end
9
- end
@@ -1,136 +0,0 @@
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