Compare commits

...

10 Commits

Author SHA1 Message Date
邱博亞 857bb2ae85 fix error 2023-04-08 15:22:54 +08:00
Patrick Mahoney 9ef0acb093 Version bump to 0.2.1 2015-06-10 08:32:09 -05:00
Patrick Mahoney 1803466eae Add version range for ci_reporter_minitest. 2015-06-10 08:30:20 -05:00
Patrick Mahoney 2fe552335a Add example to README. 2015-06-10 08:28:09 -05:00
Patrick Mahoney 751a8d0305 Version bump to 0.2.1b 2015-06-09 22:20:41 -05:00
Patrick Mahoney ba45f856ba Update ci_reporter => ci_reporter_minitest. 2015-06-09 22:17:44 -05:00
Patrick Mahoney 1a05bcd924 Find 'helper.so' even when it's in $GEM_HOME/extensions.
See https://github.com/pmahoney/process_shared/issues/4#issuecomment-106777066
2015-06-09 21:54:21 -05:00
Patrick Mahoney 25f9bb2cae Remove Ruby 1.8 special case; reorder requires to suppress warning. 2013-12-31 20:17:15 -06:00
Patrick Mahoney 88dcebf5f7 Fix typo in comment. 2013-12-31 18:25:25 -06:00
Patrick Mahoney 3acc7afc34 Delete obsolete, unused files. 2013-12-31 18:21:04 -06:00
8 changed files with 68 additions and 72 deletions

View File

@ -14,26 +14,57 @@
process_shared
==============
Concurrency primitives that may be used in a cross-process way to
coordinate share memory between processes.
Cross-process concurrency primitives that may be used to coordinate
shared memory between processes.
```ruby
require 'process_shared'
mutex = ProcessShared::Mutex.new
cond = ProcessShared::ConditionVariable.new
mem = ProcessShared::SharedMemory.new(:int32, 2) # extends FFI::Pointer
pid1 = fork do
nums = mutex.synchronize do
cond.wait(mutex)
mem.get_array_of_int(0, 2)
end
puts "process #{Process.pid} received #{nums}"
end
pid2 = fork do
nums = [12345, 67890]
mutex.synchronize do
puts "process #{Process.pid} sending #{nums}"
mem.put_array_of_int(0, nums)
cond.signal
end
end
Process.waitall
```
[API Documentation](http://www.rubydoc.info/github/pmahoney/process_shared/master)
FFI is used to access POSIX semaphore on Linux or Mach semaphores on
Mac. Atop these semaphores are implemented ProcessShared::Semaphore,
ProcessShared::Mutex. POSIX shared memory is used to implement
ProcessShared::SharedMemory.
Mac. Atop these semaphores are implemented `ProcessShared::Semaphore`,
`ProcessShared::Mutex`. POSIX shared memory is used to implement
`ProcessShared::SharedMemory`.
On Linux, POSIX semaphores support `sem_timedwait()` which can wait on
a semaphore but stop waiting after a timeout.
Mac OS X's implementation of POSIX semaphores does not support
timeouts. But, the Mach layer in Mac OS X has its own semaphores that
do support timeouts. Thus, process_shared implements a moderate
subset of the Mach API, which is quite a bit different from POSIX.
Namely, semaphores created in one process are not available in child
processes created via `fork()`. Mach does provide the means to copy
capabilities between tasks (Mach equivalent to processes).
process_shared overrides Ruby's `fork` methods so that semaphores are
copied from parent to child to emulate the POSIX behavior.
timeouts. But, the Mach layer in Mac OS X has its own semaphores that
do support timeouts. Thus, process_shared implements a moderate subset
of the Mach API, which is quite a bit different from POSIX. Namely,
semaphores created in one process are not available in child processes
created via `fork()`. Mach does provide the means to copy capabilities
between tasks (Mach equivalent to processes). In a giant hack, **on OS
X, `process_shared` overrides Ruby's `fork`** methods so that
semaphores are copied from parent to child to emulate the POSIX
behavior.
This is an incomplete work in progress.

View File

@ -1 +1 @@
0.2.1a
0.2.1

View File

@ -15,7 +15,7 @@ module Mach
# Replace methods in +syms+ with error checking wrappers that
# invoke the original method and raise a {SystemCallError}.
#
# The original method is invoked, and it's return value is passed
# The original method is invoked, and its return value is passed
# to the block (or a default check). The block should return true
# if the return value indicates an error state.
def self.error_check(*syms, &is_err)

View File

@ -16,9 +16,26 @@ module ProcessShared
FFI::Platform::LIBSUFFIX
end
ffi_lib File.join(File.expand_path(File.dirname(__FILE__)),
'helper.' + suffix)
# Ruby 2.1 (also 2.0?) puts extensions into, e.g.
# $GEM_HOME/extensions/x86_64-linux/2.1.0/static/$gemname-$gemversion,
# so they aren't in the same dir as this file. Normally that's
# fine since you're just 'require'ing them, but 'helper.so'
# isn't a real Ruby extension; it's just a shared lib to
# export some constants that are only available as macros in
# libc.
#
# Fallback to attempting to load from same directory as this file.
helper = 'process_shared/posix/helper.' + suffix
fallback_path = File.expand_path(File.dirname(__FILE__))
path = $LOAD_PATH.find(fallback_path) do |path|
File.exists?(File.join(path, helper))
end
if defined?(Truffle)
ffi_lib(File.join(::Truffle::Boot.toolchain_paths(:LD_LIBRARY_PATH), 'libgraalvm-llvm.so.1'), File.join(path, helper))
else
ffi_lib File.join(path, helper)
end
[:o_rdwr,
:o_creat,
:o_excl,

View File

@ -1,29 +0,0 @@
# require 'process_shared/libc' - circular dependency here...
module ProcessShared
module PosixCall
# Replace methods in +syms+ with error checking wrappers that
# invoke the original method and raise a {SystemCallError} with
# the current errno if the return value is an error.
#
# Errors are detected if the block returns true when called with
# the original method's return value.
def error_check(*syms, &is_err)
unless block_given?
is_err = lambda { |v| (v == -1) }
end
syms.each do |sym|
method = self.method(sym)
define_singleton_method(sym) do |*args|
ret = method.call(*args)
if is_err.call(ret)
raise SystemCallError.new("error in #{sym}", LibC.errno)
else
ret
end
end
end
end
end
end

View File

@ -1,21 +0,0 @@
require 'process_shared/posix_call'
require 'process_shared/psem'
module ProcessShared
module RT
extend FFI::Library
extend PosixCall
# FIXME: mac and linux OK, but what about everything else?
if FFI::Platform.mac?
ffi_lib 'c'
else
ffi_lib 'rt'
end
attach_function :shm_open, [:string, :int, :mode_t], :int
attach_function :shm_unlink, [:string], :int
error_check :shm_open, :shm_unlink
end
end

View File

@ -14,7 +14,7 @@ Gem::Specification.new do |s|
s.add_dependency('ffi', '~> 1.0')
s.add_development_dependency('ci_reporter')
s.add_development_dependency('ci_reporter_minitest', '~> 1.0')
s.add_development_dependency('flog')
s.add_development_dependency('minitest')
s.add_development_dependency('minitest-matchers')

View File

@ -1,7 +1,5 @@
require 'rubygems' if RUBY_VERSION =~ /^1.8/
gem 'minitest'
require 'minitest/spec'
require 'minitest/autorun'
require 'minitest/spec'
require 'minitest/matchers'
require 'process_shared'