blob: 55711e038d12ca6c3624313e5af6a933288f4c36 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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()
|