Author: Philip Semanchuk
Keywords: python sysv system v ipc semaphore shared memory

## System V IPC for Python - Semaphores, Shared Memory and Message Queues

RSS

This describes the `sysv_ipc` module which gives Python access to System V inter-process semaphores, shared memory and message queues on most (all?) *nix flavors. Examples include OS X, Linux, FreeBSD, OpenSolaris 2008.11, and AIX 5.2. It might also work under Windows with a library like Cygwin.

It works with Python 2.4 – 3.x. It's released under a BSD license.

You can download sysv_ipc version 0.6.8 ([md5 sum], [sha1 sum]) which contains the source code, setup.py, installation instructions and sample code. You can read about all of the changes in this version.

You might also want to read about some known bugs.

You might be interested in the very similar module `posix_ipc` which provides Python access to POSIX IPC primitives. POSIX IPC is a little easier to use than SysV IPC, but not all operating systems support it completely.

## Module `sysv_ipc`

Jump to semaphores, shared memory, or message queues.

### Module Functions

attach(id, [address = None, [flags = 0]])
  Attaches the (existing) shared memory that has the given `id` and returns a new SharedMemory object. See SharedMemory.attach() for details on the `address` and `flags` parameters.

  This method is useful only under fairly unusual circumstances. You probably don't need it.

ftok(path, id, [silence_warning = False])
  Calls `ftok(path, id)`. Note that `ftok()` has limitations, and this function will issue a warning to that effect unless `silence_warning` is True.
remove_semaphore(id)
  Removes the semaphore with the given `id`.
remove_shared_memory(id)
  Removes the shared memory with the given `id`.
remove_message_queue(id)
  Removes the message queue with the given `id`.

### Module Constants

IPC_CREAT, IPC_EXCL and IPC_CREX
  `IPC_CREAT` and `IPC_EXCL` are flags used when creating IPC objects. They're bitwise unique and can be ORed together. `IPC_CREX` is shorthand for `IPC_CREAT | IPC_EXCL`.

  When passed to an IPC object's constructor, `IPC_CREAT` indicates that you want to create a new object or open an existing one. If you want the call to fail if an object with that key already exists, specify the `IPC_EXCL` flag, too.

IPC_PRIVATE
  This is a special value that can be passed in place of a key. It implies that the IPC object should be available only to the creating process or its child processes (e.g. those created with `fork()`).
KEY_MIN and KEY_MAX
  Denote the range of keys that this module accepts. Your OS might limit keys to a smaller range depending on the typedef of `key_t`.

  Keys randomly generated by this module are in the range `1 <e; key <e; SHRT_MAX`. That's type-safe unless your OS has a very bizarre definition of `key_t`.

SEMAPHORE_VALUE_MAX
  The maximum value of a semaphore.
PAGE_SIZE
  The operating system's memory page size, in bytes. It's probably a good idea to make shared memory segments some multiple of this size.
SEMAPHORE_TIMEOUT_SUPPORTED
  True if the platform supports timed semaphore waits, False otherwise.
SHM_RND
  You probably don't need this, but it can be used when attaching shared memory to force the address to be rounded down to SHMLBA. See your system's man page for `shmat()` for more information.
SHM_HUGETLB, SHM_NORESERVE and SHM_REMAP
  You probably don't need these. They're Linux-specific flags that can be passed to the SharedMemory constructor, or to the `.attach()` function in the case of SHM_REMAP. See your system's man page for `shmget()` and `shmat()` for more information.

### Module Errors

In addition to standard Python errors (e.g. `ValueError`), this module raises custom errors. These errors cover situations specific to IPC.

Error
  The base error class for all the custom errors in this module. This error is occasionally raised on its own but you'll almost always see a more specific error.
InternalError
  Indicates that something has gone very wrong in the module code. Please report this to the maintainer.
PermissionsError
  Indicates that you've attempted something that the permissions on the IPC object don't allow.
ExistentialError
  Indicates an error related to the existence or non-existence of an IPC object.
BusyError
  Raised when a semaphore call to `.P()` or `.Z()` either times out or would be forced to wait when its `block` attribute is False.
NotAttachedError
  Raised when a process attempts to read from or write to a shared memory segment to which it is not attached.

### The Semaphore Class

This is a handle to a semaphore.

