Sorry - what I meant by &quot;not a multi-thread&quot; issue was that it&#39;s really a multi-heap issue. The fact that each heap is GC&#39;d on different threads doesn&#39;t seem to make the problem significantly harder, but I could be wrong - it was kind of a throwaway comment anyway.<br>
<br>Anyhow, I agree with your conclusion - I&#39;ve been going down the same design path (separate data structure shared by both sides which can track pending messages on both ends). <br><br>An unreachable MessagePort can become reachable as you say - by having its onmessage handler stuff the pointer somewhere, so any message port with any message en-route to either side should be treated as reachable. This isn&#39;t hard to do with the shared state - the only missing piece is the ability to detect when there are no references, which isn&#39;t currently possible.<br>
<br>The code in JSC::Protect.h is almost what we want. There are only two things that would need to change:<br><br>1) Change Heap::collect() to invoke markProtectedObjects() later in the GC cycle (after marking the call frames)<br>
2) Change markProtectedObjects() to invoke some function on the object (i.e. &quot;markProtected()&quot;) prior to calling mark():<br><br>ššš ProtectCountSet::iterator end = m_protectedValues.end();<br>ššš for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) {<br>
ššššššš JSCell* val = it-&gt;first;<br>ššššššš if (!val-&gt;marked())<br><b>ššššššššššš val-&gt;markProtected();</b><br>ššššššššššš val-&gt;mark();<br>ššš }<br><br>This would allow protected objects to know that they were being kept alive solely due to gcProtect(), not via references. Then we could use that to track common state and when we know the MessagePort is completely unreachable/idle, we can unprotect both ends to allow them to be GC&#39;d.<br>
<br>The alternative is to not leverage protect() but instead to add a separate set which essentially acts like the protected set but with the different behavior above.<br><br>The advantage of having the separate set is it seems like it has a lower performance impact, as the number of objects in the new protected set will be much lower than the number of overall gcProtect()-ed objects. The downside is that it&#39;s really very similar functionality, so the conceptual burden of having both is higher.<br>
<br>I&#39;ll propose the latter in my design (new separate protected set) if nobody has a strong preference for changing the behavior of the current protect() set.<br><br>-atw<br><br><br><br><br><br><br><div class="gmail_quote">
2009/5/7 Maciej Stachowiak <span dir="ltr">&lt;<a href="mailto:mjs@apple.com">mjs@apple.com</a>&gt;</span><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<div style="word-wrap: break-word;"><br><div><div class="im"><div>On May 6, 2009, at 6:41 PM, Drew Wilson wrote:</div><br><blockquote type="cite">Following up. I think I have my head around how Worker GC is happening (I may start another thread about that, as it looks like there&#39;s some cases where the thread won&#39;t be shut down, but the general design is sound).<br>
 <br>MessagePort GC is a little trickier, because we need to detect when both sides have no external references, based on this part of the HTML5 spec:<br><div>    <blockquote style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;" class="gmail_quote">
<p>[...] a message port can be received, given an event listener,   and then forgotten, and so long as that event listener could   receive a message, the channel will be maintained.</p><p>Of course, if this was to occur on both sides of the channel,   then both ports would be garbage collected, since they would not be   reachable from live code, despite having a strong reference to each   other.</p>
</blockquote>      </div>From looking at the code in bindings/js, it looks like I&#39;ve got two tools to manage object reachability:<br><br>1) I can tell when my object is reachable (during a GC) because mark() will be invoked on it.<br>
 2) I can force my object to stay active (as long as the owning context is active) by making it an ActiveDOMObject and returning true from hasPendingActivity() (which seems like it does nothing but invoke mark() on the object).<br>
 <br>So, #2 lets me keep an object alive, but to implement the spec, I need to be able to detect when my object has no more references, without actually having it get garbage collected. If I can do that, then I can build my own distributed state mechanism to allow me to determine when it&#39;s safe to GC the objects.<br>
 <br>I&#39;m looking through the JSC::Collector code, and I didn&#39;t see anything that did exactly what I want, but there are probably some things that we could do with protect() to enable this. Has anyone else had to do anything like what I describe above? It&#39;s not exactly even a multi-thread issue, as it seems like this problem would occur even with just a single thread.<br>
