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.
- data/ext/helper/extconf.rb +14 -0
- data/ext/helper/helper.c +70 -0
- data/lib/mach.rb +12 -0
- data/lib/mach/clock.rb +24 -0
- data/lib/mach/error.rb +56 -0
- data/lib/mach/functions.rb +342 -0
- data/lib/mach/host.rb +28 -0
- data/lib/mach/port.rb +143 -0
- data/lib/mach/semaphore.rb +74 -0
- data/lib/mach/task.rb +42 -0
- data/lib/mach/time_spec.rb +16 -0
- data/lib/process_shared.rb +17 -1
- data/lib/process_shared/binary_semaphore.rb +18 -7
- data/lib/process_shared/mach.rb +93 -0
- data/lib/process_shared/mach/semaphore.rb +39 -0
- data/lib/process_shared/posix/errno.rb +40 -0
- data/lib/process_shared/posix/libc.rb +78 -0
- data/lib/process_shared/posix/semaphore.rb +125 -0
- data/lib/process_shared/posix/shared_array.rb +71 -0
- data/lib/process_shared/posix/shared_memory.rb +82 -0
- data/lib/process_shared/posix/time_spec.rb +13 -0
- data/lib/process_shared/posix/time_val.rb +23 -0
- data/lib/process_shared/semaphore.rb +26 -73
- data/lib/process_shared/shared_array.rb +3 -1
- data/lib/process_shared/shared_memory.rb +10 -52
- data/lib/process_shared/time_spec.rb +22 -0
- data/spec/mach/port_spec.rb +21 -0
- data/spec/mach/scratch.rb +67 -0
- data/spec/mach/scratch2.rb +78 -0
- data/spec/mach/semaphore_spec.rb +60 -0
- data/spec/mach/task_spec.rb +31 -0
- data/spec/process_shared/scratch.rb +21 -0
- data/spec/process_shared/semaphore_spec.rb +12 -11
- data/spec/process_shared/shared_memory_spec.rb +1 -1
- metadata +46 -36
- data/ext/libpsem/bsem.c +0 -188
- data/ext/libpsem/bsem.h +0 -32
- data/ext/libpsem/constants.c +0 -22
- data/ext/libpsem/constants.h +0 -18
- data/ext/libpsem/extconf.rb +0 -40
- data/ext/libpsem/mempcpy.c +0 -7
- data/ext/libpsem/mempcpy.h +0 -13
- data/ext/libpsem/mutex.c +0 -15
- data/ext/libpsem/mutex.h +0 -14
- data/ext/libpsem/psem.c +0 -15
- data/ext/libpsem/psem.h +0 -45
- data/ext/libpsem/psem_error.c +0 -46
- data/ext/libpsem/psem_error.h +0 -11
- data/ext/libpsem/psem_posix.c +0 -160
- data/ext/libpsem/psem_posix.h +0 -10
- data/lib/process_shared/bounded_semaphore.rb +0 -46
- data/lib/process_shared/libc.rb +0 -36
- data/lib/process_shared/libpsem.bundle +0 -0
- data/lib/process_shared/libpsem.so +0 -0
- data/lib/process_shared/psem.rb +0 -113
- data/spec/process_shared/bounded_semaphore_spec.rb +0 -48
- data/spec/process_shared/libc_spec.rb +0 -9
- data/spec/process_shared/psem_spec.rb +0 -136
data/ext/libpsem/psem_posix.h
DELETED
@@ -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
|
data/lib/process_shared/libc.rb
DELETED
@@ -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
|
Binary file
|
Binary file
|
data/lib/process_shared/psem.rb
DELETED
@@ -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,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
|