[webkit-dev] WTF::callOnMainThread() and re-entrancy

Drew Wilson atwilson at google.com
Tue Mar 9 10:01:41 PST 2010

Another alternative is for us to add a flag to
scheduleDispatchFunctionsOnMainThread() which is passed as true in the case
where we are calling it from dispatchFunctionsOnMainThread():

        // If we are running accumulated functions for too long so UI may
become unresponsive, we need to
        // yield so the user input can be processed. Otherwise user may not
be able to even close the window.
        // This code has effect only in case the
scheduleDispatchFunctionsOnMainThread() is implemented in a way that
        // allows input events to be processed before we are back here.
        if (currentTime() - startTime > maxRunLoopSuspensionTime) {
            scheduleDispatchFunctionsOnMainThread(true);  // delay = true

That way, in the case where we are in some kind of tight loop and we want to
yield anyway to let UI events happen, we could instead yield for (say) 10ms
to make sure lower priority events have a chance to be dispatched.

Alexey, what do you think? My preference would be to use a lower priority
event instead of a delay, but I don't know enough about Cocoa programming to
know whether that's possible.


On Tue, Mar 9, 2010 at 9:45 AM, Drew Wilson <atwilson at google.com> wrote:

> Yeah, it's a race condition - it seems to all depend on whether the worker
> resource gets loaded before the postMessage loop starts. Failure rate is
> around 30-50% on my machine.
> It looks like events have priority in Cocoa, and I'm guessing that
> performSelectorOnMainThread() creates events with a higher priority than
> those generated by URLConnection, which can lead to starvation. I'm not
> certain what the right fix is, other than to maybe use a different method of
> dispatching events other than performSelectorOnMainThread that lets us set a
> lower priority?
> -atw
> On Mon, Mar 8, 2010 at 7:24 PM, Dmitry Titov <dimich at chromium.org> wrote:
>> At least user input is dispatched even if there are outstanding
>> performSelectorOnMainThread calls:
>> https://bugs.webkit.org/show_bug.cgi?id=23705
>> With the change in postTask, the cloneport test does not always hang - on
>> my machine it's 50-50. There is some racing condition somewhere perhaps...
>> On Mon, Mar 8, 2010 at 5:29 PM, Drew Wilson <atwilson at google.com> wrote:
>>> Following up with a related note - does anyone have any insight into how
>>> the Cocoa event loop dispatches events from different sources? In
>>> particular, I have a test (worker-cloneport.html) which posts a port back
>>> and forth between two endpoints (both on the main thread).
>>> With the change to Document.postTask() I described earlier in this
>>> thread, this test results in there always being a pending event (posted via
>>> performSelectorOnMainThread) when we re-enter the cocoa runloop. It appears
>>> that the run loop *always* dispatches this event before dispatching events
>>> from NSURLConnection - the result is that any pending resource loads never
>>> complete.
>>> Is there some kind of prioritization within the cocoa run loop so that
>>> certain types of events (like NSURLConnection events) if there are no
>>> pending events of other types?
>>> -atw
>>> On Mon, Mar 8, 2010 at 2:08 PM, Dmitry Titov <dimich at chromium.org>wrote:
>>>> Many tasks are just fine to execute while modal UI is present. For
>>>> example, XHR in a Worker probably should not be frozen by an alert on the
>>>> parent page. That posts tasks to main thread for loader.
>>>> Also, it's unclear if a task can be simply delayed or in fact some other
>>>> action should be performed at resume point - for example, timers
>>>> re-calculate the next fire time.
>>>> Maybe there can be a generic mechanism for tasks to participate in
>>>> suspend/resume... It'd require a better definition of the events - for
>>>> example, is there a difference between "suspense on modal UI" and "suspense
>>>> on going into BF cache"? Probably there is.
>>>> Dmitrty
>>>> On Mon, Mar 8, 2010 at 1:45 PM, Drew Wilson <atwilson at google.com>wrote:
>>>>> So the implication is that every single place that uses tasks has to
>>>>> have an associated activeDOMObject() or other hooks in
>>>>> ScriptExecutionContext so it can get suspend/resume calls and try to queue
>>>>> up the tasks for later? That seems a) hard (since not everything that uses
>>>>> tasks necessarily has an activeDOMObject), and b) fragile because we'll
>>>>> undoubtedly miss cases -- there's something like 70 calls to
>>>>> callOnMainThread()/postTask() in the WebCore code.
>>>>> Is there no way to do something at a lower level? callOnMainThread()
>>>>> already keeps a queue of pending callbacks, so it seems like just not
>>>>> dispatching those callbacks might be better? It's tricky because you don't
>>>>> necessarily know which ScriptExecutionContext a task is destined for at that
>>>>> low level.
>>>>> -atw
>>>>> On Mon, Mar 8, 2010 at 1:24 PM, Dmitry Titov <dimich at chromium.org>wrote:
>>>>>> On Mon, Mar 8, 2010 at 11:38 AM, Alexey Proskuryakov <ap at webkit.org>wrote:
>>>>>>> On 08.03.2010, at 11:21, Drew Wilson wrote:
>>>>>>>  So, my question is: does it surprise anyone that tasks posted via
>>>>>>>> callOnMainThread() are getting executed even though there's a modal dialog
>>>>>>>> shown? And is there anything I should be doing in my task handler to make
>>>>>>>> sure we aren't re-entering JS execution inappropriately in these cases? I'm
>>>>>>>> just concerned that the way we're posting tasks from worker threads to the
>>>>>>>> main thread may cause reentrancy problems.
>>>>>>> It is not correct to deliver messages from worker threads when an
>>>>>>> alert or a modal window is displayed. It may be ok for modal dialogs that
>>>>>>> are triggered asynchronously (such as credentials dialog).
>>>>>>> We have a manual test regression for a related issue,
>>>>>>> WebCore/manual-tests/js-timers-beneath-modal-dialog.html. You can compare
>>>>>>> how timers work, and how worker messages are delivered to find out how to
>>>>>>> fix the problem.
>>>>>> Timers are suspended by
>>>>>> ScriptExecutionContext::suspendActiveDOMObjects/resumeActiveDOMObjects from
>>>>>> PageGroupLoadDeferrer. So the context (Document) knows when it is suspended
>>>>>> and when it gets resumed.
>>>>>> It seems the task to process accumulated port messages can be
>>>>>> postponed until resume.
>>>>>>> - WBR, Alexey Proskuryakov
>>>>>>> _______________________________________________
>>>>>>> webkit-dev mailing list
>>>>>>> webkit-dev at lists.webkit.org
>>>>>>> http://lists.webkit.org/mailman/listinfo.cgi/webkit-dev
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-dev/attachments/20100309/5b96d4b5/attachment.html>

More information about the webkit-dev mailing list