process_shared 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/mach.rb +101 -4
- data/lib/mach/functions.rb +6 -129
- data/lib/mach/port.rb +8 -8
- data/lib/mach/types.rb +54 -0
- data/lib/process_shared.rb +11 -21
- data/lib/process_shared/binary_semaphore.rb +2 -7
- data/lib/process_shared/condition_variable.rb +1 -1
- data/lib/process_shared/mach.rb +4 -0
- data/lib/process_shared/mach/semaphore.rb +4 -1
- data/lib/process_shared/mutex.rb +3 -8
- data/lib/process_shared/{shared_memory.rb → object_buffer.rb} +3 -17
- data/lib/process_shared/open_with_self.rb +20 -0
- data/lib/process_shared/posix/semaphore.rb +4 -2
- data/lib/process_shared/posix/shared_memory.rb +4 -3
- data/lib/process_shared/shared_array.rb +1 -1
- data/lib/process_shared/synchronizable_semaphore.rb +16 -0
- data/spec/mach/semaphore_spec.rb +30 -20
- data/spec/process_shared/mutex_spec.rb +1 -2
- data/spec/process_shared/semaphore_spec.rb +2 -3
- metadata +29 -18
- data/lib/process_shared/semaphore.rb +0 -37
- data/lib/process_shared/with_self.rb +0 -20
- data/spec/process_shared/scratch.rb +0 -21
data/lib/mach.rb
CHANGED
@@ -1,12 +1,109 @@
|
|
1
|
-
require '
|
2
|
-
|
3
|
-
require 'mach/
|
4
|
-
require 'mach/functions'
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
require 'mach/types'
|
5
4
|
|
6
5
|
module Mach
|
6
|
+
extend Mach::Types
|
7
|
+
|
8
|
+
class MsgHeader < FFI::Struct
|
9
|
+
layout(:bits, :mach_msg_bits_t,
|
10
|
+
:size, :mach_msg_size_t,
|
11
|
+
:remote_port, :mach_port_t,
|
12
|
+
:local_port, :mach_port_t,
|
13
|
+
:reserved, :mach_msg_size_t,
|
14
|
+
:id, :mach_msg_id_t)
|
15
|
+
end
|
16
|
+
|
17
|
+
class MsgBody < FFI::Struct
|
18
|
+
layout(:descriptor_count, :mach_msg_size_t)
|
19
|
+
end
|
20
|
+
|
21
|
+
class MsgBase < FFI::Struct
|
22
|
+
layout(:header, MsgHeader,
|
23
|
+
:body, MsgBody)
|
24
|
+
end
|
25
|
+
|
26
|
+
class MsgTrailer < FFI::Struct
|
27
|
+
layout(:type, :mach_msg_trailer_type_t,
|
28
|
+
:size, :mach_msg_trailer_size_t)
|
29
|
+
end
|
30
|
+
|
31
|
+
class MsgPortDescriptor < FFI::Struct
|
32
|
+
layout(:name, :mach_port_t,
|
33
|
+
:pad1, :mach_msg_size_t, # FIXME: leave oout on __LP64__
|
34
|
+
:pad2, :uint16, # :uint
|
35
|
+
:disposition, :uint8, # :mach_msg_type_name_t
|
36
|
+
:type, :uint8) # :mach_msg_descriptor_type_t
|
37
|
+
end
|
38
|
+
|
39
|
+
SyncPolicy = enum( :fifo, 0x0,
|
40
|
+
:fixed_priority, 0x1,
|
41
|
+
:reversed, 0x2,
|
42
|
+
:order_mask, 0x3,
|
43
|
+
:lifo, 0x0 | 0x2, # um...
|
44
|
+
:max, 0x7 )
|
45
|
+
|
46
|
+
PortRight = enum( :send, 0,
|
47
|
+
:receive,
|
48
|
+
:send_once,
|
49
|
+
:port_set,
|
50
|
+
:dead_name,
|
51
|
+
:labelh,
|
52
|
+
:number )
|
53
|
+
|
54
|
+
# port type macro
|
55
|
+
def self.pt(*syms)
|
56
|
+
acc = 0
|
57
|
+
syms.each do |sym|
|
58
|
+
acc |= (1 << (PortRight[sym] + 16))
|
59
|
+
end
|
60
|
+
acc
|
61
|
+
end
|
62
|
+
|
63
|
+
PORT_NULL = 0
|
64
|
+
MSG_TIMEOUT_NONE = 0
|
65
|
+
|
66
|
+
PortType =
|
67
|
+
enum(:none, 0,
|
68
|
+
:send, pt(:send),
|
69
|
+
:receive, pt(:receive),
|
70
|
+
:send_once, pt(:send_once),
|
71
|
+
:port_set, pt(:port_set),
|
72
|
+
:dead_name, pt(:dead_name),
|
73
|
+
:labelh, pt(:labelh),
|
74
|
+
|
75
|
+
:send_receive, pt(:send, :receive),
|
76
|
+
:send_rights, pt(:send, :send_once),
|
77
|
+
:port_rights, pt(:send, :send_once, :receive),
|
78
|
+
:port_or_dead, pt(:send, :send_once, :receive, :dead_name),
|
79
|
+
:all_rights, pt(:send, :send_once, :receive, :dead_name, :port_set))
|
80
|
+
|
81
|
+
MsgType =
|
82
|
+
enum( :move_receive, 16, # must hold receive rights
|
83
|
+
:move_send, # must hold send rights
|
84
|
+
:move_send_once, # must hold sendonce rights
|
85
|
+
:copy_send, # must hold send rights
|
86
|
+
:make_send, # must hold receive rights
|
87
|
+
:make_send_once, # must hold receive rights
|
88
|
+
:copy_receive ) # must hold receive rights
|
89
|
+
|
90
|
+
SpecialPort =
|
91
|
+
enum( :kernel, 1,
|
92
|
+
:host,
|
93
|
+
:name,
|
94
|
+
:bootstrap )
|
95
|
+
|
96
|
+
KERN_SUCCESS = 0
|
97
|
+
|
98
|
+
|
7
99
|
# @return [Port] the original bootstrap port; different from that
|
8
100
|
# affected by {get,set}_special_port
|
9
101
|
def self.bootstrap_port
|
10
102
|
@bootstrap_port ||= Mach::Port.new(:port => Mach::Functions::bootstrap_port)
|
11
103
|
end
|
12
104
|
end
|
105
|
+
|
106
|
+
require 'mach/port'
|
107
|
+
require 'mach/semaphore'
|
108
|
+
require 'mach/task'
|
109
|
+
require 'mach/functions'
|
data/lib/mach/functions.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'ffi'
|
2
2
|
|
3
|
+
require 'mach/types'
|
3
4
|
require 'mach/time_spec'
|
4
5
|
|
5
6
|
module Mach
|
@@ -7,134 +8,10 @@ module Mach
|
|
7
8
|
# specific).
|
8
9
|
module Functions
|
9
10
|
extend FFI::Library
|
11
|
+
extend Types
|
10
12
|
|
11
13
|
ffi_lib 'c'
|
12
14
|
|
13
|
-
typedef :__darwin_mach_port_t, :mach_port_t
|
14
|
-
typedef :__darwin_natural_t, :natural_t
|
15
|
-
|
16
|
-
typedef :int, :integer_t
|
17
|
-
typedef :int, :kern_return_t # true for 64 bit??
|
18
|
-
typedef :int, :mach_error_t
|
19
|
-
typedef :int, :sync_policy_t # SyncPolicy
|
20
|
-
typedef :int, :clock_id_t
|
21
|
-
typedef :int, :clock_res_t
|
22
|
-
|
23
|
-
typedef :string, :name_t
|
24
|
-
|
25
|
-
typedef :mach_port_t, :host_t
|
26
|
-
typedef :mach_port_t, :task_t
|
27
|
-
typedef :mach_port_t, :ipc_space_t
|
28
|
-
typedef :mach_port_t, :semaphore_t
|
29
|
-
typedef :pointer, :mach_port_pointer_t
|
30
|
-
|
31
|
-
typedef :natural_t, :mach_port_name_t
|
32
|
-
typedef :natural_t, :mach_port_right_t # MachPortRight
|
33
|
-
typedef :pointer, :mach_port_name_array_t
|
34
|
-
typedef :pointer, :mach_port_name_pointer_t
|
35
|
-
|
36
|
-
typedef :uint, :mach_msg_type_name_t
|
37
|
-
typedef :uint, :mach_msg_bits_t
|
38
|
-
typedef :uint, :mach_msg_trailer_type_t
|
39
|
-
typedef :uint, :mach_msg_trailer_size_t
|
40
|
-
typedef :uint, :mach_msg_descriptor_type_t
|
41
|
-
typedef :natural_t, :mach_msg_timeout_t
|
42
|
-
|
43
|
-
typedef :natural_t, :mach_msg_size_t
|
44
|
-
typedef :integer_t, :mach_msg_id_t
|
45
|
-
typedef :integer_t, :mach_msg_options_t
|
46
|
-
typedef :integer_t, :mach_msg_option_t
|
47
|
-
|
48
|
-
class MsgHeader < FFI::Struct
|
49
|
-
layout(:bits, :mach_msg_bits_t,
|
50
|
-
:size, :mach_msg_size_t,
|
51
|
-
:remote_port, :mach_port_t,
|
52
|
-
:local_port, :mach_port_t,
|
53
|
-
:reserved, :mach_msg_size_t,
|
54
|
-
:id, :mach_msg_id_t)
|
55
|
-
end
|
56
|
-
|
57
|
-
class MsgBody < FFI::Struct
|
58
|
-
layout(:descriptor_count, :mach_msg_size_t)
|
59
|
-
end
|
60
|
-
|
61
|
-
class MsgBase < FFI::Struct
|
62
|
-
layout(:header, MsgHeader,
|
63
|
-
:body, MsgBody)
|
64
|
-
end
|
65
|
-
|
66
|
-
class MsgTrailer < FFI::Struct
|
67
|
-
layout(:type, :mach_msg_trailer_type_t,
|
68
|
-
:size, :mach_msg_trailer_size_t)
|
69
|
-
end
|
70
|
-
|
71
|
-
class MsgPortDescriptor < FFI::Struct
|
72
|
-
layout(:name, :mach_port_t,
|
73
|
-
:pad1, :mach_msg_size_t, # FIXME: leave oout on __LP64__
|
74
|
-
:pad2, :uint16, # :uint
|
75
|
-
:disposition, :uint8, # :mach_msg_type_name_t
|
76
|
-
:type, :uint8) # :mach_msg_descriptor_type_t
|
77
|
-
end
|
78
|
-
|
79
|
-
SyncPolicy = enum( :fifo, 0x0,
|
80
|
-
:fixed_priority, 0x1,
|
81
|
-
:reversed, 0x2,
|
82
|
-
:order_mask, 0x3,
|
83
|
-
:lifo, 0x0 | 0x2, # um...
|
84
|
-
:max, 0x7 )
|
85
|
-
|
86
|
-
MachPortRight = enum( :send, 0,
|
87
|
-
:receive,
|
88
|
-
:send_once,
|
89
|
-
:port_set,
|
90
|
-
:dead_name,
|
91
|
-
:labelh,
|
92
|
-
:number )
|
93
|
-
|
94
|
-
# port type
|
95
|
-
def self.pt(*syms)
|
96
|
-
acc = 0
|
97
|
-
syms.each do |sym|
|
98
|
-
acc |= (1 << (MachPortRight[sym] + 16))
|
99
|
-
end
|
100
|
-
acc
|
101
|
-
end
|
102
|
-
|
103
|
-
MACH_PORT_NULL = 0
|
104
|
-
MACH_MSG_TIMEOUT_NONE = 0
|
105
|
-
|
106
|
-
MachPortType =
|
107
|
-
enum(:none, 0,
|
108
|
-
:send, pt(:send),
|
109
|
-
:receive, pt(:receive),
|
110
|
-
:send_once, pt(:send_once),
|
111
|
-
:port_set, pt(:port_set),
|
112
|
-
:dead_name, pt(:dead_name),
|
113
|
-
:labelh, pt(:labelh),
|
114
|
-
|
115
|
-
:send_receive, pt(:send, :receive),
|
116
|
-
:send_rights, pt(:send, :send_once),
|
117
|
-
:port_rights, pt(:send, :send_once, :receive),
|
118
|
-
:port_or_dead, pt(:send, :send_once, :receive, :dead_name),
|
119
|
-
:all_rights, pt(:send, :send_once, :receive, :dead_name, :port_set))
|
120
|
-
|
121
|
-
MachMsgType =
|
122
|
-
enum( :move_receive, 16, # must hold receive rights
|
123
|
-
:move_send, # must hold send rights
|
124
|
-
:move_send_once, # must hold sendonce rights
|
125
|
-
:copy_send, # must hold send rights
|
126
|
-
:make_send, # must hold receive rights
|
127
|
-
:make_send_once, # must hold receive rights
|
128
|
-
:copy_receive ) # must hold receive rights
|
129
|
-
|
130
|
-
MachSpecialPort =
|
131
|
-
enum( :kernel, 1,
|
132
|
-
:host,
|
133
|
-
:name,
|
134
|
-
:bootstrap )
|
135
|
-
|
136
|
-
KERN_SUCCESS = 0
|
137
|
-
|
138
15
|
# Replace methods in +syms+ with error checking wrappers that
|
139
16
|
# invoke the original method and raise a {SystemCallError}.
|
140
17
|
#
|
@@ -232,7 +109,7 @@ module Mach
|
|
232
109
|
|
233
110
|
attach_mach_function(:mach_port_allocate,
|
234
111
|
[:ipc_space_t,
|
235
|
-
|
112
|
+
PortRight,
|
236
113
|
:mach_port_name_pointer_t],
|
237
114
|
:kern_return_t)
|
238
115
|
|
@@ -250,7 +127,7 @@ module Mach
|
|
250
127
|
[:ipc_space_t,
|
251
128
|
:mach_port_name_t,
|
252
129
|
:mach_port_t,
|
253
|
-
|
130
|
+
MsgType],
|
254
131
|
:kern_return_t)
|
255
132
|
|
256
133
|
##################
|
@@ -271,13 +148,13 @@ module Mach
|
|
271
148
|
|
272
149
|
attach_mach_function(:task_get_special_port,
|
273
150
|
[:task_t,
|
274
|
-
|
151
|
+
SpecialPort,
|
275
152
|
:mach_port_pointer_t],
|
276
153
|
:kern_return_t)
|
277
154
|
|
278
155
|
attach_mach_function(:task_set_special_port,
|
279
156
|
[:task_t,
|
280
|
-
|
157
|
+
SpecialPort,
|
281
158
|
:mach_port_t],
|
282
159
|
:kern_return_t)
|
283
160
|
|
data/lib/mach/port.rb
CHANGED
@@ -76,7 +76,7 @@ module Mach
|
|
76
76
|
# Insert +right+ into another ipc space. The current task must
|
77
77
|
# have sufficient rights to insert the requested right.
|
78
78
|
#
|
79
|
-
# @param [
|
79
|
+
# @param [MsgType] right
|
80
80
|
#
|
81
81
|
# @param [Hash] opts
|
82
82
|
#
|
@@ -100,9 +100,9 @@ module Mach
|
|
100
100
|
|
101
101
|
msg[:header].tap do |h|
|
102
102
|
h[:remote_port] = remote_port.to_i
|
103
|
-
h[:local_port] =
|
103
|
+
h[:local_port] = PORT_NULL
|
104
104
|
h[:bits] =
|
105
|
-
(
|
105
|
+
(MsgType[right] | (0 << 8)) | 0x80000000 # MACH_MSGH_BITS_COMPLEX
|
106
106
|
h[:size] = 40 # msg.size
|
107
107
|
end
|
108
108
|
|
@@ -110,8 +110,8 @@ module Mach
|
|
110
110
|
|
111
111
|
msg[:port].tap do |p|
|
112
112
|
p[:name] = port
|
113
|
-
p[:disposition] =
|
114
|
-
p[:type] = 0 #
|
113
|
+
p[:disposition] = MsgType[right]
|
114
|
+
p[:type] = 0 # MSG_PORT_DESCRIPTOR;
|
115
115
|
end
|
116
116
|
|
117
117
|
mach_msg_send msg
|
@@ -130,12 +130,12 @@ module Mach
|
|
130
130
|
msg = ReceiveRightMsg.new
|
131
131
|
|
132
132
|
mach_msg(msg,
|
133
|
-
2, #
|
133
|
+
2, # RCV_MSG,
|
134
134
|
0,
|
135
135
|
msg.size,
|
136
136
|
port,
|
137
|
-
|
138
|
-
|
137
|
+
MSG_TIMEOUT_NONE,
|
138
|
+
PORT_NULL)
|
139
139
|
|
140
140
|
self.class.new :port => msg[:port][:name]
|
141
141
|
end
|
data/lib/mach/types.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Mach
|
4
|
+
module Types
|
5
|
+
extend FFI::Library
|
6
|
+
|
7
|
+
typedef :__darwin_mach_port_t, :mach_port_t
|
8
|
+
typedef :__darwin_natural_t, :natural_t
|
9
|
+
|
10
|
+
typedef :int, :integer_t
|
11
|
+
typedef :int, :kern_return_t # true for 64 bit??
|
12
|
+
typedef :int, :mach_error_t
|
13
|
+
typedef :int, :sync_policy_t # SyncPolicy
|
14
|
+
typedef :int, :clock_id_t
|
15
|
+
typedef :int, :clock_res_t
|
16
|
+
|
17
|
+
typedef :string, :name_t
|
18
|
+
|
19
|
+
typedef :mach_port_t, :host_t
|
20
|
+
typedef :mach_port_t, :task_t
|
21
|
+
typedef :mach_port_t, :ipc_space_t
|
22
|
+
typedef :mach_port_t, :semaphore_t
|
23
|
+
typedef :pointer, :mach_port_pointer_t
|
24
|
+
|
25
|
+
typedef :natural_t, :mach_port_name_t
|
26
|
+
typedef :natural_t, :mach_port_right_t # MachPortRight
|
27
|
+
typedef :pointer, :mach_port_name_array_t
|
28
|
+
typedef :pointer, :mach_port_name_pointer_t
|
29
|
+
|
30
|
+
typedef :uint, :mach_msg_type_name_t
|
31
|
+
typedef :uint, :mach_msg_bits_t
|
32
|
+
typedef :uint, :mach_msg_trailer_type_t
|
33
|
+
typedef :uint, :mach_msg_trailer_size_t
|
34
|
+
typedef :uint, :mach_msg_descriptor_type_t
|
35
|
+
typedef :natural_t, :mach_msg_timeout_t
|
36
|
+
|
37
|
+
typedef :natural_t, :mach_msg_size_t
|
38
|
+
typedef :integer_t, :mach_msg_id_t
|
39
|
+
typedef :integer_t, :mach_msg_options_t
|
40
|
+
typedef :integer_t, :mach_msg_option_t
|
41
|
+
|
42
|
+
def self.typedefs
|
43
|
+
@ffi_typedefs
|
44
|
+
end
|
45
|
+
|
46
|
+
def find_type(t)
|
47
|
+
Mach::Types.find_type(t) || super
|
48
|
+
end
|
49
|
+
|
50
|
+
def enum(*args)
|
51
|
+
Mach::Types.enum(*args)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/process_shared.rb
CHANGED
@@ -3,39 +3,29 @@ require 'ffi'
|
|
3
3
|
if RUBY_VERSION =~ /^1.8/
|
4
4
|
require 'process_shared/define_singleton_method'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
extend DefineSingletonMethod
|
9
|
-
end
|
10
|
-
|
11
|
-
module RT
|
12
|
-
extend DefineSingletonMethod
|
13
|
-
end
|
14
|
-
|
15
|
-
module LibC
|
16
|
-
extend DefineSingletonMethod
|
17
|
-
end
|
6
|
+
class Module
|
7
|
+
include ProcessShared::DefineSingletonMethod
|
18
8
|
end
|
19
9
|
end
|
20
10
|
|
21
|
-
require 'process_shared/semaphore'
|
22
|
-
require 'process_shared/binary_semaphore'
|
23
|
-
require 'process_shared/mutex'
|
24
|
-
require 'process_shared/shared_memory'
|
25
|
-
|
26
11
|
module ProcessShared
|
27
12
|
case FFI::Platform::OS
|
28
13
|
when 'linux'
|
29
14
|
require 'process_shared/posix/shared_memory'
|
30
15
|
require 'process_shared/posix/semaphore'
|
31
16
|
|
32
|
-
SharedMemory
|
33
|
-
Semaphore
|
17
|
+
SharedMemory = Posix::SharedMemory
|
18
|
+
Semaphore = Posix::Semaphore
|
34
19
|
when 'darwin'
|
35
20
|
require 'process_shared/posix/shared_memory'
|
36
21
|
require 'process_shared/mach/semaphore'
|
37
22
|
|
38
|
-
SharedMemory
|
39
|
-
Semaphore
|
23
|
+
SharedMemory = Posix::SharedMemory
|
24
|
+
Semaphore = Mach::Semaphore
|
40
25
|
end
|
41
26
|
end
|
27
|
+
|
28
|
+
require 'process_shared/binary_semaphore'
|
29
|
+
require 'process_shared/mutex'
|
30
|
+
require 'process_shared/condition_variable'
|
31
|
+
|
@@ -1,8 +1,7 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
|
3
3
|
require 'process_shared'
|
4
|
-
require 'process_shared/
|
5
|
-
require 'process_shared/semaphore'
|
4
|
+
require 'process_shared/open_with_self'
|
6
5
|
require 'process_shared/process_error'
|
7
6
|
|
8
7
|
module ProcessShared
|
@@ -14,14 +13,10 @@ module ProcessShared
|
|
14
13
|
# This is identical to a Semaphore but with extra error checking.
|
15
14
|
class BinarySemaphore
|
16
15
|
extend Forwardable
|
17
|
-
|
16
|
+
extend ProcessShared::OpenWithSelf
|
18
17
|
|
19
18
|
def_delegators :@sem, :wait, :try_wait, :synchronize, :value, :close
|
20
19
|
|
21
|
-
def self.open(value = 1, &block)
|
22
|
-
new(value).with_self(&block)
|
23
|
-
end
|
24
|
-
|
25
20
|
# Create a new semaphore with initial value +value+. After
|
26
21
|
# {Kernel#fork}, the semaphore will be shared across two (or more)
|
27
22
|
# processes. The semaphore must be closed with {#close} in each
|
data/lib/process_shared/mach.rb
CHANGED
@@ -2,12 +2,15 @@ require 'mach'
|
|
2
2
|
require 'mach/error'
|
3
3
|
|
4
4
|
require 'process_shared/mach'
|
5
|
+
require 'process_shared/open_with_self'
|
6
|
+
require 'process_shared/synchronizable_semaphore'
|
5
7
|
|
6
8
|
module ProcessShared
|
7
9
|
module Mach
|
8
10
|
# Extends ::Mach::Semaphore to be compatible with ProcessShared::Semaphore
|
9
11
|
class Semaphore < ::Mach::Semaphore
|
10
|
-
|
12
|
+
extend ProcessShared::OpenWithSelf
|
13
|
+
include ProcessShared::SynchronizableSemaphore
|
11
14
|
|
12
15
|
def initialize(value = 1)
|
13
16
|
super(:value => value)
|
data/lib/process_shared/mutex.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
require 'process_shared
|
2
|
-
require 'process_shared/
|
3
|
-
require 'process_shared/shared_memory'
|
1
|
+
require 'process_shared'
|
2
|
+
require 'process_shared/open_with_self'
|
4
3
|
require 'process_shared/process_error'
|
5
4
|
|
6
5
|
module ProcessShared
|
@@ -20,11 +19,7 @@ module ProcessShared
|
|
20
19
|
# release its {Semaphore} and {SharedMemory} resources. For now,
|
21
20
|
# rely on the object finalizers of those objects...
|
22
21
|
class Mutex
|
23
|
-
|
24
|
-
|
25
|
-
# def self.open(&block)
|
26
|
-
# new.with_self(&block)
|
27
|
-
# end
|
22
|
+
extend OpenWithSelf
|
28
23
|
|
29
24
|
def initialize
|
30
25
|
@internal_sem = Semaphore.new
|
@@ -1,23 +1,9 @@
|
|
1
|
-
require 'process_shared/with_self'
|
2
1
|
require 'process_shared/shared_memory_io'
|
3
2
|
|
4
3
|
module ProcessShared
|
5
|
-
#
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
class << self
|
10
|
-
attr_accessor :impl
|
11
|
-
|
12
|
-
def new(*args)
|
13
|
-
impl.new(*args)
|
14
|
-
end
|
15
|
-
|
16
|
-
def open(size, &block)
|
17
|
-
new(size).with_self(&block)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
4
|
+
# Provides reading and writing of serialized objects from a memory
|
5
|
+
# buffer.
|
6
|
+
module ObjectBuffer
|
21
7
|
# Write the serialization of +obj+ (using Marshal.dump) to this
|
22
8
|
# shared memory object at +offset+ (in bytes).
|
23
9
|
#
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ProcessShared
|
2
|
+
module OpenWithSelf
|
3
|
+
# Like #new but if the optional code block is given, it will be
|
4
|
+
# passed the new object as an argument, and the object will
|
5
|
+
# automatically be closed (by invoking +close+) when the block
|
6
|
+
# terminates. In this instance, value of the block is returned.
|
7
|
+
def open(*args, &block)
|
8
|
+
obj = new(*args)
|
9
|
+
if block_given?
|
10
|
+
begin
|
11
|
+
yield obj
|
12
|
+
ensure
|
13
|
+
obj.close
|
14
|
+
end
|
15
|
+
else
|
16
|
+
obj
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
|
-
require 'process_shared/
|
1
|
+
require 'process_shared/synchronizable_semaphore'
|
2
|
+
require 'process_shared/open_with_self'
|
2
3
|
|
3
4
|
require 'process_shared/posix/errno'
|
4
5
|
require 'process_shared/posix/libc'
|
@@ -34,8 +35,9 @@ module ProcessShared
|
|
34
35
|
:sem_timedwait)
|
35
36
|
end
|
36
37
|
|
38
|
+
extend ProcessShared::OpenWithSelf
|
37
39
|
include Foreign
|
38
|
-
include ProcessShared::
|
40
|
+
include ProcessShared::SynchronizableSemaphore
|
39
41
|
|
40
42
|
# Make a Proc suitable for use as a finalizer that will call
|
41
43
|
# +shm_unlink+ on +sem+.
|
@@ -2,7 +2,8 @@ require 'ffi'
|
|
2
2
|
|
3
3
|
require 'process_shared/posix/errno'
|
4
4
|
require 'process_shared/posix/libc'
|
5
|
-
require 'process_shared/
|
5
|
+
require 'process_shared/object_buffer'
|
6
|
+
require 'process_shared/open_with_self'
|
6
7
|
|
7
8
|
module ProcessShared
|
8
9
|
module Posix
|
@@ -25,10 +26,10 @@ module ProcessShared
|
|
25
26
|
error_check :shm_open, :shm_unlink
|
26
27
|
end
|
27
28
|
|
29
|
+
extend ProcessShared::OpenWithSelf
|
28
30
|
include SharedMemory::Foreign
|
29
31
|
include LibC
|
30
|
-
|
31
|
-
include ProcessShared::SharedMemory
|
32
|
+
include ProcessShared::ObjectBuffer
|
32
33
|
|
33
34
|
attr_reader :size, :type, :type_size, :count, :fd
|
34
35
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ProcessShared
|
2
|
+
module SynchronizableSemaphore
|
3
|
+
# Yield the block after decrementing the semaphore, ensuring that
|
4
|
+
# the semaphore is incremented.
|
5
|
+
#
|
6
|
+
# @return [Object] the value of the block
|
7
|
+
def synchronize
|
8
|
+
wait
|
9
|
+
begin
|
10
|
+
yield
|
11
|
+
ensure
|
12
|
+
post
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/spec/mach/semaphore_spec.rb
CHANGED
@@ -30,31 +30,41 @@ module Mach
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'coordinates access to shared resource between two tasks' do
|
33
|
-
|
33
|
+
begin
|
34
|
+
sem = Semaphore.new(:value => 0)
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
child = fork do
|
40
|
-
parent_port = Task.self.get_bootstrap_port
|
41
|
-
Task.self.copy_send(parent_port)
|
42
|
-
# parent will copy send rights to sem into child task
|
43
|
-
sleep 0.5
|
44
|
-
sem.signal
|
45
|
-
Kernel.exit!
|
46
|
-
end
|
36
|
+
port = Port.new
|
37
|
+
port.insert_right(:make_send)
|
38
|
+
Task.self.set_bootstrap_port(port)
|
47
39
|
|
48
|
-
|
40
|
+
method = if Process.respond_to?(:__mach_original_fork__)
|
41
|
+
:__mach_original_fork__
|
42
|
+
else
|
43
|
+
:fork
|
44
|
+
end
|
49
45
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
46
|
+
child = Process.send(method) do
|
47
|
+
parent_port = Task.self.get_bootstrap_port
|
48
|
+
Task.self.copy_send(parent_port)
|
49
|
+
# parent will copy send rights to sem into child task
|
50
|
+
sleep 0.5
|
51
|
+
sem.signal
|
52
|
+
Kernel.exit!
|
53
|
+
end
|
54
54
|
|
55
|
-
|
55
|
+
child_task_port = port.receive_right
|
56
56
|
|
57
|
-
|
57
|
+
start = Time.now.to_f
|
58
|
+
sem.insert_right(:copy_send, :ipc_space => child_task_port)
|
59
|
+
sem.timedwait(1)
|
60
|
+
elapsed = Time.now.to_f - start
|
61
|
+
|
62
|
+
Process.wait child
|
63
|
+
|
64
|
+
elapsed.must be_gt(0.4)
|
65
|
+
ensure
|
66
|
+
Task.self.set_bootstrap_port(Mach::Functions.bootstrap_port)
|
67
|
+
end
|
58
68
|
end
|
59
69
|
end
|
60
70
|
end
|
@@ -1,8 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
require 'ffi'
|
4
|
-
require 'process_shared
|
5
|
-
require 'process_shared/shared_memory'
|
4
|
+
require 'process_shared'
|
6
5
|
|
7
6
|
module ProcessShared
|
8
7
|
describe Semaphore do
|
@@ -16,7 +15,7 @@ module ProcessShared
|
|
16
15
|
begin
|
17
16
|
val = mem.get_int(0)
|
18
17
|
# ensure other procs have a chance to interfere
|
19
|
-
sleep 0.
|
18
|
+
sleep 0.002 if rand(50) == 0
|
20
19
|
mem.put_int(0, val + 1)
|
21
20
|
rescue => e
|
22
21
|
"#{Process.pid} die'ing because #{e}"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: process_shared
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-09 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ffi
|
16
|
-
requirement: &
|
16
|
+
requirement: &14966860 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '1.0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *14966860
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake
|
27
|
-
requirement: &
|
27
|
+
requirement: &14906760 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *14906760
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rake-compiler
|
38
|
-
requirement: &
|
38
|
+
requirement: &14905460 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *14905460
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: minitest
|
49
|
-
requirement: &
|
49
|
+
requirement: &14903860 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *14903860
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: minitest-matchers
|
60
|
-
requirement: &
|
60
|
+
requirement: &14897460 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,7 +65,18 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *14897460
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: version
|
71
|
+
requirement: &14854820 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *14854820
|
69
80
|
description: FFI wrapper around portable semaphore library with mutex and condition
|
70
81
|
vars built on top.
|
71
82
|
email: pat@polycrystal.org
|
@@ -88,12 +99,16 @@ files:
|
|
88
99
|
- lib/mach/time_spec.rb
|
89
100
|
- lib/mach/error.rb
|
90
101
|
- lib/mach/port.rb
|
102
|
+
- lib/mach/types.rb
|
91
103
|
- lib/mach/task.rb
|
104
|
+
- lib/process_shared/synchronizable_semaphore.rb
|
92
105
|
- lib/process_shared/abstract_semaphore.rb
|
93
106
|
- lib/process_shared/posix_call.rb
|
94
107
|
- lib/process_shared/mach.rb
|
108
|
+
- lib/process_shared/object_buffer.rb
|
95
109
|
- lib/process_shared/process_error.rb
|
96
110
|
- lib/process_shared/thread.rb
|
111
|
+
- lib/process_shared/open_with_self.rb
|
97
112
|
- lib/process_shared/posix/errno.rb
|
98
113
|
- lib/process_shared/posix/semaphore.rb
|
99
114
|
- lib/process_shared/posix/time_spec.rb
|
@@ -103,16 +118,13 @@ files:
|
|
103
118
|
- lib/process_shared/posix/shared_memory.rb
|
104
119
|
- lib/process_shared/mutex.rb
|
105
120
|
- lib/process_shared/shared_memory_io.rb
|
106
|
-
- lib/process_shared/semaphore.rb
|
107
121
|
- lib/process_shared/time_spec.rb
|
108
122
|
- lib/process_shared/rt.rb
|
109
123
|
- lib/process_shared/mach/semaphore.rb
|
110
124
|
- lib/process_shared/shared_array.rb
|
111
125
|
- lib/process_shared/binary_semaphore.rb
|
112
|
-
- lib/process_shared/with_self.rb
|
113
126
|
- lib/process_shared/define_singleton_method.rb
|
114
127
|
- lib/process_shared/condition_variable.rb
|
115
|
-
- lib/process_shared/shared_memory.rb
|
116
128
|
- ext/pthread_sync_helper/pthread_sync_helper.c
|
117
129
|
- ext/semaphore.c
|
118
130
|
- ext/helper/helper.c
|
@@ -128,7 +140,6 @@ files:
|
|
128
140
|
- spec/process_shared/condition_variable_spec.rb
|
129
141
|
- spec/process_shared/mutex_spec.rb
|
130
142
|
- spec/process_shared/shared_array_spec.rb
|
131
|
-
- spec/process_shared/scratch.rb
|
132
143
|
- spec/process_shared/semaphore_spec.rb
|
133
144
|
- spec/spec_helper.rb
|
134
145
|
- README.rdoc
|
@@ -148,7 +159,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
148
159
|
version: '0'
|
149
160
|
segments:
|
150
161
|
- 0
|
151
|
-
hash:
|
162
|
+
hash: 282066855112542022
|
152
163
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
164
|
none: false
|
154
165
|
requirements:
|
@@ -157,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
168
|
version: '0'
|
158
169
|
segments:
|
159
170
|
- 0
|
160
|
-
hash:
|
171
|
+
hash: 282066855112542022
|
161
172
|
requirements: []
|
162
173
|
rubyforge_project:
|
163
174
|
rubygems_version: 1.8.10
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'process_shared/with_self'
|
2
|
-
|
3
|
-
module ProcessShared
|
4
|
-
module Semaphore
|
5
|
-
include ProcessShared::WithSelf
|
6
|
-
|
7
|
-
class << self
|
8
|
-
# the implementation to use to create semaphores. impl is set
|
9
|
-
# based on the platform in 'process_shared'
|
10
|
-
attr_accessor :impl
|
11
|
-
|
12
|
-
def new(*args)
|
13
|
-
impl.new(*args)
|
14
|
-
end
|
15
|
-
|
16
|
-
# With no associated block, open is a synonym for
|
17
|
-
# Semaphore.new. If the optional code block is given, it will be
|
18
|
-
# passed +sem+ as an argument, and the Semaphore object will
|
19
|
-
# automatically be closed when the block terminates. In this
|
20
|
-
# instance, Semaphore.open returns the value of the block.
|
21
|
-
#
|
22
|
-
# @param [Integer] value the initial semaphore value
|
23
|
-
def open(value = 1, &block)
|
24
|
-
new(value).with_self(&block)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def synchronize
|
29
|
-
wait
|
30
|
-
begin
|
31
|
-
yield
|
32
|
-
ensure
|
33
|
-
post
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module ProcessShared
|
2
|
-
module WithSelf
|
3
|
-
# With no associated block, return self. If the optional code
|
4
|
-
# block is given, it will be passed `self` as an argument, and the
|
5
|
-
# self object will automatically be closed (by invoking +close+ on
|
6
|
-
# +self+) when the block terminates. In this instance, value of
|
7
|
-
# the block is returned.
|
8
|
-
def with_self
|
9
|
-
if block_given?
|
10
|
-
begin
|
11
|
-
yield self
|
12
|
-
ensure
|
13
|
-
self.close
|
14
|
-
end
|
15
|
-
else
|
16
|
-
self
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'process_shared'
|
3
|
-
|
4
|
-
module ProcessShared
|
5
|
-
describe Semaphore2 do
|
6
|
-
it 'does stuff' do
|
7
|
-
sem = Semaphore2.new(0)
|
8
|
-
puts ProcessShared::Mach.shared_ports.inspect
|
9
|
-
fork do
|
10
|
-
puts "child: #{Process.pid}"
|
11
|
-
sleep 2
|
12
|
-
puts "child signaling sem"
|
13
|
-
sem.post
|
14
|
-
end
|
15
|
-
|
16
|
-
puts "parent waiting..."
|
17
|
-
sem.wait
|
18
|
-
puts "parent woke up"
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|