Prototype: code improvements
- rename the states to better reflect their purpose - introduce getters for in BufferDispatcher
This commit is contained in:
parent
0cb388d4a7
commit
c9f9fec117
3 changed files with 176 additions and 152 deletions
|
|
@ -369,16 +369,13 @@
|
|||
</node>
|
||||
<node CREATED="1784162963010" ID="ID_1477358179" MODIFIED="1784163021269" TEXT="oder direkt die negierte ERRNO">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
IO_URING kann errno nicht sinnvoll direkt verwenden (errno ist eine globale variable)
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -843,11 +840,12 @@
|
|||
</node>
|
||||
<node CREATED="1779504863066" ID="ID_986008832" MODIFIED="1779504921775" TEXT="jeden Frame in den Output-Code aus dem Video-output-Vortrag schicken"/>
|
||||
<node CREATED="1783642371760" ID="ID_622863035" MODIFIED="1783642377238" TEXT="Konstruktions-Schema">
|
||||
<node CREATED="1783642378650" ID="ID_460419" MODIFIED="1783642391427" TEXT="naheliegend: einen Proactor zeigen">
|
||||
<node CREATED="1783642378650" ID="ID_460419" MODIFIED="1784222786307" TEXT="naheliegend: einen Proactor zeigen">
|
||||
<node CREATED="1783642938966" ID="ID_1117409154" MODIFIED="1783642955536" TEXT="mäßig sinnvoll"/>
|
||||
<node CREATED="1783642956739" ID="ID_141690825" MODIFIED="1783642968326" TEXT="hier nur ein Consumer"/>
|
||||
<node CREATED="1784222792149" ID="ID_1259331721" MODIFIED="1784222808639" TEXT="ist aber die Standard-Lösung (push)"/>
|
||||
</node>
|
||||
<node COLOR="#5b280f" CREATED="1783642985618" ID="ID_169416260" MODIFIED="1784052474215" TEXT="oder einen pull-Worker">
|
||||
<node COLOR="#5b280f" CREATED="1783642985618" FOLDED="true" ID="ID_169416260" MODIFIED="1784052474215" TEXT="oder einen pull-Worker">
|
||||
<icon BUILTIN="button_cancel"/>
|
||||
<node CREATED="1783642995707" ID="ID_216666777" MODIFIED="1783642999794" TEXT="das wäre näher an Lumiera"/>
|
||||
<node CREATED="1783643000727" ID="ID_737342556" MODIFIED="1783643655114" TEXT="der würde jeweils nur die Queue ausräumen"/>
|
||||
|
|
@ -894,8 +892,8 @@
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1783644313430" ID="ID_170028474" MODIFIED="1783788829437" TEXT="Prototyp entwickeln">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1783644336145" ID="ID_413309976" MODIFIED="1783788834125" TEXT="Skelett">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1783644336145" ID="ID_413309976" MODIFIED="1784222754616" TEXT="Skelett">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1783788677873" ID="ID_551733396" LINK="#ID_517750346" MODIFIED="1783788805152" TEXT="Lizenz: GPL v2+"/>
|
||||
<node COLOR="#338800" CREATED="1783644339455" ID="ID_932453573" MODIFIED="1783788820590" TEXT="CMake">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
|
|
@ -944,13 +942,24 @@
|
|||
<node COLOR="#338800" CREATED="1783644357376" ID="ID_1687423764" MODIFIED="1784142889926" TEXT="ein Proactor-Thread">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node CREATED="1783644382004" ID="ID_222096554" MODIFIED="1783644392847" TEXT="Handler">
|
||||
<node CREATED="1783644394013" ID="ID_599467746" MODIFIED="1783644398783" TEXT="Completion-Handler"/>
|
||||
<node CREATED="1783644399671" ID="ID_1684157516" MODIFIED="1783644406037" TEXT="Submission-Handler"/>
|
||||
<node CREATED="1783644407569" ID="ID_69520880" MODIFIED="1783644412668" TEXT="Display-Handler"/>
|
||||
<node COLOR="#338800" CREATED="1783644382004" ID="ID_222096554" MODIFIED="1784222739934" TEXT="Handler">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1783644394013" ID="ID_599467746" MODIFIED="1784222741419" TEXT="Completion-Handler">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1783644399671" ID="ID_1684157516" MODIFIED="1784222743125" TEXT="Submission-Handler">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1783644407569" ID="ID_69520880" MODIFIED="1784222744755" TEXT="Display-Handler">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1784222746115" ID="ID_1070022489" MODIFIED="1784222750547" TEXT="Shutdown-Handler">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1783900894906" ID="ID_1398236830" MODIFIED="1783900901714" TEXT="Design-Fragen">
|
||||
</node>
|
||||
<node COLOR="#234872" CREATED="1783900894906" ID="ID_1398236830" MODIFIED="1784222832373" TEXT="Design-Fragen">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783900916807" ID="ID_1965380217" LINK="https://claude.ai/share/2d09d5e6-1a47-45e9-b05b-500550fb0977" MODIFIED="1783964756096" STYLE="fork" TEXT="Design / Technologie-Dialog mit Claude">
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
|
|
@ -1411,9 +1420,7 @@
|
|||
</node>
|
||||
<node BACKGROUND_COLOR="#accdc3" COLOR="#3f4015" CREATED="1783956594083" ID="ID_1956714359" MODIFIED="1784136509799" STYLE="fork" TEXT="onTick + follow-up">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<pre>void onTick()
|
||||
  {
|
||||
|
|
@ -1434,8 +1441,7 @@
|
|||
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<edge COLOR="#808080" STYLE="bezier" WIDTH="thin"/>
|
||||
<icon BUILTIN="wizard"/>
|
||||
<icon BUILTIN="edit"/>
|
||||
|
|
@ -1863,7 +1869,8 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1783984352027" ID="ID_1602724940" MODIFIED="1783984359484" TEXT="Aufbau der Application-Shell">
|
||||
<node BACKGROUND_COLOR="#b2e9d4" COLOR="#014e21" CREATED="1783984352027" ID="ID_1602724940" MODIFIED="1784222687829" TEXT="Aufbau der Application-Shell">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1783984371031" ID="ID_1219649133" MODIFIED="1783984401222" TEXT="das Grundschema von letztem Jahr war nützlich">
|
||||
<node CREATED="1783984407459" ID="ID_321798557" MODIFIED="1783984427656" TEXT="„muß den GTK-Code gar nicht anschauen“"/>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1783985102373" ID="ID_734300736" MODIFIED="1784076612700" TEXT="Aber: die Ablaufsteuerung liegt jetzt nicht mehr (komplett) in GTK">
|
||||
|
|
@ -1951,7 +1958,9 @@
|
|||
<node CREATED="1783986866318" ID="ID_623423104" MODIFIED="1783986874503" TEXT="alles per Konstruktor-Verdrahtung"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1784076499094" ID="ID_1786219220" MODIFIED="1784076516947" TEXT="Player per Konstruktur-Initialisierung">
|
||||
<node COLOR="#1f267f" CREATED="1784076499094" ID="ID_1786219220" MODIFIED="1784222712766" TEXT="Player per Konstruktur-Initialisierung">
|
||||
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="back"/>
|
||||
<node CREATED="1784076561463" ID="ID_1248489844" MODIFIED="1784076582686" TEXT="läuft im GUI-Thread">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
|
|
@ -1962,6 +1971,7 @@
|
|||
<node CREATED="1784076675289" ID="ID_1648662317" MODIFIED="1784076685507" TEXT="unmittelbar hier den Thread starten"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1783644425567" ID="ID_238189215" MODIFIED="1783644429274" TEXT="Flow-Steuerung">
|
||||
<node CREATED="1784052955974" ID="ID_1491751742" MODIFIED="1784052978769" TEXT="da nun Proactor ⟹ getrieben vom Timer-Tick">
|
||||
<icon BUILTIN="idea"/>
|
||||
|
|
@ -1975,9 +1985,7 @@
|
|||
<icon BUILTIN="idea"/>
|
||||
<node BACKGROUND_COLOR="#fefc4e" COLOR="#351d75" CREATED="1784076979882" ID="ID_1843330900" MODIFIED="1784078228911" TEXT="Bemerkenswert: das hat sich durch die Konversation so ergeben">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...es war nicht so, daß Claude diese „Idee gehabt“ hätte — denn ich hatte die Konversation ja so geführt, daß Claude mir meine Konzept-Ansätze validiert und verfeinert. Dann habe ich das Prinzip formuliert, daß für Async-IO irgendwo eine State-Machine sein muß. Claude hat das aufgegriffen, validiert und verschärft; und damit war offensichtlich geworden, daß man diese State-Flag als Atomic auslegen kann. Das habe ich in dem Moment genauso »offensichtlich« gesehen, und Claude hat es ebenso formuliert.
|
||||
|
|
@ -1997,8 +2005,7 @@
|
|||
⟹ das wirft ein Licht darauf, wie dieses <i>scheinbar intelligente »Generieren« funktioniert, </i>auf Basis einer industriellen Daten-Technik, die Plausibilitäten integriert und interpoliert.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="back"/>
|
||||
</node>
|
||||
|
|
@ -2006,27 +2013,24 @@
|
|||
<font BOLD="true" NAME="SansSerif" SIZE="12"/>
|
||||
<icon BUILTIN="info"/>
|
||||
<node CREATED="1784078717834" ID="ID_17978925" MODIFIED="1784078954065" TEXT="IO beauftragen: FREE ⟶ READ"/>
|
||||
<node CREATED="1784078958419" ID="ID_1531715805" MODIFIED="1784078974343" TEXT="Übergabe an Display: READ ⟶ SHOW"/>
|
||||
<node CREATED="1784165852364" ID="ID_721661485" MODIFIED="1784167391018" TEXT="Warten auf Display: SHOW ⟶ WAIT">
|
||||
<node CREATED="1784078958419" ID="ID_1531715805" MODIFIED="1784221555857" TEXT="Übergabe an Display: READ ⟶ FEED"/>
|
||||
<node CREATED="1784165852364" ID="ID_721661485" MODIFIED="1784221545799" TEXT="Warten auf Display: FEED ⟶ SHOW">
|
||||
<linktarget COLOR="#6574c5" DESTINATION="ID_721661485" ENDARROW="Default" ENDINCLINATION="925;77;" ID="Arrow_ID_86014624" SOURCE="ID_312946304" STARTARROW="None" STARTINCLINATION="397;-23;"/>
|
||||
</node>
|
||||
<node CREATED="1784078981634" ID="ID_1578413583" MODIFIED="1784167275599" TEXT="Frame-Flip: WAOT ⟶ FREE"/>
|
||||
<node CREATED="1784078981634" ID="ID_1578413583" MODIFIED="1784221551696" TEXT="Frame-Flip: SHOW ⟶ FREE"/>
|
||||
<node CREATED="1784165852364" ID="ID_849967229" MODIFIED="1784167346009" TEXT="Abbrunch/End-of-File: markiert durch STOP">
|
||||
<linktarget COLOR="#6574c5" DESTINATION="ID_849967229" ENDARROW="Default" ENDINCLINATION="755;51;" ID="Arrow_ID_1693130420" SOURCE="ID_948621808" STARTARROW="None" STARTINCLINATION="411;-22;"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1784078466234" ID="ID_424139171" MODIFIED="1784078496653">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
hier muß auch die <b>Backpressure</b> beachtet und realisiert werden
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<node CREATED="1784078502730" ID="ID_846472947" MODIFIED="1784078534574" TEXT="darf nur weitergehen, nachdem der vorherige Frame aufgegriffen wurde"/>
|
||||
<node CREATED="1784078681486" ID="ID_1106864388" MODIFIED="1784078714572" TEXT="und darf nur neue IO beauftragen wenn der Zielpuffer vom Consumer freigegeben werden"/>
|
||||
</node>
|
||||
|
|
@ -2035,102 +2039,82 @@
|
|||
<node CREATED="1784079589221" ID="ID_1308906754" MODIFIED="1784079609606" TEXT="Optionen">
|
||||
<node CREATED="1784079611026" ID="ID_870843631" MODIFIED="1784079835110" TEXT="Buffer-Ring könnte global sichtbar sein">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Sofern er aus dem GUI-Thread alloziert wird, also bevor der Proactor-Thread startet, ist die Position für beide Threads sichtbar (und unveränderlich)
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<node CREATED="1784079641676" ID="ID_595831960" MODIFIED="1784079776456" TEXT="eine currentFrameNr ebenso">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Diese wäre dann ebenfalls teil der cross-Trade-Synchronisation (ebenfalls bewirkt durch release-Semantik auf dem State-Atomic)
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1784079653178" ID="ID_1804993764" MODIFIED="1784079727230" TEXT="oder der Displayer hat intern seine eigene FrameNr">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...nur als lokale Variable, die er jeweils hochzählt, wenn er einen Trigger bekommt (Nachteil: duplizierter State, dessen Konsistenz sich nur implizit ergibt und nicht offensichtlich ist)
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1784079838160" ID="ID_1763616932" MODIFIED="1784080020991" TEXT="könnte dem Displayer direkt gegeben werden">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Das wäre dann ein Pointer (const void *); seine Sichtbarkeit ergibt sich auch hier aus dem atomic-State
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<node CREATED="1784079873496" ID="ID_714454620" MODIFIED="1784079881936" TEXT="kann aber nicht per Dispatcher erfolgen"/>
|
||||
<node CREATED="1784079882711" ID="ID_102892347" MODIFIED="1784079907595" TEXT="muß dann ein Datenfeld sein (sinnvollerweise im Displayer)"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1784080062495" ID="ID_254917759" MODIFIED="1784080174245" TEXT="die zuletzt genanne Möglichkeit erscheint mir am natürlichsten">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...da ich immer in Zuständigkeiten denke, ist es mir unsympatisch, einen Satz gemeinsamer Zustands-Variablen zu verwenden
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1784080203172" ID="ID_952531619" MODIFIED="1784080213143" TEXT="daraus ergibt sich die Datenstruktur">
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1784080203172" ID="ID_952531619" MODIFIED="1784222609101" TEXT="daraus ergibt sich die Datenstruktur">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1784080214847" ID="ID_1165930889" MODIFIED="1784080245515" TEXT="und zwar gehören damit die Buffer dem Proactor-Thread"/>
|
||||
<node CREATED="1784080390813" ID="ID_1044489570" MODIFIED="1784080418199" TEXT="Allocation und Ownership">
|
||||
<node CREATED="1784080461760" ID="ID_1762147278" MODIFIED="1784080535764" TEXT="Buffer sehr groß ⟹ einzeln allozieren">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...das gilt für ein Prod-System, in dem der Speicher framentiert ist, und man vermutlich Buffer-Pools hat
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1784080449077" ID="ID_1803805054" MODIFIED="1784080659901" TEXT="einfach wäre ein riesiges Array auf dem Heap">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Für die Demo ist das die offensichtliche Lösung: man bekommt unique-ownership und Subscript-Operator einfach vom std::unique_ptr. Wenn man den notwendigen Speicher nicht bekommt, dann läuft die Demo eh nicht, also wozu die Umstände?
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="back"/>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -2165,16 +2149,13 @@
|
|||
<node CREATED="1784131354971" ID="ID_458757211" MODIFIED="1784131366411" TEXT="diese ist jedoch festgelegt">
|
||||
<node CREATED="1784131367993" ID="ID_55736035" MODIFIED="1784131407585" TEXT="durch die Forderung nach Lesbarkeit (�� Demo-Code)">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
heißt: hier gibt es keine Möglichkeit, <i>ein Auge zuzudrücken</i>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1784131409804" ID="ID_359711423" MODIFIED="1784131419742" TEXT="durch das einmal gewählte Domain-Scoping"/>
|
||||
</node>
|
||||
|
|
@ -2188,16 +2169,13 @@
|
|||
</node>
|
||||
<node CREATED="1784136965047" ID="ID_1744030854" MODIFIED="1784137036831" TEXT="zu kurz gedacht: es ist eine Zugriffs-Klammer">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Eine Operation zum Zugriff und eine Operation um den abgeschlossenen Zugriff zu markieren; zudem gibt es auch noch den Dispatcher.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1784137038242" ID="ID_1199476075" MODIFIED="1784143571509" TEXT="dann doch ein klassisches OO-Callback-Interface">
|
||||
|
|
@ -2215,16 +2193,13 @@
|
|||
<node CREATED="1784145655032" ID="ID_815825627" MODIFIED="1784145664817" TEXT="macht man das mit C++?"/>
|
||||
<node CREATED="1784145665437" ID="ID_1276445757" MODIFIED="1784145828191" TEXT="besser direkt mit den POSIX-Funktionen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Mehrere Argumente dafür: man könnte die low-level-Flags setzen (wie <code>O_CLOEXEX, O_NOFOLLOW, </code>oder gar <code>O_DIRECT</code>). Das Öffnen ist <i>atomic,</i>  d.h. das File kann nicht mehr gelöscht/verschoben werden beform man das Filehandle hat (was bei einem getrennten STAT und Path-Check durchaus möglich ist)
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1784147238004" ID="ID_973311307" LINK="https://man7.org/linux/man-pages/man2/open.2.html" MODIFIED="1784147251992" TEXT="man: open()"/>
|
||||
</node>
|
||||
|
|
@ -2236,9 +2211,7 @@
|
|||
<node CREATED="1784151717872" ID="ID_1035839641" MODIFIED="1784151726466" TEXT="das ist eine spezielle Submission in den URing"/>
|
||||
<node BACKGROUND_COLOR="#e6dfa8" COLOR="#690f14" CREATED="1784151807158" ID="ID_161068537" MODIFIED="1784152246318" TEXT="⟹ muß URing um +1 Slot größer dimensionieren">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Begründung
|
||||
|
|
@ -2261,8 +2234,7 @@
|
|||
</li>
|
||||
</ul>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node CREATED="1784151734786" ID="ID_546021072" MODIFIED="1784151801321" TEXT="verwende hier meine Hilfsfunktion für Chrono ⟼ Kernel-Timespec">
|
||||
|
|
@ -2270,8 +2242,8 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1784143738263" ID="ID_1385880788" MODIFIED="1784152297376" TEXT="Handler-Loop">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1784143738263" ID="ID_1385880788" MODIFIED="1784222595782" TEXT="Handler-Loop">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1784143781367" ID="ID_1463866164" MODIFIED="1784165740325" TEXT="gelesene Daten entgegennehmen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1784165743594" ID="ID_465943099" MODIFIED="1784165755001" TEXT="ERRNO steckt im cqe.res">
|
||||
|
|
@ -2300,23 +2272,18 @@
|
|||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1784166180437" ID="ID_411616254" MODIFIED="1784166202948">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
verwende hier den zweiten Cursor: <font face="Monospaced" color="#271bd4">nextShow_</font>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1784166214698" ID="ID_255228689" MODIFIED="1784166237247" TEXT="darüber auf den State dieses Buffer-Slot zugreifen"/>
|
||||
<node CREATED="1784166238079" ID="ID_503678940" MODIFIED="1784166404098" TEXT="wenn Daten da sind (state == SHOW) ⟹ trigger Displayer">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
...und zwar via Glib::Dispatcher ⟶ GUI-Thread.
|
||||
|
|
@ -2325,21 +2292,17 @@
|
|||
Der zugehörige Handler-Code läuft dann bei nächster Gelegenheit in der GUI-Event-Loop, und holt sich per Callback (Interface PixelFeed) die Daten; in diesem Callback muß die Read-Barrier realisiert sein, damit der GUI-Thread alle vor diesem Punkt erfolgten Datenänderungen auch tatsächlich sieht
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1784166414946" ID="ID_1720545051" MODIFIED="1784166498112" TEXT="wenn hier Short-Read markiert ⟹ Player anhalten">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Beachte: das darf erst hier passieren, weil wir hier den nächst niedersten erwarteten Frame anschauen; da wir immer etwas im Voraus lesen, werden wir auch ein end-of-File schon einige Ticks früher markieren, müssen aber die Schleife noch solange weiterlaufen lassen, bis die letzten erfolgreich gelesenen Frames in die Anzeige übertragen wurden
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fafe99" COLOR="#fa002a" CREATED="1784166503838" ID="ID_645230473" MODIFIED="1784166532804" TEXT="Bei genauerer Betrachtung : tückisches Korrektheits-Problem hier">
|
||||
|
|
@ -2350,34 +2313,29 @@
|
|||
<node CREATED="1784166606710" ID="ID_499843773" MODIFIED="1784166618527" TEXT="in beiden Fällen ist der Cursor inkonsitent"/>
|
||||
<node CREATED="1784166652416" ID="ID_261339357" MODIFIED="1784166866154">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
brauche doch einen 3.Cursor: <font face="Monospaced" color="#5f15de">currShow_</font>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#d9b995" COLOR="#690f14" CREATED="1784165814417" ID="ID_312946304" MODIFIED="1784167391017" TEXT="muß zwingend weitere State-Transition einfürhen: WAIT">
|
||||
<node BACKGROUND_COLOR="#d9b995" COLOR="#690f14" CREATED="1784165814417" ID="ID_312946304" MODIFIED="1784221578895" TEXT="muß zwingend weitere State-Transition einfürhen: FEED">
|
||||
<arrowlink COLOR="#6574c5" DESTINATION="ID_721661485" ENDARROW="Default" ENDINCLINATION="925;77;" ID="Arrow_ID_86014624" STARTARROW="None" STARTINCLINATION="397;-23;"/>
|
||||
<arrowlink COLOR="#a03127" DESTINATION="ID_194548529" ENDARROW="Default" ENDINCLINATION="373;0;" ID="Arrow_ID_726120332" STARTARROW="None" STARTINCLINATION="-39;152;"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
<node CREATED="1784167398651" ID="ID_977847492" MODIFIED="1784167422438" TEXT="denn der 3.Cursor kann erst hier bewegt werden"/>
|
||||
<node CREATED="1784167422935" ID="ID_953106086" MODIFIED="1784167433471" TEXT="und es ist nun der 3.Cursor, der vom GUI-Thread verwendet wird"/>
|
||||
<node CREATED="1784167433959" ID="ID_1914570598" MODIFIED="1784167447134">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
also brauche ich die cross-Thread-Barriere <b>erst hier</b>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -2409,48 +2367,75 @@
|
|||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1784142980731" ID="ID_1146524396" MODIFIED="1784142995774">
|
||||
<richcontent TYPE="NODE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
also <i>keine explizite</i> Steuerung
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1784143310222" ID="ID_1598149960" MODIFIED="1784143340787" TEXT="vielmehr sorgt die feste zyklische Buffer-Struktur für die Limitierung"/>
|
||||
<node CREATED="1784143015199" ID="ID_218469149" MODIFIED="1784143039421" TEXT="zwei Phasen schreiten jeweils so schnell voran wie derzeig möglich">
|
||||
<node CREATED="1784143040300" ID="ID_227838217" MODIFIED="1784143254426" TEXT="Phase-1 : read-Submissions beauftragen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
ist jeweils nur möglich wenn der dafür vorgesehene Buffer bereits frei geworden ist
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
<node CREATED="1784143055979" ID="ID_1727640820" MODIFIED="1784143309405" TEXT="Phase-2 : eingelesene Daten übergeben">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
Ist nur möglich wenn diese Daten für den erwartungsgemäß nächsten Frame bereits da sind, und der unmittelbar vorausgegangene Frame schon komplett vom Video-Displayer übernommen wurde
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1784221175896" ID="ID_777175706" MODIFIED="1784222589807" TEXT="Ausreifen und Testen">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1784221197676" ID="ID_888318010" MODIFIED="1784221200745" TEXT="Code-Verbesserungen">
|
||||
<node CREATED="1784221201656" ID="ID_206094356" MODIFIED="1784221217727" TEXT="Getter im BufferDispatcher einführen">
|
||||
<node CREATED="1784221218666" ID="ID_847912873" MODIFIED="1784221225933" TEXT="für current-state und current-frame"/>
|
||||
<node CREATED="1784221226449" ID="ID_1575870011" MODIFIED="1784221251514" TEXT="verbirgt den kaskadierenden Zugriff über den outer-Pointer"/>
|
||||
<node CREATED="1784221253300" ID="ID_1527096674" MODIFIED="1784221274998" TEXT="macht außerdem die Verwendungsstelle lesbarer (Intention im Namen)"/>
|
||||
</node>
|
||||
<node CREATED="1784221286953" ID="ID_468705787" MODIFIED="1784221294691" TEXT="State-Flags umbenennen">
|
||||
<node CREATED="1784221295711" ID="ID_194548529" MODIFIED="1784221395809" TEXT="die Bedeutung von SHOW hat sich geändert">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
im State SHOW pasiert jetzt gar nicht mehr das Display, sondern es bedeutet nun, daß der Frame weitergegeben werden muß
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<linktarget COLOR="#a03127" DESTINATION="ID_194548529" ENDARROW="Default" ENDINCLINATION="373;0;" ID="Arrow_ID_726120332" SOURCE="ID_312946304" STARTARROW="None" STARTINCLINATION="-39;152;"/>
|
||||
</node>
|
||||
<node CREATED="1784221423989" ID="ID_1367029376" MODIFIED="1784221595584" TEXT="nenne diese Phase jetzt FEED">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head/>
|
||||
<body>
|
||||
<p>
|
||||
suche einen 4-Buchstaben-Namen, da bin ich Ästhet. PUSH wäre auch denkbar, natürlich wäre PROPAGATE viel korrekter ;-)
|
||||
</p>
|
||||
</body>
|
||||
</html></richcontent>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1784222841942" ID="ID_74519525" MODIFIED="1784222846614" TEXT="zum Laufen bringen">
|
||||
<icon BUILTIN="flag-pink"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
|
|||
|
|
@ -40,13 +40,32 @@ auto calcSrcFrame = [](size_t runningNr){ return START_FRAME + runningNr % MAX_L
|
|||
//-----------------hard-coded-config--
|
||||
|
||||
|
||||
/**
|
||||
* Read video frames from a raw video file and pass them to OpenGL display.
|
||||
* Using a »Proactor« thread to coordinate reading via IO_URING.
|
||||
* Allocates a set of frame-sized buffers (using #RING_SIZ buffers)
|
||||
* and uses them cyclically, first adding new tasks to read a frame-block
|
||||
* from the file, receiving completed tasks to hand-over the next frame
|
||||
* driven by a frame-beat timer, that is also based on IO_URING.
|
||||
* Each buffer »slot« is associated with a #BuffState flag, implemented
|
||||
* as `std::atomic` to also serve for cross-thread visibility.
|
||||
* @note UringVideoPlayer must be constructed in the GTK UI thread,
|
||||
* yet will immediately launch the »Proactor« thread from the ctor.
|
||||
* @remarks
|
||||
* - the source video and layout is hard wired
|
||||
* - playback will either be looped (if the loop fits into the source video)
|
||||
* - otherwise, when encountering end-of-file, or when the GTK window is closed,
|
||||
* the »Proactor« thread will terminate.
|
||||
* - frames will be submitted to display at the regular timer beats,
|
||||
* whenever they are ready; frames delayed by IO will slip to the next beat.
|
||||
*/
|
||||
class UringVideoPlayer
|
||||
: NonCopyable
|
||||
{
|
||||
using VideoDisplay = EglDisplay<uint8_t, VIDEO_WIDTH,VIDEO_HEIGHT>;
|
||||
using Buffer = VideoDisplay::Buffer;
|
||||
|
||||
enum BuffState { FREE=0, READ, SHOW, WAIT, STOP };
|
||||
enum BuffState { FREE, READ, FEED, SHOW, STOP };
|
||||
using AtomicBuffState = std::atomic<BuffState>;
|
||||
|
||||
using BufferAlloc = unique_ptr<Buffer[]>;
|
||||
|
|
@ -65,10 +84,15 @@ class UringVideoPlayer
|
|||
void completedFrame() override;
|
||||
|
||||
UringVideoPlayer& player_;
|
||||
|
||||
public:
|
||||
BufferDispatcher (UringVideoPlayer& player)
|
||||
: player_{player}
|
||||
{ }
|
||||
|
||||
private:
|
||||
Buffer& getCurrentFrame();
|
||||
AtomicBuffState& getCurrentFrameState();
|
||||
};
|
||||
|
||||
size_t nextRead_{0};
|
||||
|
|
@ -108,7 +132,7 @@ class UringVideoPlayer
|
|||
void
|
||||
UringVideoPlayer::playVideo()
|
||||
{
|
||||
/* ===== initial setup ===== */
|
||||
/* =============== initial-setup =============== */
|
||||
int inputFD = open (RAW_VIDEO_INPUT_FILE.c_str(), O_RDONLY);
|
||||
if (inputFD < 0)
|
||||
__FAIL ("open file \""+RAW_VIDEO_INPUT_FILE+"\"");
|
||||
|
|
@ -122,23 +146,23 @@ UringVideoPlayer::playVideo()
|
|||
io_uring_queue_init (RING_SIZ+1, &uRing, /*flags*/ 0 ); // Note: one additional »slot« for the timer event(s)
|
||||
|
||||
// Setup periodic frame beat, firing infinitely
|
||||
const auto TICK_TAG = UINT64_MAX; // special marker for timer events (different from possible frame numbers)
|
||||
const auto TICK_TAG = UINT64_MAX; // special marker for timer events (differs from possible frame numbers)
|
||||
auto timespec = asKernelTimespec (40ms); // 25fps ≙ 40ms per frame
|
||||
io_uring_sqe* timerSubmission = io_uring_get_sqe (&uRing);
|
||||
io_uring_sqe* timerSubmission{io_uring_get_sqe (&uRing)};
|
||||
io_uring_prep_timeout (timerSubmission, ×pec, /*no count limit*/ 0, IORING_TIMEOUT_MULTISHOT);
|
||||
io_uring_sqe_set_data64(timerSubmission, TICK_TAG);
|
||||
|
||||
addNextReadSubmissions (uRing, inputFD);
|
||||
io_uring_submit (&uRing);
|
||||
|
||||
/* ===== proactor-loop ===== */
|
||||
/* =============== proactor-loop =============== */
|
||||
playing_ = true;
|
||||
while (playing_.load (std::memory_order_acquire))
|
||||
{
|
||||
io_uring_cqe* completion;
|
||||
// blocking wait for the next completion entry
|
||||
int res = io_uring_wait_cqe (&uRing, &completion);
|
||||
if (0 > res)
|
||||
if (res < 0)
|
||||
__FAIL ("retrieval of io_uring completion failed");
|
||||
|
||||
uint64_t tag = completion->user_data;
|
||||
|
|
@ -167,7 +191,7 @@ UringVideoPlayer::addNextReadSubmissions (io_uring& uRing, int inputFD)
|
|||
assert (0 < inputFD);
|
||||
const size_t BUFFSIZ = sizeof(Buffer);
|
||||
|
||||
while (buffState_[nextRead_ % RING_SIZ] == FREE)
|
||||
while (FREE == buffState_[nextRead_ % RING_SIZ])
|
||||
{
|
||||
size_t srcOffset = calcSrcFrame (nextRead_);
|
||||
io_uring_sqe* readSubmission = io_uring_get_sqe (&uRing);
|
||||
|
|
@ -191,12 +215,12 @@ UringVideoPlayer::handleCompletedRead (io_uring_cqe& completion)
|
|||
__FAIL ("async read of frame from video file failed");
|
||||
|
||||
size_t frameNr = completion.user_data; // Note: completion was marked with the frameNr as »user data«
|
||||
auto& state = buffState_[frameNr % RING_SIZ]; // Can thus pick buffer slot based on frame number, modulus ring size
|
||||
auto& state = buffState_[frameNr % RING_SIZ]; // Can thus pick buffer slot based on frame number, cycling through the ring
|
||||
|
||||
if (completion.res != sizeof(Buffer))
|
||||
state.store(STOP, std::memory_order_relaxed); // Insufficient read, possibly end-of-file => signal stop of playback (to ourselves)
|
||||
else
|
||||
state.store(SHOW, std::memory_order_relaxed); // Success; frame data is in the buffer => mark ready for use at the next tick event
|
||||
state.store(FEED, std::memory_order_relaxed); // Success; frame data is in the buffer => mark ready for use at the next tick event
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -215,12 +239,12 @@ UringVideoPlayer::maybeDisplayFrame()
|
|||
auto prevState = buffState_[currShow_ % RING_SIZ].load (std::memory_order_relaxed);
|
||||
auto nextState = buffState_[nextShow_ % RING_SIZ].load (std::memory_order_relaxed);
|
||||
|
||||
if (nextState == SHOW and prevState == FREE)
|
||||
if (nextState == FEED and prevState == FREE)
|
||||
{ // can hand over this next frame to the VideoDisplay in the GUI-thread
|
||||
currShow_ = nextShow_;
|
||||
++nextShow_;
|
||||
// mark state to wait for display to complete; this also creates a write barrier
|
||||
buffState_[currShow_ % RING_SIZ].store (WAIT, std::memory_order_release);
|
||||
// mark state to wait for display completion; this also creates a write barrier
|
||||
buffState_[currShow_ % RING_SIZ].store (SHOW, std::memory_order_release);
|
||||
// Notify GUI thread via Glib::Dispatcher
|
||||
dispatchFrame_();
|
||||
}
|
||||
|
|
@ -239,9 +263,9 @@ UringVideoPlayer::Buffer*
|
|||
UringVideoPlayer::BufferDispatcher::retrieveFrame()
|
||||
{
|
||||
// retrieve buffer state from proactor-thread; this also creates a read barrier
|
||||
auto frameState = player_.buffState_[player_.currShow_ % RING_SIZ].load (std::memory_order_acquire);
|
||||
if (frameState == WAIT)
|
||||
return & player_.buffer_[player_.currShow_ % RING_SIZ];
|
||||
auto frameState = getCurrentFrameState().load (std::memory_order_acquire);
|
||||
if (frameState == SHOW)
|
||||
return & getCurrentFrame();
|
||||
else
|
||||
return nullptr;
|
||||
// (can happen only in boundary cases)
|
||||
|
|
@ -252,7 +276,22 @@ void
|
|||
UringVideoPlayer::BufferDispatcher::completedFrame()
|
||||
{
|
||||
// mark buffer as display complete for the proactor-thread; this also creates a write barrier
|
||||
player_.buffState_[player_.currShow_ % RING_SIZ].store (FREE, std::memory_order_release);
|
||||
getCurrentFrameState().store (FREE, std::memory_order_release);
|
||||
}
|
||||
|
||||
|
||||
UringVideoPlayer::Buffer&
|
||||
UringVideoPlayer::BufferDispatcher::getCurrentFrame()
|
||||
{
|
||||
auto currFrame = player_.currShow_;
|
||||
return player_.buffer_[currFrame % RING_SIZ];
|
||||
}
|
||||
|
||||
UringVideoPlayer::AtomicBuffState&
|
||||
UringVideoPlayer::BufferDispatcher::getCurrentFrameState()
|
||||
{
|
||||
auto currFrame = player_.currShow_;
|
||||
return player_.buffState_[currFrame % RING_SIZ];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@ void
|
|||
EglDisplay<PIX,WIDTH,HEIGHT>::displayFrame()
|
||||
{
|
||||
|
||||
auto currFrame = pixelFeed_.retrieveFrame();
|
||||
auto* currFrame = pixelFeed_.retrieveFrame();
|
||||
if (not currFrame) return;
|
||||
|
||||
// pick up current buffer with RGB data
|
||||
|
|
|
|||
Loading…
Reference in a new issue