process_shared 0.0.4 → 0.1.0

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 (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