#### Methods

Semaphore(key, [flags = 0, [mode = 0600, [initial_value = 0]]])
  Creates a new semaphore or opens an existing one.

  key must be `None`, `IPC_PRIVATE` or an integer > `KEY_MIN` and ≤ `KEY_MAX`. If the key is `None`, the module chooses a random unused key.

  The flags specify whether you want to create a new semaphore or open an existing one.

  - With flags set to the default of `0`, the module attempts to open an existing semaphore identified by key and raises a `ExistentialError` if that semaphore doesn't exist.
  - With flags set to `IPC_CREAT`, the module opens the semaphore identified by key or creates a new one if no such semaphore exists. Using `IPC_CREAT` by itself is not recommended. (See Semaphore Initialization.)
  - With flags set to `IPC_CREX` (`IPC_CREAT | IPC_EXCL`), the module creates a new semaphore identified by key. If a semaphore with that key already exists, the call raises an `ExistentialError`. The initial_value is ignored unless both of these flags are specified or if the semaphore is read-only.

  When opening an existing semaphore, mode is ignored.

acquire([timeout = None, [delta = 1]])
  Waits (conditionally) until the semaphore's value is > 0 and then returns, decrementing the semaphore.

  The timeout (which can be a float) specifies how many seconds this call should wait, if at all.

  The semantics of the timeout changed a little in version 0.3.

  - A timeout of None (the default) implies no time limit. The call will not return until its wait condition is satisfied.
  - When timeout is 0, the call raises a `BusyError` if it can't immediately acquire the semaphore. Since it will return immediately if not asked to wait, this can be thought of as "non-blocking" mode.
  - When the timeout is > 0, the call will wait no longer than timeout seconds before either returning (having acquired the semaphore) or raising a `BusyError`.

  When the call returns, the semaphore's value decreases by delta (or more precisely, `abs(delta)`) which defaults to 1.

  On platforms that don't support the `semtimedop()` API call, all timeouts (including zero) are treated as infinite. The call will not return until its wait condition is satisfied.

  Most platforms provide `semtimedop()`. OS X is a notable exception. The module's Boolean constant `SEMAPHORE_TIMEOUT_SUPPORTED` is True on platforms that support `semtimedop()`.

release([delta = 1])
  Releases (increments) the semaphore.

  The semaphore's value increases by delta (or more precisely, `abs(delta)`) which defaults to 1.

P()
  A synonym for `.acquire()` that takes the same parameters.

  "P" stands for prolaag or probeer te verlagen (try to decrease), the original name given by Edsger Dijkstra.

V()
  A synonym for `.release()` that takes the same parameters.

  "V" stands for verhoog (increase), the original name given by Edsger Dijkstra.

Z([timeout = None])
  Blocks until zee zemaphore is zero.

  Timeout has the same meaning as described in `.acquire()`.

remove()
  Removes (deletes) the semaphore from the system.

  As far as I can tell, the effect of deleting a semaphore that other processes are still using is OS-dependent. Check your system's man pages for `semctl(IPC_RMID)`.

#### Attributes

key (read-only)
  The key passed in the call to the constructor.
id (read-only)
  The id assigned to this semaphore by the OS.
value
  The integer value of the semaphore.
undo
  Defaults to False.

  When True, operations that change the semaphore's value will be undone (reversed) when the process exits. Note that when a process exits, an undo operation may imply that a semaphore's value should become negative or exceed its maximum. Behavior in this case is system-dependent, which means that using this flag can make your code non-portable.

block
  Defaults to True, which means that calls to `acquire()` and `release()` will not return until their wait conditions are satisfied.

  When False, these calls will not block but will instead raise an error if they are unable to return immediately.

mode
  The semaphore's permission bits.

  Tip: the following Python code will display the mode in octal:
  `print int(str(my_sem.mode), 8)`

uid
  The semaphore's user id.
gid
  The semaphore's group id.
cuid (read-only)
  The semaphore creator's user id.
cgid (read-only)
  The semaphore creator's group id.
last_pid (read-only)
  The PID of the process that last called `semop()` (`.P()`, `.V()` or `.Z()`) on this semaphore.
waiting_for_nonzero (read-only)
  The number of processes waiting for the value of the semaphore to become non-zero (i.e. the number waiting in a call to `.P()`).