</blockquote><div><br></div></div><div>It is specifically a multi-thread issue, because with a single thread and single heap both MessagePorts could just mark() each other - if they have no other references, they will be collected anyway because GC will happily collect an unreferenced cycle.</div>
<div><br></div><div>It&#39;s only the separate per-thread heaps that make it challenging, since GC may occur at different times and on separate heaps, so the two MessagePorts have to protect each other in a persistent way until both become unreachable.</div>
<div><br></div><div>The best way I can think of to handle this is to have a special phase after normal marking where objects with an external/cross-thread reference get marked in a distinctive way. Then each MessagePort would know if it was marked solely due to its opposite endpoint being live. I don&#39;t recall if there is a way for an unreachable MessagePort to become reachable - I think yes, because the message event listener can stuff the MessagePort in a global variable. But I think an unerachable port can only become reachable by receiving a message. Thus, you need a core data structure for the MessageChannel which detects the case that there are no messages pending in either direct and both endpoints are alive only due to the other endpoint. Something like that. This is a very rough design sketch, Alexey can probably explain in more detail or I can study the code.</div>
<div><br></div><div>My impression is that Workers use a similar scheme with a special additional marking phase, or once did, but Alexey will recall better than I.</div><div class="im"><div><br></div><div>š- Maciej</div><div>
<br></div><div><br></div><br><blockquote type="cite"> <br>-atw<br><br><div class="gmail_quote">2009/5/6 Drew Wilson <span dir="ltr">&lt;<a href="mailto:atwilson@google.com" target="_blank">atwilson@google.com</a>&gt;</span><br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;"> Thanks, this puts me on the right track. I&#39;ve had a bunch of discussions with the Chrome folks on how we&#39;d track MessagePort reachability in Chrome, but I&#39;d hoped that the problem might be simpler in WebKit since we had direct access to the data structures cross-thread. The existence of separate GC heaps means it&#39;s not particularly simpler after all.<br>
 <br>-atw<br><br><div class="gmail_quote">2009/5/6 Maciej Stachowiak <span dir="ltr">&lt;<a href="mailto:mjs@apple.com" target="_blank">mjs@apple.com</a>&gt;</span><div><div></div><div><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
 <div style="word-wrap: break-word;"><br><div><div><div>On May 6, 2009, at 1:53 PM, Drew Wilson wrote:</div><br><blockquote type="cite">OK, that&#39;s good to know (it only supports document contexts) - clearly some work has been done to prepare for multi-thread usage (for example, the core data structure is a thread-safe MessageQueue).<br>
 <br>I&#39;m quite happy to drive this design (in fact, I&#39;m in the middle of this now) but I would like to make sure I understand in general what the correct approach is for managing GC-able objects that are accessed cross-thread - I haven&#39;t been able to find any documentation (outside of the code itself).<br>
  <br>Is the right approach to use JSLock when manipulating cross-thread linkage? I&#39;ll write up a quick document to describe the approach I&#39;m taking, but I&#39;d like to understand your concerns about deadlocks. So long as we have only a single shared per-channel mutex, and we never grab any other locks (like JSLock) after grabbing that mutex, we should be OK. Are there other locks that may be grabbed behind the scenes that I should be aware of?<br>
 </blockquote><div><br></div><div><br></div></div><div>JSLock is not the right approach. Workers have their own completely separate GC heap. JSLock only locks the current context group&#39;s heap. It will not prevent collection in other heaps.</div>
 <div><br></div><div>I don&#39;t know exactly what the right approach is. Ultimately it&#39;s a distributed GC problem, both for our split-heap multithreading and for an approach that used processes for workers. And distributed GC is hard.</div>
 <div><br></div><div>However, Worker itself has a similar issue, since it can be kept alive either from the inside or the outside reference. You could look at how that problem was solved.</div><div><br></div><div>š- Maciej</div>
 <div><br></div><br><blockquote type="cite"><div> <br>-atw<br><br><div class="gmail_quote">2009/5/6 Alexey Proskuryakov <span dir="ltr">&lt;<a href="mailto:ap@webkit.org" target="_blank">ap@webkit.org</a>&gt;</span><br> <blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
 <br> 06.05.2009, Χ 21:38, Drew Wilson ΞΑΠΙΣΑΜ(Α):<div><br> <br> <blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">  It looks like the JSC collection code relies on JSLock to lock the heap - I&#39;m guessing that I&#39;ll need to explicitly grab the JSLock whenever I&#39;m manipulating the linkage between the two ports, is that correct? Or is there a different/better way to handle situations like this?<br>
  </blockquote> <br> <br></div> The JavaScriptCore implementation of MessagePorts only supports document contexts (i.e., it only works on main thread).<br> <br> As mentioned earlier, the first thing needed to implement MessagePorts in workers is a design of how they can be passed around without breaking GC. It is likely that taking a lock whenever atomicity is desired will cause deadlocks.<br>
  <br> - WBR, Alexey Proskuryakov<br> <br> <br> </blockquote></div><br></div> _______________________________________________<br>webkit-dev mailing list<br><a href="mailto:webkit-dev@lists.webkit.org" target="_blank">webkit-dev@lists.webkit.org</a><br>
 <a href="http://lists.webkit.org/mailman/listinfo.cgi/webkit-dev" target="_blank">http://lists.webkit.org/mailman/listinfo.cgi/webkit-dev</a><br></blockquote></div><br></div></blockquote></div></div></div><br> </blockquote>
</div><br></blockquote></div></div><br></div></blockquote></div><br>