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 process_shared
============== ==============
Concurrency primitives that may be used in a cross-process way to Cross-process concurrency primitives that may be used to coordinate
coordinate share memory between processes. 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 FFI is used to access POSIX semaphore on Linux or Mach semaphores on
Mac. Atop these semaphores are implemented ProcessShared::Semaphore, Mac. Atop these semaphores are implemented `ProcessShared::Semaphore`,
ProcessShared::Mutex. POSIX shared memory is used to implement `ProcessShared::Mutex`. POSIX shared memory is used to implement
ProcessShared::SharedMemory. `ProcessShared::SharedMemory`.
On Linux, POSIX semaphores support `sem_timedwait()` which can wait on On Linux, POSIX semaphores support `sem_timedwait()` which can wait on
a semaphore but stop waiting after a timeout. a semaphore but stop waiting after a timeout.
Mac OS X's implementation of POSIX semaphores does not support 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 timeouts. But, the Mach layer in Mac OS X has its own semaphores that
do support timeouts. Thus, process_shared implements a moderate do support timeouts. Thus, process_shared implements a moderate subset
subset of the Mach API, which is quite a bit different from POSIX. of the Mach API, which is quite a bit different from POSIX. Namely,
Namely, semaphores created in one process are not available in child semaphores created in one process are not available in child processes
processes created via `fork()`. Mach does provide the means to copy created via `fork()`. Mach does provide the means to copy capabilities
capabilities between tasks (Mach equivalent to processes). between tasks (Mach equivalent to processes). In a giant hack, **on OS
process_shared overrides Ruby's `fork` methods so that semaphores are X, `process_shared` overrides Ruby's `fork`** methods so that
copied from parent to child to emulate the POSIX behavior. semaphores are copied from parent to child to emulate the POSIX
behavior.
This is an incomplete work in progress. 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 # Replace methods in +syms+ with error checking wrappers that
# invoke the original method and raise a {SystemCallError}. # 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 # to the block (or a default check). The block should return true
# if the return value indicates an error state. # if the return value indicates an error state.
def self.error_check(*syms, &is_err) def self.error_check(*syms, &is_err)

View File

@ -16,9 +16,26 @@ module ProcessShared
FFI::Platform::LIBSUFFIX FFI::Platform::LIBSUFFIX
end end
ffi_lib File.join(File.expand_path(File.dirname(__FILE__)), # Ruby 2.1 (also 2.0?) puts extensions into, e.g.
'helper.' + suffix) # $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_rdwr,
:o_creat, :o_creat,
:o_excl, :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_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('flog')
s.add_development_dependency('minitest') s.add_development_dependency('minitest')
s.add_development_dependency('minitest-matchers') 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/autorun'
require 'minitest/spec'
require 'minitest/matchers' require 'minitest/matchers'
require 'process_shared' require 'process_shared'