waiting_for_zero (read-only)
  The number of processes waiting for the value of the semaphore to become zero (i.e. the number waiting in a call to `.Z()`).
o_time (read-only)
  The last time `semop()` (i.e. `.P()`, `.V()` or `.Z()`) was called on this semaphore.

#### Context Manager Support

These semaphores provide `__enter__()` and `__exit__()` methods so they can be used in context managers. For instance --

    with sysv_ipc.Semaphore(name) as sem:
        # Do something...

Entering the context acquires the semaphore, exiting the context releases the semaphore. See `demo4/child.py` for a complete example.

### The SharedMemory Class

This is a handle to a shared memory segment.

#### Methods

SharedMemory(key, [flags = 0, [mode = 0600, [size = 0 or PAGE_SIZE, [init_character = ' ']]]])
  Creates a new shared memory segment or opens an existing one. The memory is automatically attached.

  key must be `None`, `IPC_PRIVATE` or an integer > `0` and ≤ `KEY_MAX`. If the key is `None`, the module chooses a random unused key.

  The flags specify whether you want to create a new shared memory segment or open an existing one.

  - With flags set to the default of `0`, the module attempts to open an existing shared memory segment identified by key and raises a `ExistentialError` if it doesn't exist.
  - With flags set to `IPC_CREAT`, the module opens the shared memory segment identified by key or creates a new one if no such segment exists. Using `IPC_CREAT` by itself is not recommended. (See Memory Initialization.)
  - With flags set to `IPC_CREX` (`IPC_CREAT | IPC_EXCL`), the module creates a new shared memory segment identified by key. If a segment with that key already exists, the call raises a `ExistentialError`.

    When both `IPC_CREX` is specified and the caller has write permission, each byte in the new memory segment will be initialized to the value of init_character.

  The value of size depends on whether one is opening an existing segment or creating a new one.

  - When opening an existing segment, size must be ≤ the existing segment's size. Zero is always valid.
  - When creating an new segment, many (most? all?) operating systems insist on a size > `0`. In addition, some round the size up to the next multiple of PAGE_SIZE.

  This module supplies a default size of `PAGE_SIZE` when `IPC_CREX` is specified and `0` otherwise.

attach([address = None, [flags = 0]])
  Attaches this process to the shared memory. The memory must be attached before calling `.read()` or `.write()`. Note that the constructor automatically attaches the memory so you won't need to call this method unless you explicitly detach it and then want to use it again.

  The address parameter allows one to specify (as a Python long) a memory address at which to attach the segment. Passing None (the default) is equivalent to passing NULL to `shmat()`. See that function's man page for details.

  The flags are mostly only relevant if one specifies a specific address. One exception is the flag `SHM_RDONLY` which, surprisingly, attaches the segment read-only.

  Note that on some (and perhaps all) platforms, each call to `.attach()` increments the system's "attached" count. Thus, if each call to `.attach()` isn't paired with a call to `.detach()`, the system's "attached" count for the shared memory segment will not go to zero when the process exits. As a result, the shared memory segment may not disappear even when its creator calls `.remove()` and exits.

detach()
  Detaches this process from the shared memory.
read([byte_count = 0, [offset = 0]])
  Reads up to byte_count bytes from the shared memory segment starting at offset and returns them as a string under Python 2 or as a bytes object under Python 3.

  If byte_count is zero (the default) the entire buffer is returned.

  This method will never attempt to read past the end of the shared memory segment, even when offset + byte_count exceeds the memory segment's size. In that case, the bytes from offset to the end of the segment are returned.

write(s, [offset = 0])
  Writes the string s to the shared memory, starting at offset.

  At most `n` bytes will be written, where `n` = the segment's size minus offset.

  The string may contain embedded NULL bytes ('\0').

remove()
  Removes (destroys) the shared memory. Note that actual destruction of the segment only occurs when all processes have detached.

#### Attributes

key (read-only)
  The key provided in the constructor.
id (read-only)
  The id assigned to this semaphore by the OS.
size (read-only)
  The size of the segment in bytes.
address (read-only)
  The address of the segment as Python long.
attached (read-only)
  If True, this segment is currently attached.
last_attach_time (read-only)
  The last time a process attached this segment.
last_detach_time (read-only)
  The last time a process detached this segment.
