diff options
Diffstat (limited to 'ReadMe.html')
-rw-r--r-- | ReadMe.html | 1505 |
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 © 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 – 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 <e; key <e; 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 > <tt>KEY_MIN</tt> and ≤ <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 > 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 > 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 > <tt>0</tt> and ≤ <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> + > <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 > <tt>0</tt> and ≤ <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 > 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>> 0</tt>, the call + returns the first message of that type. + </li> + <li>When <span class="param">type</span> <tt>< 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 > 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 – +</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 –</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> – 0.6.8 (12 Sept 2014) –</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) – + <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) – + <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) – + <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) – + <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) – + <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) – + <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) – + <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) – + <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 > 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) – + <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) – + <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) – + <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) – + <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) – + <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 > 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) – + <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 –</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) – + <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) – + 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) – 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> |