codexprocess-and-thread-address-spaces.py
process-and-thread-address-spaces.py
"""Draw logical address spaces and execution contexts, not physical RAM layouts.
Tested with Python 3.14.4, NumPy 2.3.5, Matplotlib 3.10.7.
Run from _media; write the opaque matching PNG to the current directory.
"""
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.patches import FancyBboxPatch
def main():
plt.rcParams.update({"font.family": "DejaVu Sans", "font.size": 11})
ink, blue, green = "#203040", "#155d8a", "#187355"
fig, ax = plt.subplots(figsize=(11, 6.4), dpi=110, facecolor="white")
ax.set(xlim=(0, 11), ylim=(0, 6.4), facecolor="white")
ax.axis("off")
def box(x, y, width, height, label, color=ink, fill="white", size=11):
ax.add_patch(FancyBboxPatch((x, y), width, height,
boxstyle="round,pad=0.045", linewidth=1.4,
edgecolor=color, facecolor=fill))
if label:
ax.text(x + width / 2, y + height / 2, label, ha="center",
va="center", color=color, fontsize=size, linespacing=1.45)
ax.text(5.5, 6.14, "Processes separate mappings; threads share mappings",
ha="center", fontsize=17, weight="bold", color=ink)
ax.text(2.75, 5.58, "Two processes running the same executable",
ha="center", fontsize=12, weight="bold", color=ink)
ax.text(8.15, 5.58, "Two threads within one process",
ha="center", fontsize=12, weight="bold", color=ink)
for x, name, value, color, fill in [(0.35, "A", 7, blue, "#eef5fa"),
(2.95, "B", 42, green, "#eef7f2")]:
box(x, 2.65, 2.2, 2.5, "", color, fill)
ax.text(x + 1.1, 4.89, f"Process {name}: address space",
ha="center", fontsize=10.5, weight="bold", color=color)
box(x + 0.15, 3.75, 1.9, 0.65, f"VA 0x1234: x = {value}", color, "white")
box(x + 0.15, 2.91, 1.9, 0.5, f"Call stack of {name}", color, "white")
box(x, 1.33, 2.2, 0.85, f"{name}'s execution context\nregisters, PC, SP", color, fill)
ax.text(x + 1.1, 2.4, "Mappings select contents", ha="center",
fontsize=9.5, color=color)
ax.text(2.75, 0.97, "Same numeric VA, different private counters",
ha="center", fontsize=11, color=ink)
box(5.8, 2.65, 4.7, 2.5, "", ink, "#f2f4f6")
ax.text(8.15, 4.89, "One shared address space", ha="center",
fontsize=12, weight="bold", color=ink)
box(6.25, 3.75, 3.8, 0.65, "VA 0x1234: one shared x = 0", ink)
box(6.0, 2.91, 2.05, 0.5, "T1's call stack", blue, "#eef5fa")
box(8.25, 2.91, 2.05, 0.5, "T2's call stack", green, "#eef7f2")
ax.text(8.15, 2.4, "Globals, heap and both stacks are addressable by T1 and T2",
ha="center", fontsize=9.5, color=ink)
box(5.95, 1.33, 2.1, 0.85, "T1's own context\nregisters, PC1, SP1", blue, "#eef5fa")
box(8.25, 1.33, 2.1, 0.85, "T2's own context\nregisters, PC2, SP2", green, "#eef7f2")
ax.text(8.15, 0.97, "Process resources such as file descriptors are shared too",
ha="center", fontsize=10, color=ink)
ax.text(5.5, 0.55, "Own stacks are logical assignments, not protection from another thread.",
ha="center", fontsize=11, color=ink)
ax.text(5.5, 0.18, "Separate processes may deliberately share memory; code and copy-on-write pages may share physical storage.",
ha="center", fontsize=10, color=ink)
fig.subplots_adjust(left=0.015, right=0.985, top=0.985, bottom=0.02)
fig.savefig(Path.cwd() / (Path(__file__).stem + ".png"),
facecolor="white", transparent=False)
plt.close(fig)
if __name__ == "__main__":
main()