last_change_time (read-only)
  The last time a process changed the uid, gid or mode on this segment.
creator_pid (read-only)
  The PID of the process that created this segment.
last_pid (read-only)
  The PID of the most last process to attach or detach this segment.
number_attached (read-only)
  The number of processes attached to this segment.
uid
  The segment's user id.
gid
  The segment's group id.
mode
  The shared memory's permission bits.

  Tip: the following Python code will display the mode in octal:
  `print int(str(my_mem.mode), 8)`

cuid (read-only)
  The segment creator's user id.
cgid (read-only)
  The segment creator's group id.

### The MessageQueue Class

This is a handle to a message queue.

#### Methods

MessageQueue(key, [flags = 0, [mode = 0600, [max_message_size = 2048]]])
  Creates a new message queue or opens an existing one.

  key must be `None`, `IPC_PRIVATE` or an integer > `0` and ≤ `KEY_MAX`. If the key is `None`, the module chooses a random unused key.

  The flags specify whether you want to create a new queue or open an existing one.

  - With flags set to the default of `0`, the module attempts to open an existing message queue identified by key and raises a `ExistentialError` if it doesn't exist.
  - With flags set to `IPC_CREAT`, the module opens the message queue identified by key or creates a new one if no such queue exists.
  - With flags set to `IPC_CREX` (`IPC_CREAT | IPC_EXCL`), the module creates a new message queue identified by key. If a queue with that key already exists, the call raises a `ExistentialError`.

  The max_message_size can be increased from the default, but be aware of the issues discussed in Message Queue Limits.

send(message, [block = True, [type = 1]])
  Puts a message on the queue.

  The message string can contain embedded NULLs (ASCII `0x00`).

  The block flag specifies whether or not the call should wait if the message can't be sent (if, for example, the queue is full). When block is `False`, the call will raise a `BusyError` if the message can't be sent immediately.

  The type is associated with the message and is relevant when calling `receive()`. It must be > 0.

receive([block = True, [type = 0]])
  Receives a message from the queue, returning a tuple of `(message, type)`. Under Python 3, the message is a bytes object.

  The block flag specifies whether or not the call should wait if there's no messages of the specified type to retrieve. When block is `False`, the call will raise a `BusyError` if a message can't be received immediately.

  The type permits some control over which messages are retrieved.

  - When type `== 0`, the call returns the first message on the queue regardless of its type.
  - When type `> 0`, the call returns the first message of that type.
  - When type `< 0`, the call returns the first message of the lowest type that is ≤ the absolute value of type.
remove()
  Removes (deletes) the message queue.

#### Attributes

key (read-only)
  The key provided in the constructor.
id (read-only)
  The id assigned to this queue by the OS.
max_size
  The maximum size of the queue in bytes. Only a process with "appropriate privileges" can increase this value, and on some systems even that won't work. See Message Queue Limits for details.
last_send_time (read-only)
  The last time a message was placed on the queue.
last_receive_time (read-only)
  The last time a message was received from the queue.
last_change_time (read-only)
  The last time a process changed the queue's attributes.
last_send_pid (read-only)
  The id of the most recent process to send a message.
last_receive_pid (read-only)
  The id of the most recent process to receive a message.
current_messages (read-only)
  The number of messages currently in the queue.
uid
  The queue's user id.
gid
  The queue's group id.
mode
  The queue's permission bits.

  Tip: the following Python code will display the mode in octal:
  `print int(str(my_mem.mode), 8)`

cuid (read-only)
  The queue creator's user id.
cgid (read-only)
  The queue creator's group id.

### Supported Features and Differences from SHM

This module is almost, but not quite, a superset of `shm`. Some of the additional features are the ability to override the `block` flag on a per-call basis, the ability to change the semaphore's value in increments > 1 when calling `.P()` and `.V()` and exposure of `sem_otime`.

Differences that might trip you up are listed below.

- `Shm` compiles under Python 2.3 and older; this module has not been tested with Python older than 2.4
- Attribute names and method signatures are different.
- This module offers neither the functions `semaphore_haskey()` nor `memory_haskey()`.
- This module's default permission on objects is `0600` as opposed to `shm`'s `0666`.
- `Shm` maintained an internal dictionary of semaphores and shared memory segments. The object keys served as the dictionary keys. If you asked for the same object multiple times, `shm` would return the same Python object. I'm not convinced this was safe, particularly in the case where an object may have been destroyed and another with the same key created in its place.

