From 6d862d7a961ce70bc24450aadc99a901e5ab19c8 Mon Sep 17 00:00:00 2001 From: Necoro <> Date: Mon, 22 Oct 2007 22:17:48 +0000 Subject: bundled shm module --- shm/shm_wrapper.py | 301 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 shm/shm_wrapper.py (limited to 'shm/shm_wrapper.py') 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) -- cgit v1.2.3-70-g09d2