wegen/FrOSCon26/research/diagrams/thread-handoff.dot
Ichthyostega 703e60c85a Review: identify and resolve problem with sync logic
''Review supported by Claude Code''

Control flow logic was scrutinised, and a race identified
in the solution to pass on the display action to the GUI thread.

Reconsidering the design, cross-thread synchronisation is now
hinged rather on a single atomic buffer pointer, where the GUI
thread notifies back completion of display work by setting that
pointer to NULL. Overall this simplifies the control logic

----
As an aside, I setup an outline of topics for documentation in `DemoSpec.txt`
and then instructed Claude to fill in the paragraphs, based on insight gained
as part of the code validation / review. Furthermore, I requested to generate
some diagrams that could be useful later when preparting the presentation
2026-07-19 03:48:16 +02:00

56 lines
2.3 KiB
Text

// Cross-thread architecture and data-visibility handoff.
// Render: dot -Tsvg thread-handoff.dot -o thread-handoff.svg
//
// One direction of data flow: the Proactor thread reads file blocks into the
// ring of buffers and publishes a ready frame through the single atomic baton
// `toDisplay_`; the GUI thread picks it up, uploads it to the GPU, and hands
// the slot back. The release/acquire pairs on the baton carry buffer-content
// visibility in both directions.
digraph handoff {
rankdir=LR;
bgcolor="transparent";
compound=true;
fontname="sans-serif";
node [fontname="sans-serif", fontsize=11];
edge [fontname="sans-serif", fontsize=10];
file [shape=cylinder, fillcolor="#eeeeee", style=filled, label="demovideo.raw"];
subgraph cluster_proactor {
label=" »Proactor« thread — playVideo() loop ";
labeljust="l";
style="filled,rounded"; fillcolor="#eef4ff"; color="#7092c0"; fontsize=12;
wait [shape=box, style="rounded,filled", fillcolor="#ffffff",
label="io_uring_wait_cqe()\n(blocking)"];
timer [shape=box, style="rounded,filled", fillcolor="#ffedcc",
label="frame-beat timer\n20 ms · multishot"];
ring [shape=record, style=filled, fillcolor="#ffffff",
label="ring buffers\ (RING_SIZ)|<s0>slot|<s1>slot|<s2>slot|<s3>…"];
}
subgraph cluster_gui {
label=" GTK / GUI thread ";
labeljust="l";
style="filled,rounded"; fillcolor="#eefaee"; color="#6bab6b"; fontsize=12;
disp [shape=box, style="rounded,filled", fillcolor="#ffffff",
label="EglDisplay::displayFrame()\nretrieveFrame() / completedFrame()"];
gpu [shape=box, style="rounded,filled", fillcolor="#ffffff",
label="GPU texture\n(glTexImage2D → draw)"];
}
baton [shape=box, style="filled", fillcolor="#e7d8ff", penwidth=1.6,
label="toDisplay_\nstd::atomic<Buffer*>"];
file -> ring [label="io_uring read", lhead=cluster_proactor];
timer -> wait [style=dotted, label="CQE (TICK_TAG)"];
ring -> baton [label="publish\nstore(release)", color="#5a2ca0", fontcolor="#5a2ca0"];
baton -> disp [label="retrieveFrame\nload(acquire)", color="#5a2ca0", fontcolor="#5a2ca0"];
disp -> gpu [label="upload + draw"];
disp -> baton [label="completedFrame\nstore(nullptr, release)",
style=dashed, color="#3a7a3a", fontcolor="#3a7a3a"];
{ rank=same; baton; }
}