### Usage Tips

#### Sample Code

This module comes with two demonstration apps. The first (in the directory `demo`) shows how to use shared memory and semaphores. The second (in the directory `demo2`) shows how to use message queues.

#### The Weakness of `ftok()`

Most System V IPC sample code recommends `ftok()` for generating an integer key that's more-or-less random. It does not, however, guarantee that the key it generates is unused. If `ftok()` gives your application a key that some other application is already using, your app is in trouble unless it has a reliable second mechanism for generating a key. And if that's the case, why not just abandon `ftok()` and use the second mechanism exclusively?

This is the weakness of `ftok()` -- it isn't guaranteed to give you what you want. The BSD man page for `ftok` says it is "quite possible for the routine to return duplicate keys". The term "quite possible" isn't quantified, but suppose it means one-tenth of one percent. Who wants to have 1-in-1000 odds of a catastrophic failure in their program, or even 1-in-10000?

This module obviates the need for `ftok()` by generating random keys for you. If your application can't use `sysv_ipc`'s automatically generated keys because it needs to know the key in advance, hardcoding a random number like 123456 in your app might be no worse than using `ftok()` and has the advantage of not hiding its limitations.

This module provides `ftok()` in case you want to experiment with it. However, to emphasize its weakness, this version of `ftok()` raises a warning with every call unless you explicitly pass a flag to silence it.

This package also provides `ftok_experiment.py` so that you can observe how often `ftok()` generates duplicate keys on your system.

#### Semaphore Initialization

When a System V sempahore is created at the C API level, the OS is not required to initialize the semaphore's value. (This per the SUSv3 standard for `semget()`.) Some (most? all?) operating systems initialize it to zero, but this behavior is non-standard and therefore can't be relied upon.

If sempahore creation happens in an predictable, orderly fashion, this isn't a problem. But a race condition arises when multiple processes vie to create/open the same semaphore. The problem lies in the fact that when an application calls `semget()` with only the `IPC_CREAT` flag, the caller can't tell whether or not he has created a new semaphore or opened an existing one. This makes it difficult to create reliable code without using `IPC_EXCL`. W. Richard Stevens' Unix Network Programming Volume 2 calls this "a fatal flaw in the design of System V semaphores" (p 284).

For instance, imagine processes P1 and P2. They're executing the same code, and that code intends to share a binary semaphore. Consider the following sequence of events at the startup of P1 and P2 –

1. P1 calls `semget(IPC_CREAT)` to create the semaphore S.
2. P2 calls `semget(IPC_CREAT)` to open S.
3. P1 initializes the semaphore's value to 1.
4. P1 calls `acquire()`, decrementing the value to 0.
5. P2, assuming S is a newly-created semaphore that needs to be initialized, incorrectly sets the semaphore's value to 1.
6. P2 calls `acquire()`, decrementing the value to 0. Both processes now think they own the lock.

W. Richard Stevens' solution for this race condition is to check the value of `sem_otime` (an element in the `semid_ds` struct that's populated on the call to `semctl(IPC_STAT)` and which is exposed to Python by this module) which is initialized to zero when the semaphore is created and otherwise holds the time of the last call to `semop()` (which is called by `P()`/`acquire()`, `V()`/`release()`, and `Z()`).

In Python, each process would run something like this:

    try:
        sem = sysv_ipc.Semaphore(42, sysv_ipc.IPC_CREX)
    except sysv_ipc.ExistentialError:
        # One of my peers created the semaphore already
        sem = sysv_ipc.Semaphore(42)
        # Waiting for that peer to do the first acquire or release
        while not sem.o_time:
            time.sleep(.1)
    else:
        # Initializing sem.o_time to nonzero value
        sem.release()
    # Now the semaphore is safe to use.

#### Shared Memory Initialization

With shared memory, using the `IPC_CREAT` flag without `IPC_EXCL` is problematic unless you know the size of the segment you're potentially opening.

