summaryrefslogtreecommitdiff
path: root/ReadMe.html
diff options
context:
space:
mode:
Diffstat (limited to 'ReadMe.html')
-rw-r--r--ReadMe.html1505
1 files changed, 1505 insertions, 0 deletions
diff --git a/ReadMe.html b/ReadMe.html
new file mode 100644
index 0000000..686eee6
--- /dev/null
+++ b/ReadMe.html
@@ -0,0 +1,1505 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+
+<html>
+
+<head>
+ <meta name="author" content="Philip Semanchuk">
+ <meta name="copyright" content="All contents &copy; 2014 Philip Semanchuk">
+ <meta name="keywords" content="python sysv system v ipc semaphore shared memory">
+
+ <title>System V IPC for Python - Semaphores, Shared Memory and Message Queues</title>
+
+ <style type="text/css">
+ dt {
+ font-family: monospace;
+ font-weight: bold;
+ padding-bottom: .33em;
+ margin-top: 1em;
+ }
+ span[lang] { font-style: italic; }
+
+ span.param {
+ font-family: monospace;
+ font-style: italic;
+ }
+
+ span.book_title {
+ text-decoration: underline;
+ }
+
+ pre { margin-left: 2em; }
+
+ li { margin-top: 1em; margin-bottom: 1em; }
+
+ form {
+ width: 20em;
+ float: right;
+ font-size: 90%;
+ margin-left: 1em;
+ margin-bottom: 1em;
+ float: right;
+ }
+ fieldset, legend {
+ background-color: #d0d0a9;
+ }
+ /* This style is only present on the local version of the readme.
+ In the online version, the RSS feed is displayed. */
+ div.rss { display: none; }
+ </style>
+</head>
+
+<body>
+
+<h2>System V IPC for Python - Semaphores, Shared Memory and Message Queues</h2>
+
+<div class="rss">
+ <a href="rss.xml"><img src="/common/images/rss.png" width="28" height="28" alt=""></a>
+ <br><a href="rss.xml">RSS</a>
+</div>
+
+<p>This describes the <tt>sysv_ipc</tt> 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 <a href="http://f-utility.tumblr.com/post/525726296/compiling-sysv-ipc-python-module-with-gcc-on-aix-5-2">AIX 5.2</a>.
+It might also work under Windows with a library like
+<a href="http://www.cygwin.com/">Cygwin</a>.
+</p>
+
+<p>It works with Python 2.4 &ndash; 3.x.
+It's released
+under a <a href="http://creativecommons.org/licenses/BSD/">BSD license</a>.
+</p>
+
+<p>You can <strong>download
+<a href="sysv_ipc-0.6.8.tar.gz">sysv_ipc version 0.6.8</a>
+</strong>
+(<a href="sysv_ipc-0.6.8.md5.txt">[md5 sum]</a>,
+<a href="sysv_ipc-0.6.8.sha1.txt">[sha1 sum]</a>)
+
+which contains the source code, setup.py, installation instructions and
+<a href="#samples">sample code</a>. You can read about
+<a href="#current">all of the changes in this version</a>.
+</p>
+
+<p>
+You might also want to read
+about some <a href="#bugs">known bugs</a>.
+</p>
+
+<p>You might be interested in the very similar module
+<a href="/philip/posix_ipc/"><tt>posix_ipc</tt></a>
+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.
+</p>
+
+<h2>Module <tt>sysv_ipc</tt></h2>
+
+<p>Jump to <a href="#semaphore">semaphores</a>,
+<a href="#shared_memory">shared memory</a>, or
+<a href="#message_queue">message queues</a>.</p>
+
+
+<h3>Module Functions</h3>
+
+<dl>
+ <dt>attach(id, [address = None, [flags = 0]])</dt>
+ <dd>Attaches the (existing) shared memory that has the given <tt>id</tt> and
+ returns a new SharedMemory object. See
+ <a href="#attach">SharedMemory.attach()</a> for details on the
+ <tt>address</tt> and <tt>flags</tt> parameters.
+
+ <p>This method is useful only under fairly unusual circumstances.
+ You probably don't need it.
+ </p>
+ </dd>
+
+ <dt>ftok(path, id, [silence_warning = False])</dt>
+ <dd>Calls <tt>ftok(path, id)</tt>. Note that
+ <a href="#ftok_weakness"><tt>ftok()</tt> has limitations</a>, and this
+ function will issue a warning to that effect unless
+ <tt>silence_warning</tt> is True.
+ </dd>
+
+ <dt>remove_semaphore(id)</dt>
+ <dd>Removes the semaphore with the given <tt>id</tt>.</dd>
+
+ <dt>remove_shared_memory(id)</dt>
+ <dd>Removes the shared memory with the given <tt>id</tt>.</dd>
+
+ <dt>remove_message_queue(id)</dt>
+ <dd>Removes the message queue with the given <tt>id</tt>.</dd>
+</dl>
+
+
+<h3>Module Constants</h3>
+
+<dl>
+ <dt>IPC_CREAT, IPC_EXCL and IPC_CREX</dt>
+ <dd><tt>IPC_CREAT</tt> and <tt>IPC_EXCL</tt> are flags used when
+ creating IPC objects. They're
+ bitwise unique and can be ORed together. <tt>IPC_CREX</tt> is
+ shorthand for <tt>IPC_CREAT | IPC_EXCL</tt>.
+
+ <p>When passed to an IPC object's constructor, <tt>IPC_CREAT</tt> 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 <tt>IPC_EXCL</tt> flag, too.
+ </p>
+ </dd>
+
+ <dt>IPC_PRIVATE</dt>
+ <dd>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 <tt>fork()</tt>).
+ </dd>
+
+ <dt>KEY_MIN and KEY_MAX</dt>
+ <dd>Denote the range of keys that this module accepts. Your OS might
+ limit keys to a smaller range depending on the typedef of
+ <tt>key_t</tt>.
+
+ <p>Keys randomly generated by this module are in the range
+ <tt>1 &lte; key &lte; SHRT_MAX</tt>.
+ That's type-safe unless your OS has a very bizarre
+ definition of <tt>key_t</tt>.
+ </p>
+ </dd>
+
+ <dt>SEMAPHORE_VALUE_MAX</dt>
+ <dd>The maximum value of a semaphore.
+ </dd>
+
+ <dt>PAGE_SIZE</dt>
+ <dd>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.
+ </dd>
+
+ <dt>SEMAPHORE_TIMEOUT_SUPPORTED</dt>
+ <dd>True if the platform supports timed semaphore waits, False otherwise.</dd>
+
+ <dt>SHM_RND</dt>
+ <dd>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 <tt>shmat()</tt>
+ for more information.
+ </dd>
+
+ <dt>SHM_HUGETLB, SHM_NORESERVE and SHM_REMAP</dt>
+ <dd>You probably don't need these. They're Linux-specific flags that can
+ be passed to the SharedMemory
+ constructor, or to the <tt>.attach()</tt> function in the case of
+ SHM_REMAP. See your system's man page for <tt>shmget()</tt>
+ and <tt>shmat()</tt> for more information.
+ </dd>
+</dl>
+
+<h3>Module Errors</h3>
+
+<p>In addition to standard Python errors (e.g. <tt>ValueError</tt>),
+this module raises custom errors. These errors cover
+situations specific to IPC.
+</p>
+
+<dl>
+ <dt>Error</dt>
+ <dd>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.
+ </dd>
+
+ <dt>InternalError</dt>
+ <dd>Indicates that something has gone very wrong in the module code. Please
+ report this to the maintainer.
+ </dd>
+
+ <dt>PermissionsError</dt>
+ <dd>Indicates that you've attempted something that the permissions on the
+ IPC object don't allow.
+ </dd>
+
+ <dt>ExistentialError</dt>
+ <dd>Indicates an error related to the existence or non-existence of
+ an IPC object.
+ </dd>
+
+ <dt>BusyError</dt>
+ <dd>Raised when a semaphore call to <tt>.P()</tt> or <tt>.Z()</tt> either times out
+ or would be forced to wait when its <tt>block</tt> attribute is False.
+ </dd>
+
+ <dt>NotAttachedError</dt>
+ <dd>Raised when a process attempts to read from or write to a shared memory
+ segment to which it is not attached.
+ </dd>
+</dl>
+
+
+<h3 id="semaphore">The Semaphore Class</h3>
+
+<p>This is a handle to a semaphore.</p>
+
+<h4>Methods</h4>
+
+<dl>
+ <dt>Semaphore(key, [flags = 0, [mode = 0600, [initial_value = 0]]])</dt>
+ <dd>Creates a new semaphore or opens an existing one.
+
+ <p><span class="param">key</span> must be <tt>None</tt>,
+ <tt>IPC_PRIVATE</tt> or
+ an integer &gt; <tt>KEY_MIN</tt> and &le; <tt>KEY_MAX</tt>. If the key
+ is <tt>None</tt>, the module chooses a random unused key.
+ </p>
+
+ <p>The <span class="param">flags</span> specify whether you want to create a
+ new semaphore or open an existing one.
+ </p>
+
+ <ul>
+ <li>With <span class="param">flags</span> set to the <strong>default</strong> of <tt>0</tt>, the module attempts
+ to <strong>open an existing</strong> semaphore identified by <span class="param">key</span> and raises
+ a <tt>ExistentialError</tt> if that semaphore doesn't exist.
+ </li>
+
+ <li>With <span class="param">flags</span> set to <tt>IPC_CREAT</tt>, the module
+ <strong>opens</strong> the semaphore identified by
+ <span class="param">key</span> <strong>or creates</strong> a new
+ one if no such semaphore exists. Using <tt>IPC_CREAT</tt> by itself
+ is not recommended. (See <a href="#sem_init">Semaphore Initialization</a>.)
+ </li>
+
+ <li>With <span class="param">flags</span> set to
+ <tt>IPC_CREX</tt> (<tt>IPC_CREAT | IPC_EXCL</tt>),
+ the module
+ <strong>creates a new semaphore</strong> identified by <span class="param">key</span>. If a
+ semaphore with that key already exists, the call raises an
+ <tt>ExistentialError</tt>.
+ <strong>The <span class="param">initial_value</span> is ignored unless
+ both of these flags are specified</strong> or
+ if the semaphore is read-only.
+ </li>
+ </ul>
+
+ <p>When opening an existing semaphore, <span class="param">mode</span> is ignored.
+ </p>
+ </dd>
+
+ <dt>acquire([timeout = None, [delta = 1]])</dt>
+ <dd>Waits (conditionally) until the semaphore's value is &gt; 0 and then
+ returns, decrementing the semaphore.
+
+ <p>The <span class="param">timeout</span> (which can be a float) specifies how
+ many seconds this call should wait, if at all.
+ </p>
+ <p>The semantics of the timeout <a href="#v0_3">changed a little in
+ version 0.3</a>.
+ </p>
+
+ <ul>
+ <li>A <span class="param">timeout</span> of None (the default)
+ implies no time limit. The call will not return until its wait
+ condition is satisfied.
+ </li>
+
+ <li>When <span class="param">timeout</span> is 0, the call
+ raises a <tt>BusyError</tt> if it can't immediately
+ acquire the semaphore. Since it will
+ return immediately if <em>not</em> asked to wait, this can be
+ thought of as "non-blocking" mode.
+ </li>
+
+ <li>When the <span class="param">timeout</span> is &gt; 0, the call
+ will wait no longer than <span class="param">timeout</span>
+ seconds before either returning (having acquired the semaphore)
+ or raising a <tt>BusyError</tt>.
+ </li>
+ </ul>
+
+ <p>When the call returns, the semaphore's value decreases by
+ <span class="param">delta</span>
+ (or more precisely, <tt>abs(<span class="param">delta</span>)</tt>)
+ which defaults to 1.
+ </p>
+
+ <p>On platforms that don't support the <tt>semtimedop()</tt> API call,
+ all timeouts (including zero) are treated as infinite. The call
+ will not return until its wait condition is satisfied.
+ </p>
+
+ <p>Most platforms provide <tt>semtimedop()</tt>. OS X is a
+ notable exception. The module's Boolean constant
+ <tt>SEMAPHORE_TIMEOUT_SUPPORTED</tt>
+ is True on platforms that support <tt>semtimedop()</tt>.
+ </p>
+ </dd>
+
+
+ <dt>release([delta = 1])</dt>
+ <dd>
+ Releases (increments) the semaphore.
+
+ <p>The semaphore's value increases by <span class="param">delta</span>
+ (or more precisely, <tt>abs(<span class="param">delta</span>)</tt>)
+ which defaults to 1.
+ </p>
+ </dd>
+
+ <dt>P()</dt>
+ <dd>A synonym for <tt>.acquire()</tt> that takes the same parameters.
+
+ <p>"P" stands for
+ <span lang="nl">prolaag</span> or <span lang="nl">probeer te verlagen</span>
+ (try to decrease), the original name given by
+ <a href="http://en.wikipedia.org/wiki/Semaphore_(programming)">Edsger Dijkstra</a>.
+ </p>
+ </dd>
+
+ <dt>V()</dt>
+ <dd>A synonym for <tt>.release()</tt> that takes the same parameters.
+
+ <p>"V" stands for
+ <span lang="nl">verhoog</span> (increase), the original name given by
+ <a href="http://en.wikipedia.org/wiki/Semaphore_(programming)">Edsger Dijkstra</a>.
+ </p>
+ </dd>
+
+ <dt>Z([timeout = None])</dt>
+ <dd>Blocks until zee zemaphore is zero.
+
+ <p><span class="param">Timeout</span> has
+ the same meaning as described in <tt>.acquire()</tt>.
+ </p>
+ </dd>
+
+ <dt>remove()</dt>
+ <dd>
+ Removes (deletes) the semaphore from the system.
+
+ <p>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 <tt>semctl(IPC_RMID)</tt>.
+ </p>
+ </dd>
+</dl>
+
+<h4>Attributes</h4>
+
+<dl>
+ <dt>key (read-only)</dt>
+ <dd>The key passed in the call to the constructor.</dd>
+
+ <dt>id (read-only)</dt>
+ <dd>The id assigned to this semaphore by the OS.</dd>
+
+ <dt>value</dt>
+ <dd>The integer value of the semaphore.</dd>
+
+ <dt>undo</dt>
+ <dd>Defaults to False.
+
+ <p>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
+ <strong>using this flag can make your code non-portable</strong>.
+ </p>
+ </dd>
+
+ <dt>block</dt>
+ <dd>
+ Defaults to True, which means that calls to <tt>acquire()</tt> and
+ <tt>release()</tt> will not return
+ until their wait conditions are satisfied.
+
+ <p>When False, these calls
+ will not block but will instead raise an error if they are unable
+ to return immediately.
+ </p>
+ </dd>
+
+ <dt>mode</dt>
+ <dd>The semaphore's permission bits.
+
+ <p>Tip: the following Python code will display
+ the mode in octal:<br>
+ <tt>print int(str(my_sem.mode), 8)</tt>
+ </p>
+ </dd>
+
+ <dt>uid</dt>
+ <dd>The semaphore's user id.</dd>
+
+ <dt>gid</dt>
+ <dd>The semaphore's group id.</dd>
+
+ <dt>cuid (read-only)</dt>
+ <dd>The semaphore creator's user id.</dd>
+
+ <dt>cgid (read-only)</dt>
+ <dd>The semaphore creator's group id.</dd>
+
+ <dt>last_pid (read-only)</dt>
+ <dd>The PID of the process that last called <tt>semop()</tt> (<tt>.P()</tt>,
+ <tt>.V()</tt> or <tt>.Z()</tt>) on this semaphore.
+ </dd>
+
+ <dt>waiting_for_nonzero (read-only)</dt>
+ <dd>The number of processes waiting for the value of the semaphore to become
+ non-zero (i.e. the number waiting in a call to <tt>.P()</tt>).
+ </dd>
+
+ <dt>waiting_for_zero (read-only)</dt>
+ <dd>The number of processes waiting for the value of the semaphore to become
+ zero (i.e. the number waiting in a call to <tt>.Z()</tt>).
+ </dd>
+
+ <dt>o_time (read-only)</dt>
+ <dd>The last time <tt>semop()</tt> (i.e. <tt>.P()</tt>, <tt>.V()</tt> or
+ <tt>.Z()</tt>) was called on this semaphore.
+ </dd>
+</dl>
+
+<h4>Context Manager Support</h4>
+
+<p>These semaphores provide <tt>__enter__()</tt> and <tt>__exit__()</tt>
+methods so they can be used in context managers. For instance --
+</p>
+
+<pre>
+with sysv_ipc.Semaphore(name) as sem:
+ # Do something...
+</pre>
+
+<p>Entering the context acquires the semaphore, exiting the context releases
+ the semaphore. See <tt>demo4/child.py</tt> for a complete example.
+</p>
+
+
+<h3 id="shared_memory">The SharedMemory Class</h3>
+
+<p>This is a handle to a shared memory segment.
+</p>
+
+
+<h4>Methods</h4>
+
+<dl>
+ <dt>SharedMemory(key, [flags = 0, [mode = 0600, [size = 0 or PAGE_SIZE, [init_character = ' ']]]])</dt>
+ <dd>Creates a new shared memory segment or opens an existing one.
+ The memory is automatically attached.
+
+ <p><span class="param">key</span> must be <tt>None</tt>,
+ <tt>IPC_PRIVATE</tt> or
+ an integer &gt; <tt>0</tt> and &le; <tt>KEY_MAX</tt>. If the key
+ is <tt>None</tt>, the module chooses a random unused key.
+ </p>
+
+ <p>The <span class="param">flags</span> specify whether you want to create a
+ new shared memory segment or open an existing one.
+ </p>
+
+ <ul>
+ <li>With <span class="param">flags</span> set to the
+ <strong>default</strong> of <tt>0</tt>, the module attempts
+ to <strong>open an existing</strong> shared memory segment identified by
+ <span class="param">key</span> and raises
+ a <tt>ExistentialError</tt> if it doesn't exist.
+ </li>
+
+ <li>With <span class="param">flags</span> set to <strong><tt>IPC_CREAT</tt></strong>, the module
+ <strong>opens</strong> the shared memory segment identified
+ by <span class="param">key</span> <strong>or
+ creates</strong> a new one if no such segment exists.
+ Using <tt>IPC_CREAT</tt> by itself
+ is not recommended. (See <a href="#mem_init">Memory Initialization</a>.)
+ </li>
+
+ <li>With <span class="param">flags</span> set to
+ <strong><tt>IPC_CREX</tt></strong> (<tt>IPC_CREAT | IPC_EXCL</tt>),
+ the module
+ <strong>creates</strong> a new shared memory segment identified by
+ <span class="param">key</span>. If
+ a segment with that key already exists, the call raises
+ a <tt>ExistentialError</tt>.
+
+ <p>When both <tt>IPC_CREX</tt> is specified
+ and the caller has write permission, each byte in the new memory segment will be
+ initialized to the value of <span class="param">init_character</span>.
+ </p>
+ </li>
+ </ul>
+
+ <p>The value of <span class="param">size</span> depends on whether
+ one is opening an existing segment or creating a new one.
+ </p>
+ <ul>
+ <li>When opening an existing segment, <span class="param">size</span>
+ must be ≤ the existing segment's size. Zero is
+ always valid.
+ </li>
+
+ <li>When creating an new segment,
+ many (most? all?) operating systems insist on a <span class="param">size</span>
+ &gt; <tt>0</tt>.
+ In addition, some round the size
+ up to the next multiple of PAGE_SIZE.
+ </li>
+ </ul>
+
+ <p>This module supplies a default
+ <span class="param">size</span> of <tt>PAGE_SIZE</tt> when
+ <tt>IPC_CREX</tt> is specified and <tt>0</tt> otherwise.
+ </p>
+ </dd>
+
+ <dt id="attach">attach([address = None, [flags = 0]])</dt>
+ <dd>
+ Attaches this process to the shared memory. The memory must be attached
+ before calling <tt>.read()</tt> or <tt>.write()</tt>. 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.
+
+ <p>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 <tt>shmat()</tt>. See that
+ function's man page for details.
+ </p>
+
+ <p>The flags are mostly only relevant if one specifies a specific address.
+ One exception is the flag <tt>SHM_RDONLY</tt> which, surprisingly,
+ attaches the segment read-only.
+ </p>
+
+ <p>Note that on some (and perhaps all) platforms, each call to <tt>.attach()</tt>
+ increments the system's "attached" count. Thus, if each call to
+ <tt>.attach()</tt> isn't paired with a call to <tt>.detach()</tt>,
+ 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 <tt>.remove()</tt>
+ and exits.
+ </p>
+ </dd>
+
+ <dt>detach()</dt>
+ <dd>Detaches this process from the shared memory.</dd>
+
+ <dt>read([byte_count = 0, [offset = 0]])</dt>
+ <dd>Reads up to <span class="param">byte_count</span> bytes from the
+ shared memory segment starting at <span class="param">offset</span>
+ and returns them as a string under Python 2 or as a bytes object
+ under Python 3.
+
+ <p>If <span class="param">byte_count</span> is zero (the default) the
+ entire buffer is returned.
+ </p>
+
+ <p>This method will never attempt to read past the end of the shared
+ memory segment, even when
+ <span class="param">offset</span> + <span class="param">byte_count</span>
+ exceeds the memory segment's size. In that case, the bytes
+ from <span class="param">offset</span> to the end of the segment are returned.
+ </p>
+ </dd>
+
+ <dt>write(s, [offset = 0])</dt>
+ <dd>Writes the string <span class="param">s</span> to the shared memory,
+ starting at <span class="param">offset</span>.
+
+ <p>At most <tt><i>n</i></tt> bytes will be written, where
+ <tt><i>n</i></tt> = the segment's size minus <span class="param">offset</span>.
+ </p>
+
+ <p>The string may contain embedded NULL bytes ('\0').
+ </dd>
+
+ <dt>remove()</dt>
+ <dd>Removes (destroys) the shared memory. Note that actual destruction of the
+ segment only occurs when all processes have detached.
+ </dd>
+
+</dl>
+
+<h4>Attributes</h4>
+
+<dl>
+ <dt>key (read-only)</dt>
+ <dd>The key provided in the constructor.</dd>
+
+ <dt>id (read-only)</dt>
+ <dd>The id assigned to this semaphore by the OS.</dd>
+
+ <dt>size (read-only)</dt>
+ <dd>The size of the segment in bytes.</dd>
+
+ <dt>address (read-only)</dt>
+ <dd>The address of the segment as Python long.</dd>
+
+ <dt>attached (read-only)</dt>
+ <dd>If True, this segment is currently attached.</dd>
+
+ <dt>last_attach_time (read-only)</dt>
+ <dd>The last time a process attached this segment.</dd>
+
+ <dt>last_detach_time (read-only)</dt>
+ <dd>The last time a process detached this segment.</dd>
+
+ <dt>last_change_time (read-only)</dt>
+ <dd>The last time a process changed the uid, gid or mode on this segment.</dd>
+
+ <dt>creator_pid (read-only)</dt>
+ <dd>The PID of the process that created this segment.</dd>
+
+ <dt>last_pid (read-only)</dt>
+ <dd>The PID of the most last process to attach or detach this segment.</dd>
+
+ <dt>number_attached (read-only)</dt>
+ <dd>The number of processes attached to this segment.</dd>
+
+ <dt>uid</dt>
+ <dd>The segment's user id.</dd>
+
+ <dt>gid</dt>
+ <dd>The segment's group id.</dd>
+
+ <dt>mode</dt>
+ <dd>The shared memory's permission bits.
+
+ <p>Tip: the following Python code will display
+ the mode in octal:<br>
+ <tt>print int(str(my_mem.mode), 8)</tt>
+ </p>
+ </dd>
+
+ <dt>cuid (read-only)</dt>
+ <dd>The segment creator's user id.</dd>
+
+ <dt>cgid (read-only)</dt>
+ <dd>The segment creator's group id.</dd>
+</dl>
+
+
+<h3 id="message_queue">The MessageQueue Class</h3>
+
+<p>This is a handle to a message queue.</p>
+
+<h4>Methods</h4>
+
+<dl>
+ <dt>MessageQueue(key, [flags = 0, [mode = 0600, [max_message_size = 2048]]])</dt>
+ <dd>Creates a new message queue or opens an existing one.
+
+ <p><span class="param">key</span> must be <tt>None</tt>,
+ <tt>IPC_PRIVATE</tt> or
+ an integer &gt; <tt>0</tt> and &le; <tt>KEY_MAX</tt>. If the key
+ is <tt>None</tt>, the module chooses a random unused key.
+ </p>
+
+ <p>The <span class="param">flags</span> specify whether you want to create a
+ new queue or open an existing one.
+ </p>
+
+ <ul>
+ <li>With <span class="param">flags</span> set to the
+ <strong>default</strong> of <tt>0</tt>, the module attempts
+ to <strong>open an existing</strong> message queue identified by
+ <span class="param">key</span> and raises
+ a <tt>ExistentialError</tt> if it doesn't exist.
+ </li>
+
+ <li>With <span class="param">flags</span> set to <strong><tt>IPC_CREAT</tt></strong>, the module
+ <strong>opens</strong> the message queue identified
+ by <span class="param">key</span> <strong>or
+ creates</strong> a new one if no such queue exists.
+ </li>
+
+ <li>With <span class="param">flags</span> set to
+ <strong><tt>IPC_CREX</tt></strong> (<tt>IPC_CREAT | IPC_EXCL</tt>),
+ the module
+ <strong>creates</strong> a new message queue identified by
+ <span class="param">key</span>. If
+ a queue with that key already exists, the call raises
+ a <tt>ExistentialError</tt>.
+ </li>
+ </ul>
+
+ <p>The <span class="param">max_message_size</span> can be increased
+ from the default, but be aware of the issues discussed in
+ <a href="#message_queue_limits">Message Queue Limits</a>.
+ </p>
+ </dd>
+
+ <dt>send(message, [block = True, [type = 1]])</dt>
+ <dd>Puts a message on the queue.
+
+ <p>The <span class="param">message</span> string can contain embedded
+ NULLs (ASCII <tt>0x00</tt>).
+ </p>
+
+ <p>The <span class="param">block</span> flag specifies whether or
+ not the call should wait if the message can't be sent (if, for
+ example, the queue is full). When <span class="param">block</span>
+ is <tt>False</tt>, the call will raise a <tt>BusyError</tt> if
+ the message can't be sent immediately.
+ </p>
+
+ <p>The <span class="param">type</span> is
+ associated with the message and is relevant when calling
+ <tt>receive()</tt>. It must be &gt; 0.
+ </p>
+ </dd>
+
+ <dt>receive([block = True, [type = 0]])</dt>
+ <dd>
+ Receives a message from the queue, returning a tuple of
+ <tt>(message, type)</tt>. Under Python 3, the message is a
+ bytes object.
+
+ <p>The <span class="param">block</span> flag specifies whether or
+ not the call should wait if there's no messages of the
+ specified type to retrieve. When <span class="param">block</span>
+ is <tt>False</tt>, the call will raise a <tt>BusyError</tt> if
+ a message can't be received immediately.
+ </p>
+
+ <p>The <span class="param">type</span> permits some control over
+ which messages are retrieved.
+ </p>
+
+ <ul>
+ <li>When <span class="param">type</span> <tt>== 0</tt>, the call
+ returns the first message on the queue regardless of its
+ type.
+ </li>
+ <li>When <span class="param">type</span> <tt>&gt; 0</tt>, the call
+ returns the first message of that type.
+ </li>
+ <li>When <span class="param">type</span> <tt>&lt; 0</tt>, the call
+ returns the first message of the lowest type that is ≤ the
+ absolute value of <span class="param">type</span>.
+ </li>
+ </ul>
+ </dd>
+
+ <dt>remove()</dt>
+ <dd>Removes (deletes) the message queue.</dd>
+</dl>
+
+<h4>Attributes</h4>
+
+<dl>
+ <dt>key (read-only)</dt>
+ <dd>The key provided in the constructor.</dd>
+
+ <dt>id (read-only)</dt>
+ <dd>The id assigned to this queue by the OS.</dd>
+
+ <dt id="queue_max_size">max_size</dt>
+ <dd>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
+ <a href="#message_queue_limits">Message Queue Limits</a> for details.
+ </dd>
+
+ <dt>last_send_time (read-only)</dt>
+ <dd>The last time a message was placed on the queue.</dd>
+
+ <dt>last_receive_time (read-only)</dt>
+ <dd>The last time a message was received from the queue.</dd>
+
+ <dt>last_change_time (read-only)</dt>
+ <dd>The last time a process changed the queue's attributes.</dd>
+
+ <dt>last_send_pid (read-only)</dt>
+ <dd>The id of the most recent process to send a message.</dd>
+
+ <dt>last_receive_pid (read-only)</dt>
+ <dd>The id of the most recent process to receive a message.</dd>
+
+ <dt>current_messages (read-only)</dt>
+ <dd>The number of messages currently in the queue.</dd>
+
+ <dt>uid</dt>
+ <dd>The queue's user id.</dd>
+
+ <dt>gid</dt>
+ <dd>The queue's group id.</dd>
+
+ <dt>mode</dt>
+ <dd>The queue's permission bits.
+
+ <p>Tip: the following Python code will display
+ the mode in octal:<br>
+ <tt>print int(str(my_mem.mode), 8)</tt>
+ </p>
+ </dd>
+
+ <dt>cuid (read-only)</dt>
+ <dd>The queue creator's user id.</dd>
+
+ <dt>cgid (read-only)</dt>
+ <dd>The queue creator's group id.</dd>
+</dl>
+
+
+
+<h3>Supported Features and Differences from SHM</h3>
+
+<p>This module is almost, but not quite, a superset of
+<a href="http://nikitathespider.com/python/shm/"><tt>shm</tt></a>.
+Some of the additional features are the ability to override the <tt>block</tt>
+flag on a per-call basis, the ability to change the semaphore's value
+in increments &gt; 1 when calling <tt>.P()</tt> and <tt>.V()</tt>
+and exposure of <tt>sem_otime</tt>.
+</p>
+
+<p>Differences that might trip you up are listed below.</p>
+
+<ul>
+ <li><tt>Shm</tt> compiles under Python 2.3 and older; this module has
+ not been tested with Python older than 2.4
+ </li>
+ <li>Attribute names and method signatures are different.</li>
+ <li>This module offers neither the functions <tt>semaphore_haskey()</tt>
+ nor <tt>memory_haskey()</tt>.
+ </li>
+ <li>This module's default permission on objects is <tt>0600</tt> as opposed
+ to <tt>shm</tt>'s <tt>0666</tt>.
+ </li>
+ <li><tt>Shm</tt> 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, <tt>shm</tt> 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.
+ </li>
+</ul>
+
+<h3>Usage Tips</h3>
+
+<h4>Sample Code</h4>
+
+<p>This module comes with two demonstration apps. The first (in the
+directory <tt>demo</tt>) shows how to use shared memory and semaphores.
+The second (in the directory <tt>demo2</tt>) shows how to use
+message queues.
+
+
+<h4 id="ftok_weakness">The Weakness of <tt>ftok()</tt></h4>
+
+<p>
+Most System V IPC sample code recommends <tt>ftok()</tt> for generating an
+integer key that's more-or-less random.
+It does not, however, guarantee that the key it generates is unused. If
+<tt>ftok()</tt> 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 <tt>ftok()</tt> and use the
+second mechanism exclusively?
+</p>
+
+<p>This is the weakness of <tt>ftok()</tt> -- it isn't guaranteed to give you
+what you want. The <a href="http://www.unix.com/man-page/FreeBSD/3/ftok/">BSD
+man page for <tt>ftok</tt></a> 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?
+</p>
+
+<p>This module obviates the need for <tt>ftok()</tt> by generating random
+keys for you. If your application can't use <tt>sysv_ipc</tt>'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
+<tt>ftok()</tt> and has the advantage of not hiding its limitations.
+</p>
+
+<p>This module provides <tt>ftok()</tt> in case you want to experiment with it.
+However, to emphasize its weakness, this version of <tt>ftok()</tt> raises a
+warning with every call unless you explicitly pass a flag to silence it.
+</p>
+
+<p>This package also provides <tt>ftok_experiment.py</tt> so that you can observe
+how often <tt>ftok()</tt> generates duplicate keys on your system.
+</p>
+
+
+<h4 id="sem_init">Semaphore Initialization</h4>
+
+<p>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
+<a href="http://www.opengroup.org/onlinepubs/009695399/functions/semget.html">the
+SUSv3 standard for <tt>semget()</tt></a>.)
+Some (most? all?) operating systems initialize it to zero, but this behavior
+is non-standard and therefore can't be relied upon.
+</p>
+
+<p>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 <tt>semget()</tt> with only
+the <tt>IPC_CREAT</tt> flag, the caller can't tell whether or not he has
+created a new semaphore or opened an existing one.
+<strong>This makes it
+difficult to create reliable code without using <tt>IPC_EXCL</tt>.</strong>
+W. Richard Stevens' <span class='book_title'>Unix Network Programming Volume 2</span>
+calls this "a fatal flaw in the design of System V semaphores" (p 284).
+</p>
+
+<p>
+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 &ndash;
+</p>
+
+<ol>
+ <li>P1 calls <tt>semget(IPC_CREAT)</tt> to create the semaphore S.</li>
+ <li>P2 calls <tt>semget(IPC_CREAT)</tt> to open S.</li>
+ <li>P1 initializes the semaphore's value to 1.</li>
+ <li>P1 calls <tt>acquire()</tt>, decrementing the value to 0.</li>
+ <li>P2, assuming S is a newly-created semaphore that needs to be initialized,
+ incorrectly sets the semaphore's value to 1.</li>
+ <li>P2 calls <tt>acquire()</tt>, decrementing the value to 0. Both processes
+ now think they own the lock.</li>
+</ol>
+
+<p>W. Richard Stevens' solution for this race condition is to check the value of
+<tt>sem_otime</tt> (an element in the <tt>semid_ds</tt> struct that's
+populated on the call to <tt>semctl(IPC_STAT)</tt> 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 <tt>semop()</tt> (which is called by <tt>P()</tt>/<tt>acquire()</tt>,
+<tt>V()</tt>/<tt>release()</tt>, and <tt>Z()</tt>).
+</p>
+
+<p>In Python, each process would run something like this:
+<pre>
+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.
+</pre>
+
+
+<h4 id="mem_init">Shared Memory Initialization</h4>
+
+<p>With shared memory,
+using the <tt>IPC_CREAT</tt> flag without <tt>IPC_EXCL</tt>
+is problematic <em>unless you know the size of the segment
+you're potentially opening</em>.
+</p>
+
+<p>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 <tt>IPC_CREAT</tt>
+can open or create a segment, there's no safe value for the size under
+this circumstance.
+</p>
+
+<p>As a (sort of) side note, the
+<a href="http://www.opengroup.org/onlinepubs/009695399/functions/shmget.html">SUSv3
+specification for <tt>shmget()</tt></a> 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.
+</p>
+
+
+<h4 id="message_queue_limits">Message Queue Limits</h4>
+
+<p>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.
+</p>
+
+<p><strong>Some implementations impose extremely stingy limits.</strong>
+For instance, many BSDish systems (OS X, FreeBSD,
+<a href="http://fxr.watson.org/fxr/source/sys/msg.h?v=NETBSD">NetBSD</a>, and
+<a href="http://fxr.watson.org/fxr/source/sys/msg.h?v=OPENBSD">OpenBSD</a>)
+limit queues to 2048 bytes. Note that that's the <em>total
+queue size</em>, not the message size. Two 1k messages would fill the queue.
+</p>
+
+<p><strong>Those limits can be very difficult to change.</strong> 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.
+</p>
+
+<p><strong>This module can't figure out what the limits are</strong>, 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 <tt>sysctl</tt>).
+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.
+</p>
+
+<p>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 <tt>.send()</tt> get stuck because a queue is full even though you've
+only put 2048 bytes of messages in it.
+</p>
+
+<p>Here are the limits I've been able to find under my test operating
+systems, ordered from best (most generous) to worst (most stingy).
+<strong>This information was current as of 2009</strong> 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.
+</p>
+
+<p>Under <strong>OpenSolaris 2008.05</strong> each queue's maximum size defaults
+to 64k. A privileged process (e.g. root) can change this through the
+<tt>max_size</tt> attribute of a <tt>sysv_ipc.MessageQueue</tt> object.
+I was able to increase it to 16M and successfully sent sixteen 1M messages to
+the queue.
+</p>
+
+<p>Under <strong>Ubuntu 8.04</strong> (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.
+</p>
+
+<p>Under <strong>FreeBSD 7</strong> and I think NetBSD and OpenBSD, each
+queue's maximum size defaults to 2048 bytes. Furthermore, one can (as root)
+set <tt>max_size</tt> to something larger and FreeBSD doesn't complain, but
+it also ignores the change.
+</p>
+
+<p><strong>OS X</strong> 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
+<a href="http://www.google.com/search?q=site%3Aopensource.apple.com+%22msg.h%22">Darwin
+message queue limits</a>.
+</p>
+
+<p>If you want
+to search for these limits on your operating system, the key constants are
+<tt>MSGSEG</tt>, <tt>MSGSSZ</tt>, <tt>MSGTQL</tt>, <tt>MSGMNB</tt>,
+<tt>MSGMNI</tt> and <tt>MSGMAX</tt>. Under BSD, <tt>sysctl kern.ipc</tt>
+should tell you what you need to know and may allow you to change these
+parameters.
+</p>
+
+<h4>Nobody Likes a Mr. Messy</h4>
+
+<p>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 <em>outside of its own process</em>, just like a file on a hard drive. It
+won't go away when your process ends unless you explicitly remove it.
+</p>
+
+<p>In short, remember to clean up after yourself.</p>
+
+<h4>Consult Your Local <tt>man</tt> Pages</h4>
+
+<p>The sysv_ipc module is just a wrapper around your system's API. If your
+system's implementation has quirks, the <tt>man</tt> pages for <tt>semget, semctl, semop
+shmget, shmat, shmdt</tt> and <tt>shmctl</tt> will probably cover them.
+</p>
+
+<h4>Interesting Tools</h4>
+
+<p>Many systems (although not some older versions of OS X) come
+with <tt>ipcs</tt> and <tt>ipcrm</tt>.
+The former shows existing shared memory, semaphores and message queues on your system and
+the latter allows you to remove them.
+</p>
+
+
+<h4>Last But Not Least</h4>
+
+<p>For Pythonistas &ndash;</p>
+<ul>
+ <li><a href="https://www.youtube.com/watch?v=Xe1a1wHxTyo">A meditation on the inaccuracy
+ of shared memories</a>
+ </li>
+</ul>
+
+<h3 id="bugs">Known Bugs</h3>
+
+<p>Bugs? My code never has bugs! There are, however, some suboptimal anomalies...</p>
+
+<ul>
+ <li>Under OS X, <tt>sys/ipc.h</tt> defines two versions of the
+ <tt>ipc_perm</tt> struct. This module picks up the old, deprecated
+ one which stores uid and gid values in 16 bit types. It's definitions
+ in <tt>Python.h</tt> that cause this, though, so there's not much
+ I can do to change it.
+ </li>
+ <li>This module can't report the exact min and max values for a key.
+ It turns out
+ that <a href="http://groups.google.com/group/comp.lang.c/browse_thread/thread/14a1cdbfb111f4eb">it's
+ really difficult to determine the maximum value that a
+ typedef-ed variable can hold</a>.
+ </li>
+</ul>
+
+<h3>Version History</h3>
+
+<ul id="history">
+ <li id="v0_6_8"><strong><span id="current">Current</span> &ndash; 0.6.8 (12 Sept 2014) &ndash;</strong>
+ <ul>
+ <li>Fixed a bug in <tt>prober.py</tt> where prober would fail
+ on systems where Python's include file was not named
+ <tt>pyconfig.h</tt>. (RHEL 6 is one such system.) Thanks to
+ Joshua Harlow for the bug report and patch.
+ </li>
+
+ <li><i>Spasibo</i> 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.
+ </li>
+ </ul>
+ </li>
+
+ <li id="v0_6_7">0.6.7 (1 August 2014) &ndash;
+ <p><i>Spasibo</i> to Yuriy Taraday for reporting some doc errors
+ corrected in this version.
+ </p>
+
+ <ul>
+ <li>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.
+ </li>
+
+ <li>Changed randomly generated keys to never use a value of 0.</li>
+
+ <li>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.)
+ </li>
+
+ <li>This is the first version downloadable from PyPI.</li>
+ </ul>
+ </li>
+
+ <li id="v0_6_6">0.6.6 (15 October 2013) &ndash;
+ <p>Added the ability to use Semaphores in context managers.
+ Thanks to Matt Ruffalo for the suggestion and patch.
+ </p>
+ </li>
+
+ <li id="v0_6_5">0.6.5 (31 March 2013) &ndash;
+ <p>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.
+ </p>
+ </li>
+
+ <li id="v0_6_4">0.6.4 (19 Dec 2012) &ndash;
+ <ul>
+ <li>Added a module-level <tt>attach()</tt> method based on a
+ suggestion by Vladimír Včelák.
+ </li>
+ <li>Added the <tt>ftok()</tt> method along with dire warnings about
+ its use.
+ </li>
+ </ul>
+ </li>
+
+ <li id="v0_6_3">0.6.3 (3 Oct 2010) &ndash;
+ <ul>
+ <li>Fixed a segfault in <tt>write()</tt> that occurred any time
+ an offset was passed. This was introduced in v0.6.0.
+ <i>Tack</i> to Johan Bernhardtson for the bug report.
+ </li>
+ </ul>
+ </li>
+
+ <li id="v0_6_2">0.6.2 (6 July 2010) &ndash;
+ <ul>
+ <li>Updated setup.py metadata to reflect Python 3 compatibility.
+ No functional change.
+ </li>
+ </ul>
+ </li>
+
+ <li id="v0_6_1">0.6.1 (26 June 2010) &ndash;
+ <ul>
+ <li>Fixed a typo introduced in the previous version that caused
+ unpredictable behavior (usually a segfault) if a block flag
+ was passed to <tt>MessageQueue.send()</tt>. <i>Obrigado</i>
+ to Álvaro Justen and Ronald Kaiser for the bug report and
+ patch.
+ </li>
+ </ul>
+ </li>
+
+ <li id="v0_6_0">0.6.0 (20 May 2010) &ndash;
+ <ul>
+ <li>Added Python 3 support.</li>
+ <li>Renamed a constant that caused a problem under AIX.
+ Thanks to Loic Nageleisen for the bug report.
+ </li>
+ <li>Updated this documentation a little.</li>
+ </ul>
+ </li>
+
+ <li id="v0_5_2">0.5.2 (17 Jan 2010)</strong>
+ <ul>
+ <li>Fixed a bug that insisted on keys &gt; 0. Thanks to 原志
+ (Daniel) for the bug report and patch.
+ </li>
+ <li>Fixed a bug where the module could have generated invalid
+ keys on systems that typedef <tt>key_t</tt> as a
+ <tt>short</tt>. I don't think such a system exists, though.
+ </li>
+ <li>Fixed a LICENSE file typo.</li>
+ <li>Added an RSS feed to this page.</li>
+ </ul>
+ </li>
+
+ <li id="v0_5_1">0.5.1 (1 Dec 2009) &ndash;
+ <p>No code changes in this version.</p>
+ <ul>
+ <li>Fixed the comment in <tt>sysv_ipc_module.c</tt> that
+ still referred to the GPL license.
+ </li>
+ <li>Added the attributes <tt>__version</tt>, <tt>__author__</tt>,
+ <tt>__license__</tt> and <tt>__copyright__</tt>.
+ </li>
+ <li>Removed <tt>file()</tt> from <tt>setup.py</tt> in favor
+ of <tt>open()</tt>.
+ </li>
+ </ul>
+ </li>
+
+ <li id="v0_5">0.5 (6 Oct 2009) &ndash;
+ <p>No code changes in this version.</p>
+ <ul>
+ <li>Changed the license from GPL to BSD.</li>
+ </ul>
+ </li>
+
+ <li id="v0_4_2">0.4.2 (22 Mar 2009) &ndash;
+ <p>No code changes in this version.</p>
+ <ul>
+ <li>Fixed broken documentation links to youtube.</li>
+ <li>Fixed the project name in the LICENSE file.</li>
+ </ul>
+ </li>
+
+ <li id="v0_4_1"> 0.4.1 (12 Feb 2009) &ndash;
+ <ul>
+ <li>Changed status to beta.</li>
+ <li>Added automatic generation of keys.</li>
+ <li>Added a message queue demo.</li>
+ <li>Added <tt>str()</tt> and <tt>repr()</tt> support to all
+ objects.</li>
+ <li>Fixed a bug in <tt>SharedMemory.write()</tt> 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 <tt>long</tt> and <tt>int</tt>, or
+ <tt>long</tt> and <tt>py_size_t</tt>
+ (depending on Python version). <em>Tack</em> to Jesper
+ for debug help.
+ </li>
+ <li>Plugged a memory leak in <tt>MessageQueue.receive()</tt>.</li>
+ <li>Added a VERSION attribute to the module.</li>
+ </ul>
+ </li>
+
+ <li id="v0_4">0.4 (28 Jan 2009) &ndash;
+ <ul>
+ <li>Added message queues.</li>
+ <li>Fixed a bug where the <tt>key</tt> attribute of SharedMemory objects
+ returned garbage.
+ </li>
+ <li>Fixed a bug where keys &gt; INT_MAX would get truncated on
+ platforms where longs are bigger than ints.
+ </li>
+ <li>Provided decent inline documentation for object attributes
+ (available via the <tt>help()</tt> command).
+ </li>
+ <li>Rearranged the code which was suffering growing pains.</li>
+ </ul>
+ </li>
+
+ <li id="v0_3">0.3 (16 Jan 2009) &ndash;
+ <p>This version features a rename of classes and errors
+ (sorry about breaking the names), some modifications to
+ semaphore timeouts, and many small fixes.
+ </p>
+
+ <p>A semaphore's <tt>.block</tt> flag now consistently trumps the
+ timeout. When <tt>False</tt>, the timeout is irrelevant -- calls
+ will never block. In prior versions, the flag was ignored
+ when the timeout was non-zero.
+ </p>
+
+ <p>Also, on platforms (such as OS X) where <tt>semtimedop()</tt> is
+ not supported, all timeouts are now treated as <tt>None</tt>.
+ In other words, when <tt>.block</tt> is True, all calls
+ wait as long as necessary.
+ </p>
+
+ <p>Other fixes &ndash;</p>
+
+ <ul>
+ <li>Fixed the poor choices I'd made for class and
+ error names by removing the leading "SysV" and "SysVIpc".
+ </li>
+ <li>Removed dependencies on Python 2.5. The module now works
+ with Python 2.4.4 and perhaps earlier versions.
+ </li>
+ <li>Fixed a bug where I was not following SysV semaphore semantics
+ for interaction between timeouts and the block flag.
+ </li>
+ <li>Fixed compile problems on OpenSolaris 2008.05.</li>
+ <li>Got rid of OS X compile warnings.</li>
+ <li>Fixed many instances where I was making potentially lossy
+ conversions between Python values and Unix-specific
+ types like <tt>key_t</tt>, <tt>pid_t</tt>, etc.
+ </li>
+ <li>Fixed a bug in the SharedMemory <tt>attach()</tt> function
+ that would set an error string but not return an error
+ value if the passed address was not <tt>None</tt> or a long.
+ </li>
+ <li>Simplified the code a little.</li>
+ <li>Restricted the semaphore <tt>acquire()</tt> and
+ <tt>release()</tt> delta to be between SHORT_MIN and
+ SHORT_MAX since
+ <a href="http://opengroup.org/onlinepubs/007908775/xsh/semop.html">it
+ is a short in the SUSv2 spec</a>.
+ </li>
+ <li>Fixed a bug where calling <tt>acquire()</tt> or
+ <tt>release()</tt> with a delta of <tt>0</tt> would call
+ <tt>.Z()</tt> instead.
+ </li>
+ <li>Disallowed byte counts ≤ <tt>0</tt> in
+ <tt>SharedMemory.read()</tt>
+ </li>
+ <li>Fixed a bug in the <tt>SharedMemory</tt> init code that
+ could, under vanishingly rare circumstances, return failure
+ without setting the error code.
+ </li>
+ <li>Removed some dead code relating to the <tt>.seq</tt> member
+ of the <tt>sem_perm</tt> and <tt>shm_perm</tt> structs.
+ </li>
+ <li>Stopped accessing the non-standard <tt>key</tt>
+ (a.k.a. <tt>_key</tt> and <tt>__key</tt>) element of the
+ <tt>ipc_perm</tt> struct.
+ </li>
+ <li>Added code to ensure the module doesn't try to create
+ a string that's larger than Python permits when reading
+ from shared memory.
+ </li>
+ </ul>
+ </li>
+
+ <li>0.2.1 (3 Jan 2009) &ndash;
+ <ul>
+ <li>Fixed a bug that prevented the module-specific
+ errors (<tt>ExistentialError</tt>, etc.) from
+ being visible in the module.
+ </li>
+ <li>Fixed a bug that re-initialized shared memory with
+ the init character when only <tt>IPC_CREAT</tt> was specified
+ and an existing segment was opened.
+ </li>
+ <li>Fixed a bug that always defaulted the size of a shared
+ memory segment to <tt>PAGE_SIZE</tt>. Updated code and
+ documentation to use intelligent defaults. <em>Tack</em> to
+ Jesper for the bug report.
+ </li>
+ <li>Several cosmetic changes. (Added more metadata to setup.py,
+ added a newline to the end of probe_results.h to avoid
+ compiler complaints, etc.)
+ </li>
+ </ul>
+ </li>
+
+ <li>0.2 (16 Dec 2008) &ndash;
+ Lots of small fixes.
+
+ <ul>
+ <li>Fixed a bug where calling <tt>shm.remove()</tt> on shared
+ memory that was already removed would cause a SystemError.
+ (I wasn't setting the Python error before returning.)
+ </li>
+
+ <li>Fixed a couple of bugs that would cause the creation
+ of a new, read-only shared memory segment to fail.
+ </li>
+
+ <li>Fixed a bug that would cause the creation
+ of a new, read-only semaphore to fail.
+ </li>
+
+ <li>Added the constant <tt>IPC_CREX</tt>.</li>
+
+ <li>Renamed (sorry) <tt>MAX_KEY</tt> to <tt>KEY_MAX</tt> and
+ <tt>MAX_SEMAPHORE_VALUE</tt> to <tt>SEMAPHORE_VALUE_MAX</tt>
+ to be consistent with the C naming convention in limits.h.
+ </li>
+
+ <li>Hardcoded <tt>SEMAPHORE_VALUE_MAX</tt> to 32767 until I can
+ find a reliable way to determine it at install time.
+ </li>
+
+ <li>Changed prober.py to write out a C header file with
+ platform-specific definitions in it.
+ </li>
+
+ <li>Replaced OSError in shared memory functions with custom
+ errors from this module.
+ </li>
+
+ <li>Added code to raise a ValueError when an attempt is made
+ to assign an out-of-range value to a semaphore.
+ </li>
+
+ <li>Added code to raise a ValueError when an out-of-range key
+ is passed to a constructor.
+ </li>
+
+ <li>Fixed a bug in the demo program conclusion.c that caused
+ some informational messages to be printed twice.
+ </li>
+
+ <li>Fixed some documentation bugs.</li>
+ </ul>
+ </li>
+ <li>0.1 (4 Dec 2008) &ndash; Original (alpha) version.</li>
+</ul>
+
+
+<h3>Future Features/Changes</h3>
+
+<p>These are features that may or may not be added depending on technical
+difficulty, user interest and so forth.
+</p>
+
+<ul>
+ <li>Update this documentation with a list of platforms that support semtimedop().</li>
+
+ <li>Find a way to make <tt>SEMAPHORE_VALUE_MAX</tt> more accurate.</li>
+</ul>
+
+<p>I don't plan on adding support for semaphore sets.</p>
+
+
+</body>
+</html>