Library: identify reason for deadlock

- the deadlock was caused by leaking error state through the C-style lumiera_error

- but the reason for the deadlock lies in the »convenience shortcut«
  in the Object-Monitor scope guard for entering a wait state immediately.
  This function undermines the unlocking-guarantee, when an exception
  emanates from within the wait() function itself.
This commit is contained in:
Fischlurch 2023-09-30 23:55:42 +02:00
parent 48d6f0fae3
commit fdd8e2d595
5 changed files with 296 additions and 26 deletions

View file

@ -474,7 +474,10 @@ namespace lib {
/** convenience shortcut:
* Locks and immediately enters wait state,
* observing a condition defined as member function. */
* observing a condition defined as member function.
* @deprecated WARNING this function is not correct! ////////////////////////////TICKET #1051
* Lock is not released on error from within wait()
*/
template<class X>
Lock(X* it, bool (X::*method)(void))
: mon_(getMonitor(it))

View file

@ -224,7 +224,7 @@ namespace lib {
using BAS::BAS;
/** Wrapper to capture a success/failure indicator and possibly a computation result */
lib::Result<RES> result_{error::Logic{"Thread still running; need to join() first."}};
lib::Result<RES> result_{error::Logic{"No result yet, thread still running; need to join() first."}};
template<class FUN, typename...ARGS>

View file

@ -195,7 +195,8 @@ namespace control {
void
awaitStateProcessed() const
{
Lock blockWaiting(unConst(this), &DispatcherLoop::isStateSynched); ///////////////////////TICKET #1057 : const correctness on wait predicate
Lock(unConst(this)).wait(unConst(*this), &DispatcherLoop::isStateSynched); ///////////////////////TICKET #1051 : support bool-λ and fix the correctness-error in the »convenience shortcut«
////////////////////////TICKET #1057 : const correctness on wait predicate
// wake-up typically by updateState()
}

View file

@ -351,7 +351,7 @@ namespace test {
public:
InvocationProducer (SyncBarrier& trigger)
: barrier_{trigger}
, thread_{"command producer", [&]{ fabricateCommands(); }}
, thread_{"producer", [&]{ fabricateCommands(); }}
{ }
~InvocationProducer()
@ -391,7 +391,6 @@ namespace test {
};
/* == controlling code in main thread == */
try{
Time prevState = testCommandState;
FSecs expectedOffset{0};
@ -424,19 +423,6 @@ namespace test {
__DELAY__
CHECK (testCommandState - prevState == Time(expectedOffset));
}
catch(lumiera::Error& ex)
{
cout << "##### Lumix-Ex: "<<ex.what()<<endl;
}
catch(std::exception& jaleck)
{
cout << "##### Standard-Ex: "<<jaleck.what()<<endl;
}
catch(...)
{
cout << "WOOT??"<<endl;
}
}// Note: leaving this scope blocks for joining all producer threads
};

View file

@ -80526,7 +80526,8 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1696037017218" ID="ID_166804637" MODIFIED="1696037028972" TEXT="main-Thread blockt im Destruktor"/>
<node CREATED="1696037163527" ID="ID_1110298475" MODIFIED="1696037175948" TEXT="ich sehe zuletzt: deactivateCommandProecssing: Session command interface closed."/>
</node>
<node CREATED="1696037187379" ID="ID_1472154127" MODIFIED="1696037197430" TEXT="Feststellungen">
<node CREATED="1696037187379" ID="ID_1472154127" MODIFIED="1696110527686" TEXT="Untersuchung">
<icon BUILTIN="edit"/>
<node CREATED="1696037199267" ID="ID_791125343" MODIFIED="1696037224734" TEXT="Mischzustand: der Dispatcher-Thread l&#xe4;uft auf dem alten Framework">
<icon BUILTIN="messagebox_warning"/>
<node COLOR="#338800" CREATED="1696039674199" ID="ID_1718267866" MODIFIED="1696039763561" TEXT="sicherheitshalber auch gleich umstellen">
@ -80569,18 +80570,287 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696037316298" ID="ID_804937793" MODIFIED="1696037339615" TEXT="unklar: wer sollte den Dispatcher-Thread aufwecken?">
<icon BUILTIN="forward"/>
<node COLOR="#435e98" CREATED="1696037316298" ID="ID_804937793" MODIFIED="1696119125636" TEXT="wer sollte den Dispatcher-Thread aufwecken?">
<icon BUILTIN="help"/>
<node CREATED="1696039648897" ID="ID_1751198515" MODIFIED="1696039665811" TEXT="normalerweise sollten das doch die ankommenden Commands bewirken"/>
<node CREATED="1696119047052" ID="ID_936117034" MODIFIED="1696119060820" TEXT="so ist es und das passiert auch tats&#xe4;chlich (Debugger)"/>
<node CREATED="1696119072544" ID="ID_1846378296" MODIFIED="1696119107817">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
aber hier schl&#228;ft der Dispatcher-Thrad gar nicht &#8212; sondern <b>wartet auf das Lock</b>
</p>
</body>
</html></richcontent>
<icon BUILTIN="messagebox_warning"/>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1696037228668" ID="ID_1851104736" MODIFIED="1696037273970" TEXT="warum sehe ich das wieder-&#xd6;ffnen des Command-Interfaces nicht?">
</node>
<node COLOR="#435e98" CREATED="1696037228668" ID="ID_1851104736" MODIFIED="1696119163653" TEXT="warum sehe ich das wieder-&#xd6;ffnen des Command-Interfaces nicht?">
<font NAME="SansSerif" SIZE="12"/>
<icon BUILTIN="help"/>
<node CREATED="1696037275093" ID="ID_1726964186" MODIFIED="1696037285735" TEXT="fliegt hier eine Exception??">
<icon BUILTIN="idea"/>
</node>
<node COLOR="#5b280f" CREATED="1696039593569" ID="ID_843115246" MODIFIED="1696039620815" TEXT="nein (try-catch eingebaut)">
<icon BUILTIN="button_cancel"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696071955817" ID="ID_1414770650" MODIFIED="1696081429821" TEXT="Bingo! ein error::Logic vom noch-leeren Result">
<arrowlink COLOR="#ea255e" DESTINATION="ID_1817962717" ENDARROW="Default" ENDINCLINATION="13;-34;" ID="Arrow_ID_1502503112" STARTARROW="None" STARTINCLINATION="-60;3;"/>
<icon BUILTIN="broken-line"/>
</node>
<node CREATED="1696081298897" ID="ID_1868082673" MODIFIED="1696081376953">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
&#10233; der Test-Controller-Thread kommt gar nicht dazu,
</p>
<p>
auf das Ende der Worker zu warten
</p>
</body>
</html></richcontent>
</node>
</node>
<node COLOR="#435e98" CREATED="1696072400009" ID="ID_1841370105" MODIFIED="1696119175236" TEXT="wo / von wem wird der ausgeworfen?">
<icon BUILTIN="help"/>
<node CREATED="1696081214992" ID="ID_1035877149" MODIFIED="1696081226551" TEXT="kommt aus Monitor::wait()">
<icon BUILTIN="info"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1696081133452" ID="ID_1817962717" MODIFIED="1696081429821">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
ein <i>verschleppter </i>Error-State
</p>
</body>
</html>
</richcontent>
<linktarget COLOR="#ea255e" DESTINATION="ID_1817962717" ENDARROW="Default" ENDINCLINATION="13;-34;" ID="Arrow_ID_1502503112" SOURCE="ID_1414770650" STARTARROW="None" STARTINCLINATION="-60;3;"/>
<icon BUILTIN="broken-line"/>
<node CREATED="1696081456787" ID="ID_1943309176" MODIFIED="1696081469917" TEXT="jeder ThreadJoinable setzt versehentlich im ctor den Error-State"/>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1696081471577" ID="ID_1910682637" MODIFIED="1696119881017" TEXT="hier r&#xe4;cht sich wieder das inkonsitente Error-Handling-Konzept">
<arrowlink COLOR="#734d4b" DESTINATION="ID_693954886" ENDARROW="Default" ENDINCLINATION="61;-139;" ID="Arrow_ID_921866413" STARTARROW="None" STARTINCLINATION="-390;17;"/>
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1696081526120" ID="ID_1896518266" MODIFIED="1696081543442" TEXT="der C-Code f&#xfc;hrt thread-local sticky Error-States ein"/>
<node CREATED="1696081544119" ID="ID_588082490" MODIFIED="1696081570191" TEXT="das C++ Exception-Handling nimmt keine R&#xfc;cksicht auf C"/>
<node CREATED="1696081571283" ID="ID_970986418" MODIFIED="1696081613486" TEXT="wir haben versucht, beides miteinander zu verknoten">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...und zwar an der einzigen Stelle, an der das zuverl&#228;ssig m&#246;glich ist: im Konstruktur von Exceptions
</p>
</body>
</html>
</richcontent>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696081614501" ID="ID_459919469" MODIFIED="1696081636718" TEXT="sobald man Exceptions als Datentyp konstruiert, f&#xfc;hrt das zu Problemen">
<icon BUILTIN="clanbomber"/>
</node>
<node COLOR="#713bb7" CREATED="1696110701766" ID="ID_1580901081" MODIFIED="1696110730061" TEXT="hier wird eine Entscheidung zunehmend dringend">
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696119213950" ID="ID_1474208134" MODIFIED="1696119236987" STYLE="fork" TEXT="damit w&#xe4;re die Ver&#xe4;nderung identifiziert, die den Test gebrochen hat">
<icon BUILTIN="idea"/>
</node>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696119176376" ID="ID_1102042597" MODIFIED="1696119790825" TEXT="es sollte trotzdem nicht zum Deadlock kommen...">
<icon BUILTIN="broken-line"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696119319135" ID="ID_252514263" MODIFIED="1696119336272" TEXT="zu erwartendes Verhalten">
<icon BUILTIN="yes"/>
<node CREATED="1696119247081" ID="ID_1738546690" MODIFIED="1696119272977" TEXT="der Test-Controller-Thread f&#xe4;llt raus"/>
<node CREATED="1696119277549" ID="ID_1653664780" MODIFIED="1696119290721" TEXT="der deque-dtor will die Threads joinen, diese laufen aber noch"/>
<node CREATED="1696119291931" ID="ID_370824920" MODIFIED="1696119314748" TEXT="da niemand mehr blockt, sollten die Threads irgendwann ihre Arbeit gemacht haben"/>
<node CREATED="1696119342372" ID="ID_717868506" MODIFIED="1696119352142" TEXT="und dann kehrt auch das join() zur&#xfc;ck"/>
</node>
<node CREATED="1696119354771" ID="ID_597533525" MODIFIED="1696119368139" TEXT="beobachtete Situation">
<icon BUILTIN="info"/>
<node CREATED="1696119371496" ID="ID_280882639" MODIFIED="1696119387379" TEXT="Test-Controller-Thread steht im Futex von Thread-join()"/>
<node CREATED="1696119388607" ID="ID_44228871" MODIFIED="1696119445874" TEXT="der Session-Thread m&#xf6;chte DispatcherLoop::awaitAction() machen &#xd83e;&#xdc32; blockt im Lock"/>
<node CREATED="1696119449493" ID="ID_1470434035" MODIFIED="1696119475208" TEXT="die Producer-Threads m&#xf6;chten DispatcherLoop::enqueue() machen &#xd83e;&#xdc32; blockt im Lock"/>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1696119485297" ID="ID_340575780" MODIFIED="1696119500059" TEXT="wer h&#xe4;lt dann das Lock?">
<icon BUILTIN="help"/>
<node CREATED="1696119504254" ID="ID_458863936" MODIFIED="1696119525043" TEXT="Detail-Debugging: das pthread-Mutex-Objekt zeigt seinen Owner">
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1696119526100" ID="ID_593631628" MODIFIED="1696119555643" TEXT="der Owner ist immer noch der Thread-Controller Thread">
<icon BUILTIN="broken-line"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696119586947" ID="ID_41292943" MODIFIED="1696119624718" STYLE="fork" TEXT="aaaber ... der ist doch aus dem Scope mit dem Lock-Guard raus???">
<icon BUILTIN="smiley-angry"/>
</node>
<node BACKGROUND_COLOR="#fdfdcf" COLOR="#ff0000" CREATED="1696119627366" ID="ID_9801066" MODIFIED="1696119976164">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
Debugger &#10233; Lock-Guard-<b>Destruktor wird nicht aufgerufen</b>
</p>
</body>
</html>
</richcontent>
<arrowlink COLOR="#db3b65" DESTINATION="ID_893400394" ENDARROW="Default" ENDINCLINATION="214;-12;" ID="Arrow_ID_1289856285" STARTARROW="None" STARTINCLINATION="-385;17;"/>
<icon BUILTIN="broken-line"/>
</node>
<node CREATED="1696119704813" ID="ID_271843832" MODIFIED="1696119725139" TEXT="??!">
<icon BUILTIN="smiley-oh"/>
</node>
<node CREATED="1696119709771" ID="ID_870266168" MODIFIED="1696119719039" TEXT="????!!">
<icon BUILTIN="smily_bad"/>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696119729864" ID="ID_1528519295" MODIFIED="1696119766685">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
die Exception fliegt ja <b>aus dem Konstruktor</b>&#160;vom Guard
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
</node>
</node>
</node>
<node COLOR="#435e98" CREATED="1696119796679" ID="ID_1360508343" MODIFIED="1696119834888">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
(ja dann <font size="5">KANN</font>s ja gar nicht funktionieren)
</p>
</body>
</html>
</richcontent>
<font NAME="SansSerif" SIZE="11"/>
<icon BUILTIN="ksmiletris"/>
</node>
</node>
<node CREATED="1696109856041" ID="ID_130019164" MODIFIED="1696110849648" TEXT="Fazit">
<icon BUILTIN="forward"/>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1696109861199" ID="ID_693954886" MODIFIED="1696119872703" TEXT="Entscheidung die Kopplung von C-Flag und Exceptions betreffend">
<linktarget COLOR="#734d4b" DESTINATION="ID_693954886" ENDARROW="Default" ENDINCLINATION="61;-139;" ID="Arrow_ID_921866413" SOURCE="ID_1910682637" STARTARROW="None" STARTINCLINATION="-390;17;"/>
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
<node CREATED="1696109905830" ID="ID_1712639748" MODIFIED="1696110190076" TEXT="wir brauchen einen konzeptionellen Rahmen">
<arrowlink COLOR="#fdcfce" DESTINATION="ID_853481552" ENDARROW="Default" ENDINCLINATION="-959;56;" ID="Arrow_ID_275745687" STARTARROW="None" STARTINCLINATION="-1085;66;"/>
<icon BUILTIN="messagebox_warning"/>
</node>
<node CREATED="1696110202816" ID="ID_892025569" MODIFIED="1696110324805">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
das Problem ist entstanden weil der Monitor &#8222;vorsorglich&#8220; den Error-State auswertet,
</p>
<p>
dann aber nicht klar ist, wie mit einer solchen Situation umzugehen ist.
</p>
<p>
Des weiteren ist nicht klar, was die Kopplung zwischen Exception und Error-State soll
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
</node>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1696110353252" ID="ID_1579091753" MODIFIED="1696110384783">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
die <b>Gleichwertigkeit</b>&#160;von Error-Flag und Exception wird nun <i>in Frage gestellt</i>
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1696110388984" ID="ID_1739603971" MODIFIED="1696110439910">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
<u>Plan</u>: k&#252;nftig sollen Error-Flags nur noch aus C-Code stammen
</p>
</body>
</html>
</richcontent>
<font ITALIC="true" NAME="SansSerif" SIZE="14"/>
<icon BUILTIN="yes"/>
</node>
</node>
<node CREATED="1696110741312" ID="ID_1412671366" MODIFIED="1696110830911" TEXT="da&#xdf; sich diese Probleme nun h&#xe4;ufen liegt an der &#xbb;Integration&#xab;">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
solange ich nur Detail-Komponenten gebaut habe, konnte ich von komplett definiertem Kontext (Unit-Test) ausgehen; damit waren Exceptions vor allem etwas, was man <i>pro forma</i>&#160;noch mit einbaut, aber letztlich nur &#8222;&#252;ber die Mauer wirft&#8220;
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="smiley-oh"/>
</node>
<node CREATED="1696119904681" ID="ID_1065151947" MODIFIED="1696119920360">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
die verschleppte Exception ist aber nur der <b>Anla&#223;</b>
</p>
</body>
</html>
</richcontent>
</node>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696119921079" ID="ID_893400394" MODIFIED="1696119969475">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
der <b>Grund</b>&#160;ist ein <b>Bug</b>&#160;im Objekt-Monitor
</p>
</body>
</html>
</richcontent>
<linktarget COLOR="#db3b65" DESTINATION="ID_893400394" ENDARROW="Default" ENDINCLINATION="214;-12;" ID="Arrow_ID_1289856285" SOURCE="ID_9801066" STARTARROW="None" STARTINCLINATION="-385;17;"/>
<icon BUILTIN="broken-line"/>
<node CREATED="1696119983670" ID="ID_878293823" MODIFIED="1696120171437" TEXT="der &#xbb;convenience-shortcut&#xab; hat eine L&#xfc;cke ge&#xf6;ffnet">
<icon BUILTIN="idea"/>
</node>
<node CREATED="1696120059139" ID="ID_1860999331" MODIFIED="1696120128327" TEXT="(sync.hpp Zeile 482) weil das mon_.acquireLock() und das wait() im ctor-Body stehen..."/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1696120129842" ID="ID_323663607" MODIFIED="1696120264827" TEXT="...untergr&#xe4;bt ein Fehler im wait() den Schutz vom acquireLock()">
<arrowlink COLOR="#682b39" DESTINATION="ID_276811059" ENDARROW="Default" ENDINCLINATION="617;-40;" ID="Arrow_ID_599709584" STARTARROW="None" STARTINCLINATION="-274;12;"/>
<icon BUILTIN="clanbomber"/>
</node>
</node>
</node>
@ -80634,6 +80904,12 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695395162340" ID="ID_188901559" MODIFIED="1695395168717" TEXT="Pr&#xfc;fen auf m&#xf6;gliche Vereinfachungen">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696120192842" ID="ID_276811059" MODIFIED="1696120264827" TEXT="Bug im wait-&#xbb;convenience-shorcut&#xab;">
<linktarget COLOR="#682b39" DESTINATION="ID_276811059" ENDARROW="Default" ENDINCLINATION="617;-40;" ID="Arrow_ID_599709584" SOURCE="ID_323663607" STARTARROW="None" STARTINCLINATION="-274;12;"/>
<icon BUILTIN="broken-line"/>
<node CREATED="1696120269872" ID="ID_538013070" MODIFIED="1696120281507" TEXT="denkbar w&#xe4;re stattdessen eine statische Methode"/>
<node CREATED="1696120282704" ID="ID_1767472760" MODIFIED="1696120305079" TEXT="(oder man verzichtet komplett auf den &#x201e;shortcut&#x201c;)"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695395186529" ID="ID_110802115" MODIFIED="1695395202288" TEXT="Tests &#xfc;berpr&#xfc;fen und modernisieren">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695395205001" ID="ID_881035953" MODIFIED="1695395208312" TEXT="SyncLocking_test">
@ -91915,12 +92191,16 @@ class Something
<node CREATED="1694795401834" ID="ID_1693797726" MODIFIED="1694795408588" TEXT="Overview Rulers"/>
<node CREATED="1694795411496" ID="ID_560488135" MODIFIED="1694795415392" TEXT="Expanding / Collapsing"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1694386540703" ID="ID_1995627499" MODIFIED="1694795131620" TEXT="#1188 Placement-GUI">
<icon BUILTIN="hourglass"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1696109921291" ID="ID_853481552" LINK="https://issues.lumiera.org/ticket/1341" MODIFIED="1696110190077" TEXT="#110 und #1341 Clarify Error handling scheme">
<linktarget COLOR="#fdcfce" DESTINATION="ID_853481552" ENDARROW="Default" ENDINCLINATION="-959;56;" ID="Arrow_ID_275745687" SOURCE="ID_1712639748" STARTARROW="None" STARTINCLINATION="-1085;66;"/>
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1694440562933" ID="ID_1529688085" LINK="https://issues.lumiera.org/ticket/1338" MODIFIED="1694795034628" TEXT="#1338 Non-standard Play-processing">
<icon BUILTIN="flag-yellow"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1694386540703" ID="ID_1995627499" MODIFIED="1696110147305" TEXT="#1188 Placement-GUI">
<icon BUILTIN="hourglass"/>
</node>
<node BACKGROUND_COLOR="#d2beaf" COLOR="#5c4d6e" CREATED="1694386944106" ID="ID_1974621116" MODIFIED="1694792485209" TEXT="#1237 GUI content outlining">
<icon BUILTIN="hourglass"/>
</node>