Why? Because when creating a new segment, many (most? all?) operating systems demand a non-zero size. However, when opening an existing segment, zero is the only guaranteed safe value (again, assuming one doesn't know the size of the segment in advance). Since `IPC_CREAT` can open or create a segment, there's no safe value for the size under this circumstance.

As a (sort of) side note, the SUSv3 specification for `shmget()` says only that the size of a new segment must not be less than "the system-imposed minimum". I gather that at one time, some systems set the minimum at zero despite the fact that it doesn't make much sense to create a zero-length shared memory segment. I think most modern systems do the sensible thing and insist on a minimum length of 1.

#### Message Queue Limits

Python programmers can usually remain blissfully ignorant of memory allocation issues. Unfortunately, a combination of factors makes them relevant when dealing with System V message queues.

Some implementations impose extremely stingy limits. For instance, many BSDish systems (OS X, FreeBSD, NetBSD, and OpenBSD) limit queues to 2048 bytes. Note that that's the total queue size, not the message size. Two 1k messages would fill the queue.

Those limits can be very difficult to change. At best, only privileged processes can increase the limit. At worst, the limit is a kernel parameter and requires a kernel change via a tunable or a recompile.

This module can't figure out what the limits are, so it can't cushion them or even report them to you. On some systems the limits are expressed in header files, on others they're available through kernel interfaces (like FreeBSD's `sysctl`). Under OS X and to some extent OpenSolaris I can't figure out where they're defined and what I report here is the result of experimentation and educated guesses formed by Googling.

The good news is that this module will still behave as advertised no matter what these limits are. Nevertheless you might be surprised when a call to `.send()` get stuck because a queue is full even though you've only put 2048 bytes of messages in it.

Here are the limits I've been able to find under my test operating systems, ordered from best (most generous) to worst (most stingy). This information was current as of 2009 when I wrote the message queue code. It's getting pretty stale now. I hope the situation has improved over the 2009 numbers I describe below.

Under OpenSolaris 2008.05 each queue's maximum size defaults to 64k. A privileged process (e.g. root) can change this through the `max_size` attribute of a `sysv_ipc.MessageQueue` object. I was able to increase it to 16M and successfully sent sixteen 1M messages to the queue.

Under Ubuntu 8.04 (and perhaps other Linuxes) each queue's maximum size defaults to 16k. As with OpenSolaris, I was able to increase this to 16M, but only for a privileged process.

Under FreeBSD 7 and I think NetBSD and OpenBSD, each queue's maximum size defaults to 2048 bytes. Furthermore, one can (as root) set `max_size` to something larger and FreeBSD doesn't complain, but it also ignores the change.

OS X is the worst of the lot. Each queue is limited to 2048 bytes and OS X silently ignores attempts to increase this (just like FreeBSD). To add insult to injury, there appears to be no way to increase this limit short of recompiling the kernel. I'm guessing at this based on the Darwin message queue limits.

If you want to search for these limits on your operating system, the key constants are `MSGSEG`, `MSGSSZ`, `MSGTQL`, `MSGMNB`, `MSGMNI` and `MSGMAX`. Under BSD, `sysctl kern.ipc` should tell you what you need to know and may allow you to change these parameters.

#### Nobody Likes a Mr. Messy

Semaphores and especially shared memory are a little different from most Python objects and therefore require a little more care on the part of the programmer. When a program creates a semaphore or shared memory object, it creates something that resides outside of its own process, just like a file on a hard drive. It won't go away when your process ends unless you explicitly remove it.

In short, remember to clean up after yourself.

#### Consult Your Local `man` Pages

The sysv_ipc module is just a wrapper around your system's API. If your system's implementation has quirks, the `man` pages for `semget, semctl, semop shmget, shmat, shmdt` and `shmctl` will probably cover them.

#### Interesting Tools

Many systems (although not some older versions of OS X) come with `ipcs` and `ipcrm`. The former shows existing shared memory, semaphores and message queues on your system and the latter allows you to remove them.

#### Last But Not Least

For Pythonistas –

- A meditation on the inaccuracy of shared memories

### Known Bugs

Bugs? My code never has bugs! There are, however, some suboptimal anomalies...

- Under OS X, `sys/ipc.h` defines two versions of the `ipc_perm` struct. This module picks up the old, deprecated one which stores uid and gid values in 16 bit types. It's definitions in `Python.h` that cause this, though, so there's not much I can do to change it.
- This module can't report the exact min and max values for a key. It turns out that it's really difficult to determine the maximum value that a typedef-ed variable can hold.

