<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div>Hi Vincent,</div><div><br></div><div>Thank you for this very detailed explanation of the issue. I need to think about this for a bit.</div><div><br></div><div>It seems like the WK2 infrastructure should suffer from this same issue. Perhaps if we revived WK2 on Windows it would provide a better match to this situation.</div><div><br></div><div>Could you please do me a favor: copy the text of your e-mail and paste it into a new bug at <a href="https://bugs.webkit.org">https://bugs.webkit.org</a> and cc me and Darin on this? Just file it under "WebKit Misc".</div><div><br></div><div>Thanks!</div><div><br></div><div>-Brent<br><br>Sent from my iPad</div><div><br>On Sep 15, 2013, at 8:53 AM, "Van Den Berghe, Vincent" &lt;<a href="mailto:Vincent.VanDenBerghe@bvdinfo.com">Vincent.VanDenBerghe@bvdinfo.com</a>&gt; wrote:<br><br></div><blockquote type="cite"><div>

<meta http-equiv="Content-Type" content="text/html; charset=us-ascii">
<meta name="Generator" content="Microsoft Word 12 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:Wingdings;
        panose-1:5 0 0 0 0 0 0 0 0 0;}
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:Consolas;
        panose-1:2 11 6 9 2 2 4 3 2 4;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph
        {mso-style-priority:34;
        margin-top:0in;
        margin-right:0in;
        margin-bottom:0in;
        margin-left:.5in;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri","sans-serif";}
span.EmailStyle17
        {mso-style-type:personal-compose;
        font-family:"Calibri","sans-serif";
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
/* List Definitions */
@list l0
        {mso-list-id:481242355;
        mso-list-type:hybrid;
        mso-list-template-ids:-333525054 1427935532 67698691 67698693 67698689 67698691 67698693 67698689 67698691 67698693;}
@list l0:level1
        {mso-level-start-at:0;
        mso-level-number-format:bullet;
        mso-level-text:-;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-.25in;
        font-family:"Calibri","sans-serif";
        mso-fareast-font-family:Calibri;
        mso-bidi-font-family:"Times New Roman";}
@list l1
        {mso-list-id:1592812772;
        mso-list-type:hybrid;
        mso-list-template-ids:-1380543114 1589129208 67698691 67698693 67698689 67698691 67698693 67698689 67698691 67698693;}
@list l1:level1
        {mso-level-start-at:0;
        mso-level-number-format:bullet;
        mso-level-text:-;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-.25in;
        font-family:"Calibri","sans-serif";
        mso-fareast-font-family:Calibri;
        mso-bidi-font-family:"Times New Roman";}
ol
        {margin-bottom:0in;}
ul
        {margin-bottom:0in;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->


<div class="WordSection1">
<p class="MsoNormal">Hello again,<o:p></o:p></p>
<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal">(for Brent Fulgham: codeword “onion”, I repeat, codeword “onion”
<span style="font-family:Wingdings">J</span>)<o:p></o:p></p>
<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal"><u>Context<o:p></o:p></u></p>
<p class="MsoNormal">Consider embedding WebKit in an <a href="http://ASP.NET">ASP.NET</a> website (even though what follows is valid in other scenarios). In order to do this, you need a (managed) thread with a message loop. If you want this to work reliably, you make sure all WebKit’s
 COM objects are created on that thread. If you chose not to, what follows is still valid.<o:p></o:p></p>
<p class="MsoNormal">Note that this thread doesn’t need to be the main process thread: in the case of a worker process of a web server, you don’t even have access to that. For WebKit, it just needs to be “a” thread with a message loop, as long as it’s the same
 one.<o:p></o:p></p>
<p class="MsoNormal"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none">When you instantiate a Webkit COM object for the first time, Windows’ COM will ultimately call LoadLibrary on WebKit.dll. It will do so on the thread that wants to instantiate the COM object. This initializes
 the CRT and triggers a call to <span style="font-size:9.5pt;font-family:Consolas">
DllMain</span> with the argument <span style="font-size:9.5pt;font-family:Consolas">
ul_reason_for_call</span> set to <span style="font-size:9.5pt;font-family:Consolas">
DLL_PROCESS_ATTACH</span>. <o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">When the last reference to the last WebKit object is released, COM will NOT call FreeLibrary(). COM doesn’t know the concept of “last object”, and will keep the DLL around to avoid the overhead of loading it
 again should another instance be needed.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">By default, your unmanaged DLL will remain loaded until the process is terminated. The main process thread will then call FreeLibrary(), prompting indirectly another call to
<span style="font-size:9.5pt;font-family:Consolas">DllMain</span> with the argument
<span style="font-size:9.5pt;font-family:Consolas">ul_reason_for_call</span>&nbsp;hanksset to
<span style="font-size:9.5pt;font-family:Consolas">DLL_PROCESS_DETACH</span>.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">The main thing to take away from this, is that the thread executing
<span style="font-size:9.5pt;font-family:Consolas">DLL_PROCESS_ATTACH</span> code and the thread executing
<span style="font-size:9.5pt;font-family:Consolas">DLL_PROCESS_DETACH</span> code will not necessarily be the same. In the above scenario, they will never be the same.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">For those who prefer the horse’s mouth:
<a href="http://msdn.microsoft.com/en-us/library/windows/desktop/ms682583(v=vs.85).aspx">
http://msdn.microsoft.com/en-ure us/library/windows/desktop/ms682583(v=vs.85).aspx</a>us&nbsp;<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none"><u>AtomicString<o:p></o:p></u></p>
<p class="MsoNormal" style="text-autospace:none">Consider the following code:<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">LONG FontPlatformData::adjustedGDIFontWeight(LONG gdiFontWeight,
<span style="color:blue">const</span> String&amp; family)<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">{<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp;
<span style="color:blue">static</span> AtomicString lucidaStr(<span style="color:#A31515">"Lucida Grande"</span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp;
<span style="color:blue">if</span> (equalIgnoringCase(family, lucidaStr)) {<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span style="color:blue">if</span> (gdiFontWeight == FW_NORMAL)<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span style="color:blue">return</span> FW_MEDIUM;<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span style="color:blue">if</span> (gdiFontWeight == FW_BOLD)<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<span style="color:blue">return</span> FW_SEMIBOLD;<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp; }<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp;
<span style="color:blue">return</span> gdiFontWeight;<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none">This is a method (one of many examples) with a
<span style="font-size:9.5pt;font-family:Consolas;color:blue">static</span><span style="font-size:9.5pt;font-family:Consolas"> AtomicString</span> object. The constructor of
<span style="font-size:9.5pt;font-family:Consolas">lucidaStr</span> will be executed in a thread-safe way (exactly once) by the first thread that will enter this method. The C++ compiler will generate code that will make sure of it, at least if the compiler
 obeys C++0x, which mandates this behavior.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">Code will also be executed that registers the destructor&nbsp; of
<span style="font-size:9.5pt;font-family:Consolas">lucidaStr</span> so that it is executed when the program terminates. The mechanism is similar to functions registered with atexit(). Destruction order will be reverse construction order, as expected.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">This code being in a DLL, it means that the destructor will be called when the DLL is unloaded: after the the
<span style="font-size:9.5pt;font-family:Consolas">DLL_PROCESS_DETACH</span> code of
<span style="font-size:9.5pt;font-family:Consolas">DllMain</span>, the CRT will do so.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">Given the context described above, it means that the destructor of an
<span style="font-size:9.5pt;font-family:Consolas">AtomicString</span> will be executed by a different thread than the one that executed its constructor.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none">When an <span style="font-size:9.5pt;font-family:Consolas">
AtomicString</span> is destroyed, the following method is executed:<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas;color:blue">void</span><span style="font-size:9.5pt;font-family:Consolas"> AtomicString::remove(StringImpl* string)<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">{<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp; ASSERT(string-&gt;isAtomic());<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp; AtomicStringTableLocker locker;<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp; HashSet&lt;StringImpl*&gt;&amp; atomicStringTable = stringTable();<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp; HashSet&lt;StringImpl*&gt;::iterator iterator = atomicStringTable.find(string);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp; ASSERT_WITH_MESSAGE(iterator != atomicStringTable.end(),
<span style="color:green">"The string being removed is atomic in the string table of an other thread!"</span>);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp; &nbsp;atomicStringTable.remove(iterator);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">}<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none">This will fail on the assertion, since the string was created on the string table of a different thread.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">The process will therefore crash on termination. Every time.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none"><u>Why this is relevant<o:p></o:p></u></p>
<p class="MsoNormal" style="text-autospace:none">One can argue that for “eternal’ processes, this is not relevant. Unfortunately, this is wrong. For example on Windows, IIS worker processes can be periodically recycled for legitimate reasons (elapsed or scheduled
 time, number of requests, memory usage or on demand). Every legitimate requests will log a process crash, which is bad form (to say the least).<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none"><u>Workaround<o:p></o:p></u></p>
<p class="MsoNormal" style="text-autospace:none">The workaround I’ve applied was to change the
<span style="font-size:9.5pt;font-family:Consolas">ASSERT_WITH_MESSAGE</span> and the line below it in the above method to this:<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp;
<span style="color:blue">if</span>(iterator != atomicStringTable.end())<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; atomicStringTable.remove(iterator);<o:p></o:p></span></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas"><o:p>&nbsp;</o:p></span></p>
<p class="MsoNormal" style="text-autospace:none">The workaround sucks because is never a good idea to eliminate a perfectly valid an assertion just for taking care of a corner case. Unfortunately, this corner case was systematic crashing behavior, which is
 worse.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">I was afraid there were other classes whose static instances are so sensitive to threading, but it seems that AtomicString is the only one. Whew!<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">In my defense, I’ve seen worse. I’ve seen .NET wrappers for WebKit creating a static instance of WebView and call various methods in order to initialize the variables on the main thread and avoid the crash. Needless
 to say, these workarounds don’t work.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none"><u>Theoretical but impractical workaround 1<o:p></o:p></u></p>
<p class="MsoNormal" style="text-autospace:none">You can convince COM to unload unused libraries with a call to CoFreeUnusedLibraries(). This will trigger a call to DllCanUnloadNow (which is implemented by WebKit in WebKitDLL.cpp) and if that function returns
 S_OK (for WebKit this means: when there are no instances and no locks left), the DLL will be unloaded. Unfortunately, the question remains on which thread to call CoFreeUnusedLibraries? If you take the “multithreaded route” instantiating your objects, there
 is no right answer to that question, since different static atomic strings inside methods can be initialized on demand by different threads.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">On .NET, there is also the problem of termination detection: usually, your managed “webkit thread” will be a background thread to avoid blocking the termination of the worker process. This means that the thread
 can be terminated without notice, and hence there is no good place to put termination code.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none"><u>Theoretical but impractical workaround 2<o:p></o:p></u></p>
<p class="MsoNormal" style="text-autospace:none">You can forego all the built-in COM support, call LoadLibrary/FreeLibrary yourself., and handle all instantiating/calling/marshalling in .NET. Tricky and difficult, but not impossible.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">But then, what’s the point of providing COM support? And besides, calling FreeLibrary is as impractical as calling CoFreeUnusedLibraries() so you’re back to square one.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none"><u>AtomicString (again)<o:p></o:p></u></p>
<p class="MsoNormal" style="text-autospace:none">Unless I’m mistaken, an AtomicString instance is an immutable object, at least conceptually. &nbsp;It makes a lot of sense for immutable objects (like the String class in managed environments Java and .NET) to be
 thread safe.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">This is not the case for AtomicString because of some (thread) affinity to a thread-specific string table. This design doesn’t work for static instances. For those instances, shouldn’t AtomicString reference
 a global and thread-neutral string table? Perhaps via a special constructor to be used only in those instances?<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">I’m new here, so maybe the discussion is moot and there is some very good reason why things are designed the way they are. I just don’t see it.&nbsp; Explanations are welcome.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none">The closest design I can compare it with is string interning (<a href="http://en.wikipedia.org/wiki/String_interning">http://en.wikipedia.org/wiki/String_interning</a>). But in managed languages, there’s one
 big (thread-neutral and thread-safe) string table, not one string table per thread.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none">This is one of those cases where I feel WebKit’s design conspires against you. Well, it certainly did against me. Now excuse me while I get my handkerchief.<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none"><o:p>&nbsp;</o:p></p>
<p class="MsoNormal" style="text-autospace:none">Vincent<o:p></o:p></p>
<p class="MsoNormal" style="text-autospace:none"><span style="font-size:9.5pt;font-family:Consolas"><o:p>&nbsp;</o:p></span></p>
</div>


</div></blockquote><blockquote type="cite"><div><span>_______________________________________________</span><br><span>webkit-dev mailing list</span><br><span><a href="mailto:webkit-dev@lists.webkit.org">webkit-dev@lists.webkit.org</a></span><br><span><a href="https://lists.webkit.org/mailman/listinfo/webkit-dev">https://lists.webkit.org/mailman/listinfo/webkit-dev</a></span><br></div></blockquote></body></html>