process_shared 0.1.0 → 0.1.2
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.
- 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
|