### Version History

- Current – 0.6.8 (12 Sept 2014) –
  - Fixed a bug in `prober.py` where prober would fail on systems where Python's include file was not named `pyconfig.h`. (RHEL 6 is one such system.) Thanks to Joshua Harlow for the bug report and patch.
  - Spasibo again to Yuriy Taraday for pointing out that the semaphore initialization example I changed in the previous version was still not quite correct, and for suggesting something better.
- 0.6.7 (1 August 2014) –

  Spasibo to Yuriy Taraday for reporting some doc errors corrected in this version.

  - Added KEY_MIN as a module-level constant. The documentation has claimed that it was available for a long time so now the code finally matches the documentation.
  - Changed randomly generated keys to never use a value of 0.
  - Fixed two documenation errors in the special section on semaphore initialization and gave long overdue credit to W. Richard Stevens' book for the code idea. (Any code mistakes are mine, not his.)
  - This is the first version downloadable from PyPI.
- 0.6.6 (15 October 2013) –

  Added the ability to use Semaphores in context managers. Thanks to Matt Ruffalo for the suggestion and patch.

- 0.6.5 (31 March 2013) –

  Fixed a bug where SharedMemory.write() claimed to accept keyword arguments but didn't actually do so. Thanks to Matt Ruffalo for the bug report and patch.

- 0.6.4 (19 Dec 2012) –
  - Added a module-level `attach()` method based on a suggestion by Vladimír Včelák.
  - Added the `ftok()` method along with dire warnings about its use.
- 0.6.3 (3 Oct 2010) –
  - Fixed a segfault in `write()` that occurred any time an offset was passed. This was introduced in v0.6.0. Tack to Johan Bernhardtson for the bug report.
- 0.6.2 (6 July 2010) –
  - Updated setup.py metadata to reflect Python 3 compatibility. No functional change.
- 0.6.1 (26 June 2010) –
  - Fixed a typo introduced in the previous version that caused unpredictable behavior (usually a segfault) if a block flag was passed to `MessageQueue.send()`. Obrigado to Álvaro Justen and Ronald Kaiser for the bug report and patch.
- 0.6.0 (20 May 2010) –
  - Added Python 3 support.
  - Renamed a constant that caused a problem under AIX. Thanks to Loic Nageleisen for the bug report.
  - Updated this documentation a little.
- 0.5.2 (17 Jan 2010)
  - Fixed a bug that insisted on keys > 0. Thanks to 原志 (Daniel) for the bug report and patch.
  - Fixed a bug where the module could have generated invalid keys on systems that typedef `key_t` as a `short`. I don't think such a system exists, though.
  - Fixed a LICENSE file typo.
  - Added an RSS feed to this page.
- 0.5.1 (1 Dec 2009) –

  No code changes in this version.

  - Fixed the comment in `sysv_ipc_module.c` that still referred to the GPL license.
  - Added the attributes `__version`, `__author__`, `__license__` and `__copyright__`.
  - Removed `file()` from `setup.py` in favor of `open()`.
- 0.5 (6 Oct 2009) –

  No code changes in this version.

  - Changed the license from GPL to BSD.
- 0.4.2 (22 Mar 2009) –

  No code changes in this version.

  - Fixed broken documentation links to youtube.
  - Fixed the project name in the LICENSE file.
- 0.4.1 (12 Feb 2009) –
  - Changed status to beta.
  - Added automatic generation of keys.
  - Added a message queue demo.
  - Added `str()` and `repr()` support to all objects.
  - Fixed a bug in `SharedMemory.write()` that could cause a spurious error of "Attempt to write past end of memory segment". This bug only occurred on platforms using different sizes for `long` and `int`, or `long` and `py_size_t` (depending on Python version). Tack to Jesper for debug help.
  - Plugged a memory leak in `MessageQueue.receive()`.
  - Added a VERSION attribute to the module.
- 0.4 (28 Jan 2009) –
  - Added message queues.
  - Fixed a bug where the `key` attribute of SharedMemory objects returned garbage.
  - Fixed a bug where keys > INT_MAX would get truncated on platforms where longs are bigger than ints.
  - Provided decent inline documentation for object attributes (available via the `help()` command).
  - Rearranged the code which was suffering growing pains.
