process_shared 0.1.6 → 0.1.7

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.
@@ -1,71 +0,0 @@
1
- module ProcessShared
2
- module Posix
3
- class SharedArray < SharedMemory
4
- include Enumerable
5
-
6
- # A fixed-size array in shared memory. Processes forked from this
7
- # one will be able to read and write shared data to the array.
8
- # Access should be synchronized using a {Mutex}, {Semaphore}, or
9
- # other means.
10
- #
11
- # Note that {Enumerable} methods such as {#map}, {#sort},
12
- # etc. return new {Array} objects rather than modifying the shared
13
- # array.
14
- #
15
- # @param [Symbol] type_or_count the data type as a symbol
16
- # understood by FFI (e.g. :int, :double)
17
- #
18
- # @param [Integer] count number of array elements
19
- def initialize(type_or_count = 1, count = 1)
20
- super(type_or_count, count)
21
-
22
- # See https://github.com/ffi/ffi/issues/118
23
- ffi_type = FFI.find_type(self.type)
24
-
25
- name = if ffi_type.inspect =~ /FFI::Type::Builtin:(\w+)*/
26
- # name will be something like int32
27
- $1.downcase
28
- end
29
-
30
- unless name
31
- raise ArgumentError, "could not find FFI::Type for #{self.type}"
32
- end
33
-
34
- getter = "get_#{name}"
35
- setter = "put_#{name}"
36
-
37
- # singleton class
38
- sclass = class << self; self; end
39
-
40
- unless sclass.method_defined?(getter)
41
- raise ArgumentError, "no element getter for #{self.type} (#{getter})"
42
- end
43
-
44
- unless sclass.method_defined?(setter)
45
- raise ArgumentError, "no element setter for #{self.type} (#{setter})"
46
- end
47
-
48
- sclass.send(:alias_method, :get_type, getter)
49
- sclass.send(:alias_method, :put_type, setter)
50
- end
51
-
52
- def each
53
- # NOTE: using @count because Enumerable defines its own count
54
- # method...
55
- @count.times { |i| yield self[i] }
56
- end
57
-
58
- def each_with_index
59
- @count.times { |i| yield self[i], i }
60
- end
61
-
62
- def [](i)
63
- get_type(i * self.type_size)
64
- end
65
-
66
- def []=(i, val)
67
- put_type(i * self.type_size, val)
68
- end
69
- end
70
- end
71
- end
@@ -1,30 +0,0 @@
1
- module ProcessShared
2
- # API-compatible with Ruby Thread class but using ProcessShared
3
- # primitives instead (i.e. each Thread will be a separate OS
4
- # process).
5
- class Process
6
- class << self
7
- # How the heck will I implement this...
8
- def abort_on_exception
9
- end
10
-
11
- def abort_on_exception=(val)
12
- end
13
-
14
- # This can't really work since each thread is a separate process..
15
- def current
16
- end
17
-
18
- def kill(process)
19
- ::Process.kill(process.pid)
20
- end
21
- end
22
-
23
- def join(limit = nil)
24
- if limit
25
- else
26
- ::Process.wait(pid)
27
- end
28
- end
29
- end
30
- end
data/lib/scratch.rb DELETED
@@ -1,300 +0,0 @@
1
- require 'ffi'
2
-
3
- module LibC
4
- extend FFI::Library
5
-
6
- ffi_lib FFI::Library::LIBC
7
-
8
- attach_variable :errno, :int
9
-
10
- attach_function :mmap, [:pointer, :size_t, :int, :int, :int, :off_t], :pointer
11
- attach_function :munmap, [:pointer, :size_t], :int
12
-
13
- attach_function :ftruncate, [:int, :off_t], :int
14
-
15
- class << self
16
- def call(err_msg = 'error in system call', &block)
17
- ret = yield
18
- err = LibC.errno
19
-
20
- if ret.kind_of?(Fixnum) and ret < 0
21
- raise SystemCallError.new(err_msg, err)
22
- end
23
-
24
- ret
25
- end
26
- end
27
- end
28
-
29
- module RT
30
- extend FFI::Library
31
-
32
- ffi_lib 'rt'
33
-
34
- attach_function :shm_open, [:string, :int, :mode_t], :int
35
- attach_function :shm_unlink, [:string], :int
36
- end
37
-
38
- module PSem
39
- extend FFI::Library
40
-
41
- lib = File.join(File.expand_path(File.dirname(__FILE__)),
42
- 'process_shared/libpsem.' + FFI::Platform::LIBSUFFIX)
43
- ffi_lib lib
44
-
45
- attach_function :psem_alloc, [], :pointer
46
- attach_function :psem_free, [:pointer], :void
47
-
48
- attach_function :psem_open, [:pointer, :string, :uint, :uint], :int
49
- attach_function :psem_close, [:pointer], :int
50
- attach_function :psem_unlink, [:string], :int
51
- attach_function :psem_post, [:pointer], :int
52
- attach_function :psem_wait, [:pointer], :int
53
- attach_function :psem_trywait, [:pointer], :int
54
- attach_function :psem_timedwait, [:pointer, :pointer], :int
55
- attach_function :psem_getvalue, [:pointer, :pointer], :int
56
-
57
- attach_function :bsem_alloc, [], :pointer
58
- attach_function :bsem_free, [:pointer], :void
59
-
60
- attach_function :bsem_open, [:pointer, :string, :uint, :uint], :int
61
- attach_function :bsem_close, [:pointer], :int
62
- attach_function :bsem_unlink, [:string], :int
63
- attach_function :bsem_post, [:pointer], :int
64
- attach_function :bsem_wait, [:pointer], :int
65
- attach_function :bsem_trywait, [:pointer], :int
66
- attach_function :bsem_timedwait, [:pointer, :pointer], :int
67
- attach_function :bsem_getvalue, [:pointer, :pointer], :int
68
-
69
- class << self
70
- include PSem
71
-
72
- def test
73
- bsem = bsem_alloc()
74
-
75
- class << bsem
76
- def value
77
- @int ||= FFI::MemoryPointer.new(:int)
78
- LibC.call { PSem.bsem_getvalue(self, @int) }
79
- @int.get_int(0)
80
- end
81
- end
82
-
83
- puts "alloc'ed at #{bsem.inspect}"
84
- puts LibC.call { bsem_open(bsem, "foobar", 1, 1) }
85
- puts "opened at #{bsem.inspect}"
86
- puts LibC.call { bsem_unlink("foobar") }
87
- puts "unlinked"
88
-
89
- puts "waiting for sem..."
90
- puts "value is #{bsem.value}"
91
- LibC.call { bsem_wait(bsem) }
92
- puts "acquired!"
93
- puts "value is #{bsem.value}"
94
- LibC.call { bsem_post(bsem) }
95
- puts "posted!"
96
- puts "value is #{bsem.value}"
97
-
98
- puts LibC.call { bsem_close(bsem) }
99
- bsem_free(bsem)
100
- end
101
- end
102
- end
103
-
104
- module PThread
105
- extend FFI::Library
106
-
107
- ffi_lib '/lib/x86_64-linux-gnu/libpthread-2.13.so' # 'pthread'
108
-
109
- attach_function :pthread_mutex_init, [:pointer, :pointer], :int
110
- attach_function :pthread_mutex_lock, [:pointer], :int
111
- attach_function :pthread_mutex_trylock, [:pointer], :int
112
- attach_function :pthread_mutex_unlock, [:pointer], :int
113
- attach_function :pthread_mutex_destroy, [:pointer], :int
114
-
115
- attach_function :pthread_mutexattr_init, [:pointer], :int
116
- attach_function :pthread_mutexattr_settype, [:pointer, :int], :int
117
- attach_function :pthread_mutexattr_gettype, [:pointer, :pointer], :int
118
-
119
- attach_function :pthread_mutexattr_setpshared, [:pointer, :int], :int
120
-
121
- class << self
122
- def call(err_msg = 'error in pthreads', &block)
123
- ret = yield
124
- raise SystemCallError.new(err_msg, ret) unless ret == 0
125
- end
126
- end
127
-
128
- module Helper
129
- extend FFI::Library
130
-
131
- # FIXME: this might not alwasy be ".so"
132
- lib = File.join(File.expand_path(File.dirname(__FILE__)), 'pthread_sync_helper.so')
133
- ffi_lib lib
134
-
135
- attach_variable :sizeof_pthread_mutex_t, :size_t
136
- attach_variable :sizeof_pthread_mutexattr_t, :size_t
137
-
138
- attach_variable :o_rdwr, :int
139
- attach_variable :o_creat, :int
140
-
141
- [:pthread_process_shared,
142
-
143
- :o_rdwr,
144
- :o_creat,
145
-
146
- :prot_read,
147
- :prot_write,
148
- :prot_exec,
149
- :prot_none,
150
-
151
- :map_shared,
152
- :map_private].each do |sym|
153
- attach_variable sym, :int
154
- end
155
-
156
- attach_variable :map_failed, :pointer
157
-
158
- PTHREAD_PROCESS_SHARED = pthread_process_shared
159
-
160
- O_RDWR = o_rdwr
161
- O_CREAT = o_creat
162
-
163
- PROT_READ = prot_read
164
- PROT_WRITE = prot_write
165
- PROT_EXEC = prot_exec
166
- PROT_NONE = prot_none
167
-
168
- MAP_FAILED = map_failed
169
- MAP_SHARED = map_shared
170
- MAP_PRIVATE = map_private
171
- end
172
-
173
- class Mutex
174
- include PThread
175
- include PThread::Helper
176
-
177
- class << self
178
- def alloc
179
- FFI::MemoryPointer.new(Helper.sizeof_pthread_mutex_t)
180
- end
181
- end
182
-
183
- def initialize(mutex = Mutex.alloc, attr = nil)
184
- @mutex = mutex
185
- PThread.call { pthread_mutex_init(@mutex, attr) }
186
- end
187
-
188
- def destroy
189
- PThread.call { pthread_mutex_destroy(@mutex) }
190
- end
191
-
192
- def lock
193
- PThread.call { pthread_mutex_lock(@mutex) }
194
- end
195
-
196
- def try_lock
197
- PThread.call { pthread_mutex_trylock(@mutex) }
198
- end
199
-
200
- def unlock
201
- PThread.call { pthread_mutex_unlock(@mutex) }
202
- end
203
- end
204
-
205
- class MutexAttr
206
- include PThread
207
- include PThread::Helper
208
-
209
- class << self
210
- def alloc
211
- FFI::MemoryPointer.new(Helper.sizeof_pthread_mutexattr_t)
212
- end
213
- end
214
-
215
- def initialize(ptr = MutexAttr.alloc)
216
- puts "have #{ptr}"
217
- @ptr = ptr
218
- PThread.call { pthread_mutexattr_init(@ptr) }
219
- self.type = type if type
220
- end
221
-
222
- def pointer
223
- @ptr
224
- end
225
-
226
- def pshared=(val)
227
- PThread.call { pthread_mutexattr_setpshared(@ptr, val) }
228
- end
229
-
230
- def type=(type)
231
- PThread.call { pthread_mutexattr_settype(@ptr, type) }
232
- end
233
-
234
- def type
235
- t = FFI::MemoryPointer.new(:int)
236
- PThread.call { pthread_mutexattr_gettype(@ptr, t) }
237
- t.get_int(0)
238
- end
239
- end
240
-
241
- class Int < FFI::Struct
242
- layout :val => :int
243
- end
244
-
245
- class << self
246
- include Helper
247
-
248
- def test
249
- puts "hi #{Helper.sizeof_pthread_mutex_t}"
250
- puts Mutex.new
251
-
252
-
253
- fd = LibC.call { RT.shm_open("/foo", O_CREAT | O_RDWR, 0777) }
254
- LibC.call { LibC.ftruncate(fd, 100) }
255
- pointer = LibC.mmap(nil, 100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
256
- puts pointer
257
- puts pointer == MAP_FAILED
258
- puts MAP_FAILED
259
-
260
- attr = MutexAttr.new
261
- attr.pshared = PTHREAD_PROCESS_SHARED
262
-
263
- mutex = Mutex.new(pointer, attr.pointer)
264
-
265
-
266
- fd = LibC.call { RT.shm_open("/someint", O_CREAT | O_RDWR, 0777) }
267
- LibC.call { LibC.ftruncate(fd, 100) }
268
- pointer = LibC.mmap(nil, 100, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)
269
- abort "failed" if pointer == MAP_FAILED
270
-
271
- value = Int.new(pointer)
272
- value[:val] = 0
273
- puts "int[0]: #{value[:val]}"
274
-
275
- puts "parent has mutex #{mutex}"
276
-
277
- n = 10000
278
-
279
- child = fork do
280
- puts "child and I have mutex: #{mutex}"
281
-
282
- n.times do |i|
283
- mutex.lock
284
- value[:val] = (value[:val] + 1)
285
- mutex.unlock
286
- end
287
- end
288
-
289
- n.times do |i|
290
- mutex.lock
291
- value[:val] = (value[:val] + 1)
292
- mutex.unlock
293
- end
294
-
295
- Process.wait(child)
296
-
297
- puts "value is now #{value[:val]}"
298
- end
299
- end
300
- end
data/spec/mach/scratch.rb DELETED
@@ -1,67 +0,0 @@
1
- require 'mach'
2
- require 'mach/functions'
3
-
4
- include Mach
5
- include Mach::Functions
6
-
7
- sem = Semaphore.new(:value => 0)
8
-
9
- # puts ">parent has sem #{sem.port}"
10
-
11
- # fork do
12
- # sleep 2 # make parent wait a bit
13
- # puts "in child..."
14
- # sem = Mach::Semaphore.new(:port => Mach::Task.self.get_bootstrap_port)
15
- # puts "child signaling sem #{sem.port}"
16
- # sem.signal
17
- # end
18
-
19
- # puts ">parent waiting on sem..."
20
- # sem.wait
21
- # puts ">parent done waiting!"
22
-
23
- def struct(*layout)
24
- yield FFI::Struct.new(nil, *layout)
25
- end
26
-
27
- puts "sizeof MsgPortDescriptor: #{MsgPortDescriptor.size}"
28
- port = Port.new
29
- port.insert_right(:make_send)
30
-
31
- Task.self.set_bootstrap_port(port)
32
- puts "> self:#{mach_task_self} bootstrap:#{port.port} (#{Mach::Functions::bootstrap_port.to_i})"
33
-
34
- child = fork do
35
- parent_port = Task.self.get_bootstrap_port
36
- puts "in child... self:#{mach_task_self} bootstrap:#{parent_port.port}"
37
-
38
- #port = Port.new
39
- #port.copy_send(parent_port)
40
-
41
- #sem = port.receive_right
42
-
43
- Task.self.copy_send(parent_port)
44
- puts "child sleeping"
45
- sleep 2
46
- puts "child signaling semaphore"
47
- sem.signal
48
- puts "child out"
49
- sleep 2
50
- end
51
-
52
- sleep 0.1
53
- if Process.wait(child, Process::WNOHANG)
54
- puts "child died!"
55
- #exit 1
56
- end
57
-
58
- Task.self.set_bootstrap_port(Mach::Functions::bootstrap_port)
59
- child_task_port = port.receive_right
60
- puts "parent: child task port is #{child_task_port}"
61
-
62
- sem.insert_right(:copy_send, :ipc_space => child_task_port)
63
-
64
- puts "parent waiting"
65
- sem.wait
66
- puts "parent done waiting!"
67
-