diff options
Diffstat (limited to 'demo/premise.py')
-rw-r--r-- | demo/premise.py | 118 |
1 files changed, 118 insertions, 0 deletions
diff --git a/demo/premise.py b/demo/premise.py new file mode 100644 index 0000000..55711e0 --- /dev/null +++ b/demo/premise.py @@ -0,0 +1,118 @@ +# Python modules +import time +import mmap +import os +import sys +PY_MAJOR_VERSION = sys.version_info[0] +# hashlib is only available in Python >= 2.5. I still want to support +# older Pythons so I import md5 if hashlib is not available. Fortunately +# md5 can masquerade as hashlib for my purposes. +try: + import hashlib +except ImportError: + import md5 as hashlib + +# 3rd party modules +import posix_ipc + +# Utils for this demo +import utils + + +utils.say("Oooo 'ello, I'm Mrs. Premise!") + +params = utils.read_params() + +# Create the shared memory and the semaphore. +memory = posix_ipc.SharedMemory(params["SHARED_MEMORY_NAME"], posix_ipc.O_CREX, + size=params["SHM_SIZE"]) +semaphore = posix_ipc.Semaphore(params["SEMAPHORE_NAME"], posix_ipc.O_CREX) + +# MMap the shared memory +mapfile = mmap.mmap(memory.fd, memory.size) + +# Once I've mmapped the file descriptor, I can close it without +# interfering with the mmap. +memory.close_fd() + +# I seed the shared memory with a random string (the current time). +what_i_wrote = time.asctime() +utils.write_to_memory(mapfile, what_i_wrote) + +for i in range(params["ITERATIONS"]): + utils.say("iteration %d" % i) + if not params["LIVE_DANGEROUSLY"]: + # Release the semaphore... + utils.say("Releasing the semaphore") + semaphore.release() + # ...and wait for it to become available again. In real code + # I might want to sleep briefly before calling .acquire() in + # order to politely give other processes an opportunity to grab + # the semaphore while it is free so as to avoid starvation. But + # this code is meant to be a stress test that maximizes the + # opportunity for shared memory corruption and politeness is + # not helpful in stress tests. + utils.say("Waiting to acquire the semaphore") + semaphore.acquire() + + s = utils.read_from_memory(mapfile) + + # I keep checking the shared memory until something new has + # been written. + while s == what_i_wrote: + # Nothing new; give Mrs. Conclusion another chance to respond. + if not params["LIVE_DANGEROUSLY"]: + utils.say("Releasing the semaphore") + semaphore.release() + utils.say("Waiting to acquire the semaphore") + semaphore.acquire() + + s = utils.read_from_memory(mapfile) + + # What I read must be the md5 of what I wrote or something's + # gone wrong. + if PY_MAJOR_VERSION > 2: + what_i_wrote = what_i_wrote.encode() + + try: + assert(s == hashlib.md5(what_i_wrote).hexdigest()) + except AssertionError: + utils.raise_error(AssertionError, + "Shared memory corruption after %d iterations." % i) + + # MD5 the reply and write back to Mrs. Conclusion. + if PY_MAJOR_VERSION > 2: + s = s.encode() + what_i_wrote = hashlib.md5(s).hexdigest() + utils.write_to_memory(mapfile, what_i_wrote) + +utils.say("") +utils.say("%d iterations complete" % (i + 1)) + +# Announce for one last time that the semaphore is free again so that +# Mrs. Conclusion can exit. +if not params["LIVE_DANGEROUSLY"]: + utils.say("") + utils.say("Final release of the semaphore followed by a 5 second pause") + semaphore.release() + time.sleep(5) + # ...before beginning to wait until it is free again. + # Technically, this is bad practice. It's possible that on a + # heavily loaded machine, Mrs. Conclusion wouldn't get a chance + # to acquire the semaphore. There really ought to be a loop here + # that waits for some sort of goodbye message but for purposes of + # simplicity I'm skipping that. + utils.say("Final wait to acquire the semaphore") + semaphore.acquire() + +utils.say("Destroying semaphore and shared memory.") +mapfile.close() +# I could call memory.unlink() here but in order to demonstrate +# unlinking at the module level I'll do it that way. +posix_ipc.unlink_shared_memory(params["SHARED_MEMORY_NAME"]) + +semaphore.release() + +# I could also unlink the semaphore by calling +# posix_ipc.unlink_semaphore() but I'll do it this way instead. +semaphore.unlink() |