- 0.3 (16 Jan 2009) –

  This version features a rename of classes and errors (sorry about breaking the names), some modifications to semaphore timeouts, and many small fixes.

  A semaphore's `.block` flag now consistently trumps the timeout. When `False`, the timeout is irrelevant -- calls will never block. In prior versions, the flag was ignored when the timeout was non-zero.

  Also, on platforms (such as OS X) where `semtimedop()` is not supported, all timeouts are now treated as `None`. In other words, when `.block` is True, all calls wait as long as necessary.

  Other fixes –

  - Fixed the poor choices I'd made for class and error names by removing the leading "SysV" and "SysVIpc".
  - Removed dependencies on Python 2.5. The module now works with Python 2.4.4 and perhaps earlier versions.
  - Fixed a bug where I was not following SysV semaphore semantics for interaction between timeouts and the block flag.
  - Fixed compile problems on OpenSolaris 2008.05.
  - Got rid of OS X compile warnings.
  - Fixed many instances where I was making potentially lossy conversions between Python values and Unix-specific types like `key_t`, `pid_t`, etc.
  - Fixed a bug in the SharedMemory `attach()` function that would set an error string but not return an error value if the passed address was not `None` or a long.
  - Simplified the code a little.
  - Restricted the semaphore `acquire()` and `release()` delta to be between SHORT_MIN and SHORT_MAX since it is a short in the SUSv2 spec.
  - Fixed a bug where calling `acquire()` or `release()` with a delta of `0` would call `.Z()` instead.
  - Disallowed byte counts ≤ `0` in `SharedMemory.read()`
  - Fixed a bug in the `SharedMemory` init code that could, under vanishingly rare circumstances, return failure without setting the error code.
  - Removed some dead code relating to the `.seq` member of the `sem_perm` and `shm_perm` structs.
  - Stopped accessing the non-standard `key` (a.k.a. `_key` and `__key`) element of the `ipc_perm` struct.
  - Added code to ensure the module doesn't try to create a string that's larger than Python permits when reading from shared memory.
- 0.2.1 (3 Jan 2009) –
  - Fixed a bug that prevented the module-specific errors (`ExistentialError`, etc.) from being visible in the module.
  - Fixed a bug that re-initialized shared memory with the init character when only `IPC_CREAT` was specified and an existing segment was opened.
  - Fixed a bug that always defaulted the size of a shared memory segment to `PAGE_SIZE`. Updated code and documentation to use intelligent defaults. Tack to Jesper for the bug report.
  - Several cosmetic changes. (Added more metadata to setup.py, added a newline to the end of probe_results.h to avoid compiler complaints, etc.)
- 0.2 (16 Dec 2008) – Lots of small fixes.
  - Fixed a bug where calling `shm.remove()` on shared memory that was already removed would cause a SystemError. (I wasn't setting the Python error before returning.)
  - Fixed a couple of bugs that would cause the creation of a new, read-only shared memory segment to fail.
  - Fixed a bug that would cause the creation of a new, read-only semaphore to fail.
  - Added the constant `IPC_CREX`.
  - Renamed (sorry) `MAX_KEY` to `KEY_MAX` and `MAX_SEMAPHORE_VALUE` to `SEMAPHORE_VALUE_MAX` to be consistent with the C naming convention in limits.h.
  - Hardcoded `SEMAPHORE_VALUE_MAX` to 32767 until I can find a reliable way to determine it at install time.
  - Changed prober.py to write out a C header file with platform-specific definitions in it.
  - Replaced OSError in shared memory functions with custom errors from this module.
  - Added code to raise a ValueError when an attempt is made to assign an out-of-range value to a semaphore.
  - Added code to raise a ValueError when an out-of-range key is passed to a constructor.
  - Fixed a bug in the demo program conclusion.c that caused some informational messages to be printed twice.
  - Fixed some documentation bugs.
- 0.1 (4 Dec 2008) – Original (alpha) version.

### Future Features/Changes

These are features that may or may not be added depending on technical difficulty, user interest and so forth.

- Update this documentation with a list of platforms that support semtimedop().
- Find a way to make `SEMAPHORE_VALUE_MAX` more accurate.

I don't plan on adding support for semaphore sets.