summaryrefslogtreecommitdiff
path: root/shm/shm_wrapper.py
diff options
context:
space:
mode:
Diffstat (limited to 'shm/shm_wrapper.py')
-rw-r--r--shm/shm_wrapper.py301
1 files changed, 301 insertions, 0 deletions
diff --git a/shm/shm_wrapper.py b/shm/shm_wrapper.py
new file mode 100644
index 0000000..bf29f65
--- /dev/null
+++ b/shm/shm_wrapper.py
@@ -0,0 +1,301 @@
+# shm_wrapper - A wrapper for the shm module which provides access
+# to System V shared memory and semaphores on *nix systems.
+#
+# Copyright (c) 2007 by Philip Semanchuk
+# Contact info at http://NikitaTheSpider.com/
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Python modules
+import random
+import sys
+
+# Third party modules
+import shm
+
+r"""shm_wrapper - A wrapper for the shm module which provides access
+to System V shared memory and semaphores on *nix systems.
+
+The module shm is a Python wrapper around system functions like shmget. This
+module in turn offers higher-level, more Pythonic access to shared memory and
+semaphores.
+
+Full documentation is online at http://NikitaTheSpider.com/python/shm/
+
+"""
+
+def create_memory(size, permissions = 0666, InitCharacter = ' '):
+ """ Creates a new shared memory segment. One can destroy it either by calling the
+ module-level method remove_memory() or by calling the .remove() method of a handle to
+ said memory.
+ """
+ memory = None
+
+ # I create the memory using a randomly-generated key. I keep trying until I find one
+ # that works or until I hit an error.
+ while not memory:
+ key = random.randint(1, sys.maxint - 1)
+ try:
+ memory = shm.create_memory(key, size, permissions)
+ except shm.error, ExtraData:
+ if shm.memory_haskey(key):
+ # Oops, bad luck, the key exists. I'll try another. I can't call
+ # memory_haskey() before calling create_memory() because that would create
+ # a race condition where I could verify a key is not used but then another
+ # process could call create_memory() with that key before I got a chance to
+ # do so.
+ pass
+ else:
+ # Uh-oh, something fundamental is wrong.
+ raise shm.error, ExtraData
+
+ # Here I implicitly discard the memory handle object returned to me by shm and instead
+ # return my own handle to the shared memory segment.
+ memory = SharedMemoryHandle(key)
+
+ memory.write(InitCharacter[0] * memory.size)
+
+ return memory
+
+
+def remove_memory(key):
+ # Destroys the shared memory segment. Raises KeyError if the key doesn't exist.
+ shm.remove_memory(shm.getshmid(key))
+
+
+class SharedMemoryHandle(object):
+ def __init__(self, key):
+ self._MemoryHandle = None
+
+ # getshmid will raise a KeyError if there's no memory segment with this key.
+ shmid = shm.getshmid(key)
+ self._MemoryHandle = shm.memory(shmid)
+
+
+ def __del__(self):
+ if self._MemoryHandle:
+ # This will raise an error if the memory has been destroyed.
+ try:
+ if self._MemoryHandle.attached:
+ self._MemoryHandle.detach()
+ except shm.error:
+ pass
+
+
+ def remove(self):
+ if self._MemoryHandle:
+ if self._MemoryHandle.attached:
+ self._MemoryHandle.detach()
+
+ shm.remove_memory(self._MemoryHandle.shmid)
+ self._MemoryHandle = None
+
+
+ def read(self, NumberOfBytes = 0, offset = 0):
+ if not self._MemoryHandle.attached:
+ self._MemoryHandle.attach()
+
+ if not NumberOfBytes:
+ NumberOfBytes = self._MemoryHandle.size - offset
+
+ return self._MemoryHandle.read(NumberOfBytes, offset)
+
+
+ def write(self, s, offset = 0):
+ if not self._MemoryHandle.attached:
+ self._MemoryHandle.attach()
+
+ self._MemoryHandle.write(s, offset)
+
+
+ # Properties start here ================================================================
+
+ # key
+ def __get_key(self): return self._MemoryHandle.key
+ def __set_key(self, foo): raise AttributeError
+ key = property(__get_key, __set_key)
+
+ # size of segment
+ def __get_size(self): return self._MemoryHandle.size
+ def __set_size(self, foo): raise AttributeError
+ size = property(__get_size, __set_size)
+
+ # permissions
+ def __get_permissions(self): return self._MemoryHandle.perm
+ def __set_permissions(self, permissions): self._MemoryHandle.setperm(permissions)
+ permissions = property(__get_permissions, __set_permissions)
+
+ # The number of processes currently attached to this memory segment.
+ def __get_number_attached(self): return self._MemoryHandle.nattch
+ def __set_number_attached(self, foo): raise AttributeError
+ number_attached = property(__get_number_attached, __set_number_attached)
+
+ # segment's uid
+ def __get_uid(self): return self._MemoryHandle.uid
+ def __set_uid(self, uid): self._MemoryHandle.setuid(uid)
+ uid = property(__get_uid, __set_uid)
+
+ # segment's gid
+ def __get_gid(self): return self._MemoryHandle.gid
+ def __set_gid(self, gid): self._MemoryHandle.setgid(gid)
+ gid = property(__get_gid, __set_gid)
+
+ # Creator uid (read-only)
+ def __get_creator_uid(self): return self._MemoryHandle.cuid
+ def __set_creator_uid(self, foo): raise AttributeError
+ creator_uid = property(__get_creator_uid, __set_creator_uid)
+
+ # Creator gid (read-only)
+ def __get_creator_gid(self): return self._MemoryHandle.cgid
+ def __set_creator_gid(self, foo): raise AttributeError
+ creator_gid = property(__get_creator_gid, __set_creator_gid)
+
+ # Creator pid (read-only)
+ def __get_creator_pid(self): return self._MemoryHandle.cpid
+ def __set_creator_pid(self, foo): raise AttributeError
+ creator_pid = property(__get_creator_pid, __set_creator_pid)
+
+ # pid of last process to operate on this segment (read-only)
+ def __get_last_pid(self): return self._MemoryHandle.lpid
+ def __set_last_pid(self, foo): raise AttributeError
+ last_pid = property(__get_last_pid, __set_last_pid)
+
+
+
+def create_semaphore(InitialValue = 1, permissions = 0666):
+ """ Creates a new semaphore. One can destroy it either by calling the
+ module-level method remove_semaphore() or by calling the .remove() method of a
+ handle to said semaphore.
+ """
+ semaphore = None
+
+ # I create the semaphore using a randomly-generated key. I keep trying until I find one
+ # that works or until I hit an error.
+ while not semaphore:
+ key = random.randint(1, sys.maxint - 1)
+ try:
+ semaphore = shm.create_semaphore(key, InitialValue, permissions)
+ except shm.error, ExtraData:
+ if shm.semaphore_haskey(key):
+ # Oops, bad luck, the key exists. I'll try another. I can't call
+ # memory_haskey() before calling create_semaphore() because that would create
+ # a race condition where I could verify a key is not used but then another
+ # process could call create_semaphore() with that key before I got a chance to
+ # do so.
+ pass
+ else:
+ # Uh-oh, something fundamental is wrong.
+ raise ExtraData
+
+ # Here I implicitly discard the semaphore object returned to me by shm and instead
+ # return my own handle to the semaphore.
+ return SemaphoreHandle(key)
+
+
+def remove_semaphore(key):
+ # Destroys the semaphore. Raises KeyError if the key doesn't exist.
+ shm.remove_semaphore(shm.getsemid(key))
+
+
+class SemaphoreHandle(object):
+ def __init__(self, key):
+ # getsemid will raise a KeyError if appropriate.
+ self._SemaphoreHandle = shm.semaphore(shm.getsemid(key))
+
+
+ def remove(self):
+ shm.remove_semaphore(self._SemaphoreHandle.semid)
+ self._SemaphoreHandle = None
+
+
+ def P(self):
+ # P = prolaag = probeer te verlagen (try to decrease)
+ self._SemaphoreHandle.P()
+
+
+ def V(self):
+ # V = verhoog (increase)
+ self._SemaphoreHandle.V()
+
+
+ def Z(self):
+ # Z = block until Zee semaphore is Zero
+ self._SemaphoreHandle.Z()
+
+
+ # Properties start here ================================================================
+ def __get_key(self): return self._SemaphoreHandle.key
+ def __set_key(self, foo): raise AttributeError
+ key = property(__get_key, __set_key)
+
+
+ def __get_value(self): return self._SemaphoreHandle.val
+ def __set_value(self, value): self._semaphore.setval(value)
+ value = property(__get_value, __set_value)
+
+
+ def __get_WaitingForZero(self): return self._SemaphoreHandle.zcnt
+ def __set_WaitingForZero(self, foo): raise AttributeError
+ WaitingForZero = property(__get_WaitingForZero, __set_WaitingForZero)
+
+
+ def __get_WaitingForNonZero(self): return self._SemaphoreHandle.ncnt
+ def __set_WaitingForNonZero(self, foo): raise AttributeError
+ WaitingForNonZero = property(__get_WaitingForNonZero, __set_WaitingForNonZero)
+
+
+ def __get_blocking(self): return self._SemaphoreHandle.blocking
+ def __set_blocking(self, block): self._SemaphoreHandle.setblocking(block)
+ blocking = property(__get_blocking, __set_blocking)
+
+
+ def __get_undo(self): raise AttributeError
+ def __set_undo(self, undo): self._SemaphoreHandle.setundo(undo)
+ undo = property(__get_undo, __set_undo)
+
+
+ # segment's uid
+ def __get_uid(self): return self._SemaphoreHandle.uid
+ def __set_uid(self, uid): self._SemaphoreHandle.setuid(uid)
+ uid = property(__get_uid, __set_uid)
+
+
+ # segment's gid
+ def __get_gid(self): return self._SemaphoreHandle.gid
+ def __set_gid(self, gid): self._SemaphoreHandle.setgid(gid)
+ gid = property(__get_gid, __set_gid)
+
+
+ # Creator uid (read-only)
+ def __get_creator_uid(self): return self._SemaphoreHandle.cuid
+ def __set_creator_uid(self, foo): raise AttributeError
+ creator_uid = property(__get_creator_uid, __set_creator_uid)
+
+
+ # Creator gid (read-only)
+ def __get_creator_gid(self): return self._SemaphoreHandle.cgid
+ def __set_creator_gid(self, foo): raise AttributeError
+ creator_gid = property(__get_creator_gid, __set_creator_gid)
+
+
+ # Creator pid -- since semaphores have a lot of the same properties as memory
+ # objects, one would expect creator PID to be exposed here, but it isn't
+ # made available by the system (true AFAICT for BSDs, OS X and Solaris).
+
+
+ # pid of last process to operate on this segment (read-only)
+ def __get_last_pid(self): return self._SemaphoreHandle.lpid
+ def __set_last_pid(self, foo): raise AttributeError
+ last_pid = property(__get_last_pid, __set_last_pid)