com.lts.ipc.semaphore
Class Semaphore

java.lang.Object
  extended by com.lts.ipc.semaphore.Semaphore

public class Semaphore
extends java.lang.Object

An inter-process, n-ary semaphore.

Description

An instance of this class presents an implementation of a general semaphore that is capable of spanning more than one process. Briefly, a semaphore has an integer value associated with it that is supposed to always be zero or more. Calling the increment method tries to decrease the value by 1, but if the value is already less than 1, the calling process waits until some other process changes the value to 1 or greater before continuing. The increment method increases the semaphore value by 1 and never blocks.

This class was created because standard java does not provide any mechanism for communication between java VMs other than sockets, etc. Those methods are fine, but semaphores, etc. can be hundreds of times faster.

The class uses file naming as explained in the package description. In the case of this class, the file name will refer to an operating system file whose contents are a string that is the numeric "handle" that the system uses to identify the semaphore in system calls.

The class assumes that the primary reason for using this class is speed, and therefore most other issues are ignored in favor of speed. For this reason, some methods that could throw a more descriptive exception, such as increment when the semaphore is not connected, throw things like NullPointerException.

Native Methods

This class uses native methods, specifically the methods defined in the SemaphoreNative class. This is an inherent security issue that really cannot be avoided if clients want to use this class. The name of the library used is defined by com.lts.ipc.semaphore.SemaphoreNative#LIBRARY_NAME. The library is not loaded until an instance of this class actually tries to connect or create an underlying semaphore; so clients have a bit of control over error handling.

Implementation

The implementation of this class depends on the notion that a semaphore can be identified by a long integer "handle." This is the convention used by POSIX and Windows, but if it is not in fact the case for the platform, the class will not function. Of course if this is the case, the native methods should fail to load before a Semaphore can be used, but that's another issue.

Windows will not allow a backslash character in a semaphore name. Thus the name "\temp" will not work, but "temp" will. For that reason, semaphores must use a virtual/actual naming scheme.

The virtual name is the name of a file that contains the actual name. The first process to try and use the semaphore creates the file and populates it with an actual name. Thereafter, processes read the file to determine what the name of the semaphore is.

The current time in milliseconds is used as the actual name. This has a vulnerability in that if there are several threads or processes that are running at roughly the same time, then the same value could be chosen for all of them.

Author:
cnh

Field Summary
protected  long myHandle
          The underlying operating system handle for the semaphore.
 
Constructor Summary
Semaphore()
          Create a semaphore without actually doing anything at the operating system level.
Semaphore(java.lang.String name)
           
Semaphore(java.lang.String name, int initialValue)
          Create a semaphore and attach to the underlying operating system construct.
 
Method Summary
 void connect(java.lang.String name, int initialValue)
          Connect to the underlying semaphore.
 void connect(java.lang.String name, int maxValue, int initialValue)
          Connect to the underlying operating system resource, creating it if it does not exist.
protected  void convertReturnCode(SemaphoreResult result)
           
 boolean decrement()
          Decrement the semaphore by 1, blocking if required.
 boolean decrement(long timeout)
           Try to decrement the semaphore, waiting at least until the specified time to do so if the semaphore is already at 0 or below.
protected static int generateNextActualName()
           
 java.lang.String getActualName()
           
 long getHandle()
           
 void increment()
          Increment the value of the semaphore.
 void setActualName(java.lang.String s)
           
 void setHandle(long handle)
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

myHandle

protected long myHandle
The underlying operating system handle for the semaphore.

Constructor Detail

Semaphore

public Semaphore()
Create a semaphore without actually doing anything at the operating system level.

A call should be made to connect(String, int) before attempting to use other methods, otherwise NullPointerExceptions will be thrown.


Semaphore

public Semaphore(java.lang.String name)
          throws IPCException
Throws:
IPCException

Semaphore

public Semaphore(java.lang.String name,
                 int initialValue)
          throws IPCException
Create a semaphore and attach to the underlying operating system construct.

This method is equivalent to calling the no-arg constructor, followed by calling the connect(String, int) method.

Parameters:
name - The name of the semaphore.
initialValue - The initial value of the semaphore.
Throws:
IPCException
Method Detail

getHandle

public long getHandle()

setHandle

public void setHandle(long handle)

getActualName

public java.lang.String getActualName()

setActualName

public void setActualName(java.lang.String s)

generateNextActualName

protected static int generateNextActualName()

connect

public void connect(java.lang.String name,
                    int maxValue,
                    int initialValue)
             throws IPCException
Connect to the underlying operating system resource, creating it if it does not exist.

Calling this method when the instance is already connected has no effect.

A side effect of this method is that it creates a file whose name is the value of the name parameter. The contents of the file is the actual name of the semaphore that is used when creating the semaphore.

Parameters:
name - The name of the semaphore.
initialValue - The initial value for the semaphore.
Throws:
IPCException

connect

public void connect(java.lang.String name,
                    int initialValue)
             throws IPCException
Connect to the underlying semaphore.

This method will attempt to connect to the underlying semaphore, creating it if it does not exist.

The initialValue parameter is ignored if the semaphore already exists. In the situation where the semaphore is created, the initialValue argument is used to set the starting value

Parameters:
name - The name of the semaphore. See class documentation for details.
initialValue - The initial value for the semaphore if it needs to be created.
Throws:
IPCException - If there is a problem creating the semaphore.

convertReturnCode

protected void convertReturnCode(SemaphoreResult result)

increment

public void increment()
               throws IPCException
Increment the value of the semaphore.

Calling this method when the semaphore is not connected will result in a NullPointerException being thrown.

Throws:
IPCException

decrement

public boolean decrement(long timeout)
                  throws IPCException

Try to decrement the semaphore, waiting at least until the specified time to do so if the semaphore is already at 0 or below.

Note that time is relative to System.nanoTime(). If that method returns a value that is greater than the value passed to us, then the method will not wait for the semaphore to become available.

The method always tries at least once to decrement the semaphore. The only question is whether or not the method will wait if it cannot immediately perform its operation.

Parameters:
stopTime - The time, relative to System.nanoTime(), after which the method will not wait for the semaphore to become available. Passing a negative value will cause the method to wait until the semaphore is available instead of timing out.
Returns:
true if the semaphore was reserved, false if it timed out.
Throws:
IPCException - If the call times out.

decrement

public boolean decrement()
                  throws IPCException
Decrement the semaphore by 1, blocking if required.

This method is equivalent to calling decrement(-1). See that method for details.

Returns:
Whether the drecrement succeeded. This version of the method should always return true.
Throws:
IPCException - If a problem is encountered while trying to perform this operation.