Expand documentation; fix markup.
This commit is contained in:
parent
27e8aeb4c4
commit
d102786090
|
@ -8,17 +8,28 @@ module ProcessShared
|
||||||
include ProcessShared::PSem
|
include ProcessShared::PSem
|
||||||
public
|
public
|
||||||
|
|
||||||
# Generate a name for a semaphore.
|
# Generate a name for a semaphore. If +name+ is given, it is used
|
||||||
|
# as the name (and so a semaphore could be shared by arbitrary
|
||||||
|
# processes not forked from one another). Otherwise, a name is
|
||||||
|
# generated containing +middle+ and the process id.
|
||||||
|
#
|
||||||
|
# @param [String] middle arbitrary string used in the middle
|
||||||
|
# @param [String] name if given, used as the name
|
||||||
|
# @return [String] name, or the generated name
|
||||||
def self.gen_name(middle, name = nil)
|
def self.gen_name(middle, name = nil)
|
||||||
if name
|
if name
|
||||||
name
|
name
|
||||||
else
|
else
|
||||||
@count ||= 0
|
@count ||= 0
|
||||||
@count += 1
|
@count += 1
|
||||||
"ps-#{middle}-#{Process.pid}-#{@count}"
|
"ps-#{middle}-#{::Process.pid}-#{@count}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Make a Proc suitable for use as a finalizer that will call
|
||||||
|
# +psem_unlink+ on +name+ and ignore system errors.
|
||||||
|
#
|
||||||
|
# @return [Proc] a finalizer
|
||||||
def self.make_finalizer(name)
|
def self.make_finalizer(name)
|
||||||
proc { ProcessShared::PSem.psem_unlink(name, nil) }
|
proc { ProcessShared::PSem.psem_unlink(name, nil) }
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,12 +2,15 @@ require 'process_shared/psem'
|
||||||
require 'process_shared/semaphore'
|
require 'process_shared/semaphore'
|
||||||
|
|
||||||
module ProcessShared
|
module ProcessShared
|
||||||
|
# BoundedSemaphore is identical to Semaphore except that its value
|
||||||
|
# is not permitted to rise above a maximum. When the value is at
|
||||||
|
# the maximum, calls to #post will have no effect.
|
||||||
class BoundedSemaphore < Semaphore
|
class BoundedSemaphore < Semaphore
|
||||||
# With no associated block, open is a synonym for
|
# With no associated block, open is a synonym for
|
||||||
# Semaphore.new. If the optional code block is given, it will be
|
# Semaphore.new. If the optional code block is given, it will be
|
||||||
# passed `sem` as an argument, and the Semaphore object will
|
# passed +sem+ as an argument, and the Semaphore object will
|
||||||
# automatically be closed when the block terminates. In this
|
# automatically be closed when the block terminates. In this
|
||||||
# instance, Semaphore.open returns the value of the block.
|
# instance, BoundedSemaphore.open returns the value of the block.
|
||||||
#
|
#
|
||||||
# @param [Integer] value the initial semaphore value
|
# @param [Integer] value the initial semaphore value
|
||||||
# @param [String] name not currently supported
|
# @param [String] name not currently supported
|
||||||
|
@ -15,9 +18,9 @@ module ProcessShared
|
||||||
new(maxvalue, value, name).with_self(&block)
|
new(maxvalue, value, name).with_self(&block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Create a new semaphore with initial value `value`. After
|
# Create a new semaphore with initial value +value+. After
|
||||||
# Kernel#fork, the semaphore will be shared across two (or more)
|
# {Kernel#fork}, the semaphore will be shared across two (or more)
|
||||||
# processes. The semaphore must be closed with #close in each
|
# processes. The semaphore must be closed with {#close} in each
|
||||||
# process that no longer needs the semaphore.
|
# process that no longer needs the semaphore.
|
||||||
#
|
#
|
||||||
# (An object finalizer is registered that will close the semaphore
|
# (An object finalizer is registered that will close the semaphore
|
||||||
|
|
|
@ -4,12 +4,27 @@ require 'process_shared/shared_memory'
|
||||||
require 'process_shared/process_error'
|
require 'process_shared/process_error'
|
||||||
|
|
||||||
module ProcessShared
|
module ProcessShared
|
||||||
|
# This Mutex class is implemented as a BoundedSemaphore with a
|
||||||
|
# maximum value of 1. Additionally, the locking process is tracked,
|
||||||
|
# and {ProcessError} is raised if either {#unlock} is called by a
|
||||||
|
# process different from the locking process, or if {#lock} is
|
||||||
|
# called while the process already holds the lock (i.e. the mutex is
|
||||||
|
# not re-entrant). This tracking is not without performance cost,
|
||||||
|
# of course (current implementation uses an additional
|
||||||
|
# {BoundedSemaphore} and {SharedMemory} segment).
|
||||||
|
#
|
||||||
|
# The API is intended to be identical to the {::Mutex} in the core
|
||||||
|
# Ruby library.
|
||||||
|
#
|
||||||
|
# TODO: the core Ruby api has no #close method, but this Mutex must
|
||||||
|
# release its {BoundedSemaphore} and {SharedMemory} resources. For
|
||||||
|
# now, rely on the object finalizers of those objects...
|
||||||
class Mutex
|
class Mutex
|
||||||
include WithSelf
|
# include WithSelf
|
||||||
|
|
||||||
def self.open(&block)
|
# def self.open(&block)
|
||||||
new.with_self(&block)
|
# new.with_self(&block)
|
||||||
end
|
# end
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@internal_sem = BoundedSemaphore.new(1)
|
@internal_sem = BoundedSemaphore.new(1)
|
||||||
|
@ -73,6 +88,8 @@ module ProcessShared
|
||||||
|
|
||||||
# Acquire the lock, yield the block, then ensure the lock is
|
# Acquire the lock, yield the block, then ensure the lock is
|
||||||
# unlocked.
|
# unlocked.
|
||||||
|
#
|
||||||
|
# @return [Object] the result of the block
|
||||||
def synchronize
|
def synchronize
|
||||||
lock
|
lock
|
||||||
begin
|
begin
|
||||||
|
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
module ProcessShared
|
module ProcessShared
|
||||||
module PosixCall
|
module PosixCall
|
||||||
# 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 with the
|
# invoke the original method and raise a {SystemCallError} with
|
||||||
# current errno if the return value is an error.
|
# the current errno if the return value is an error.
|
||||||
#
|
#
|
||||||
# Errors are detected if the block returns true when called with
|
# Errors are detected if the block returns true when called with
|
||||||
# the original method's return value.
|
# the original method's return value.
|
||||||
|
|
|
@ -5,7 +5,7 @@ module ProcessShared
|
||||||
class Semaphore < AbstractSemaphore
|
class Semaphore < AbstractSemaphore
|
||||||
# With no associated block, open is a synonym for
|
# With no associated block, open is a synonym for
|
||||||
# Semaphore.new. If the optional code block is given, it will be
|
# Semaphore.new. If the optional code block is given, it will be
|
||||||
# passed `sem` as an argument, and the Semaphore object will
|
# passed +sem+ as an argument, and the Semaphore object will
|
||||||
# automatically be closed when the block terminates. In this
|
# automatically be closed when the block terminates. In this
|
||||||
# instance, Semaphore.open returns the value of the block.
|
# instance, Semaphore.open returns the value of the block.
|
||||||
#
|
#
|
||||||
|
@ -15,7 +15,7 @@ module ProcessShared
|
||||||
new(value, name).with_self(&block)
|
new(value, name).with_self(&block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Create a new semaphore with initial value `value`. After
|
# Create a new semaphore with initial value +value+. After
|
||||||
# Kernel#fork, the semaphore will be shared across two (or more)
|
# Kernel#fork, the semaphore will be shared across two (or more)
|
||||||
# processes. The semaphore must be closed with #close in each
|
# processes. The semaphore must be closed with #close in each
|
||||||
# process that no longer needs the semaphore.
|
# process that no longer needs the semaphore.
|
||||||
|
@ -33,7 +33,7 @@ module ProcessShared
|
||||||
end
|
end
|
||||||
|
|
||||||
# Decrement the value of the semaphore. If the value is zero,
|
# Decrement the value of the semaphore. If the value is zero,
|
||||||
# wait until another process increments via #post.
|
# wait until another process increments via {#post}.
|
||||||
def wait
|
def wait
|
||||||
psem_wait(sem, err)
|
psem_wait(sem, err)
|
||||||
end
|
end
|
||||||
|
@ -44,7 +44,8 @@ module ProcessShared
|
||||||
psem_post(sem, err)
|
psem_post(sem, err)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Get the current value of the semaphore.
|
# Get the current value of the semaphore. Raises {Errno::NOTSUP} on
|
||||||
|
# platforms that don't support this (e.g. Mac OS X).
|
||||||
#
|
#
|
||||||
# @return [Integer] the current value of the semaphore.
|
# @return [Integer] the current value of the semaphore.
|
||||||
def value
|
def value
|
||||||
|
@ -53,6 +54,11 @@ module ProcessShared
|
||||||
int.get_int(0)
|
int.get_int(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Release the resources associated with this semaphore. Calls to
|
||||||
|
# other methods are undefined after {#close} has been called.
|
||||||
|
#
|
||||||
|
# Close must be called when the semaphore is no longer needed. An
|
||||||
|
# object finalizer will close the semaphore as a last resort.
|
||||||
def close
|
def close
|
||||||
psem_close(sem, err)
|
psem_close(sem, err)
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,8 +2,8 @@ module ProcessShared
|
||||||
module WithSelf
|
module WithSelf
|
||||||
# With no associated block, return self. If the optional code
|
# With no associated block, return self. If the optional code
|
||||||
# block is given, it will be passed `self` as an argument, and the
|
# block is given, it will be passed `self` as an argument, and the
|
||||||
# self object will automatically be closed (by invoking `close` on
|
# self object will automatically be closed (by invoking +close+ on
|
||||||
# `self`) when the block terminates. In this instance, value of
|
# +self+) when the block terminates. In this instance, value of
|
||||||
# the block is returned.
|
# the block is returned.
|
||||||
def with_self
|
def with_self
|
||||||
if block_given?
|
if block_given?
|
||||||
|
|
Loading…
Reference in New Issue