ubuntu-webapps-bugs team mailing list archive
-
ubuntu-webapps-bugs team
-
Mailing list archive
-
Message #03756
[Bug 1536797] [NEW] Fix nested message loop handling
Public bug reported:
I've reviewed the behaviour of Oxide if Qt or an application executes a
nested QEventLoop on the main thread. This is needed to ensure we can
safely handle drag and drop:
- Scenario 1: QEventLoop executed with no Chromium code on the stack.
In this case, the nested loop will pump the Chromium event queue as normal, and this is fine because there are no nested Chromium tasks.
- Scenario 2: QEventLoop executed from a non-nested Chromium task.
In this case, the nested loop will pump the Chromium event queue by re-entering oxide::qt::MessagePump::RunOneTask()
- It doesn't look like there's any re-entrancy issues here.
- MessageLoop::DoWork() will not run any tasks because the MessageLoop is in a task and nestable tasks haven't been explicitly allowed (MessageLoop::nestable_tasks_allowed_ is set to false in RunTask).
- MessageLoop::DoDelayedWork() - same as DoWork()
- MessageLoop::DoIdleWork() will process tasks from the deferred non-nestable work queue.
The last point is a bug, as DoIdleWork() should not run tasks in a
nested loop. However, it seems like an edge case - tasks are only added
to this work queue via nested calls to DoWork() and DoDelayedWork() when
nestable tasks are allowed but the task isn't nestable. We don't do this
anywhere in Oxide, although that doesn't mean it couldn't happen
elsewhere in Chromium.
- Scenario 3: QEventLoop executed from a nested Chromium task (via RunLoop::Run)
As 2, above. Nested tasks are still blocked in DoIdle and DoDelayedWork because RunTask clears nestable_tasks_allowed_ before running the nested task. However, DoIdleWork will behave correctly here because the RunLoop::run_depth_ check in MessageLoop::ProcessNextDelayedNonNestableTask will work.
It seems like we should detect re-entrancy from a nested QEventLoop in oxide::qt::MessagePump::RunOneTask(). We could do this by adding an extra bit to RunState, that we set when calling in to MessageLoop.
- If we re-enter from a nested QEventLoop, the extra bit on the current RunState will be set. In this case, we should create a new RunLoop instance before calling in to MessageLoop.
- A nested RunLoop creates a new RunState in our MessagePump. In this case, we won't trigger the re-entrancy detection (and we don't need to)
After this is fixed, a nested QEventLoop created outside of Oxide will
process Qt events but won't run any Oxide or Chromium tasks. The only
way to run a nested loop that processes nestable Oxide or Chromium tasks
is to use MessageLoop::ScopedNestableTasksAllower and RunLoop, but that
can only be done from code in Oxide.
** Affects: oxide
Importance: Medium
Status: Triaged
** Changed in: oxide
Importance: Undecided => Medium
** Changed in: oxide
Status: New => Triaged
--
You received this bug notification because you are a member of Ubuntu
WebApps bug tracking, which is subscribed to Oxide.
https://bugs.launchpad.net/bugs/1536797
Title:
Fix nested message loop handling
Status in Oxide:
Triaged
Bug description:
I've reviewed the behaviour of Oxide if Qt or an application executes
a nested QEventLoop on the main thread. This is needed to ensure we
can safely handle drag and drop:
- Scenario 1: QEventLoop executed with no Chromium code on the stack.
In this case, the nested loop will pump the Chromium event queue as normal, and this is fine because there are no nested Chromium tasks.
- Scenario 2: QEventLoop executed from a non-nested Chromium task.
In this case, the nested loop will pump the Chromium event queue by re-entering oxide::qt::MessagePump::RunOneTask()
- It doesn't look like there's any re-entrancy issues here.
- MessageLoop::DoWork() will not run any tasks because the MessageLoop is in a task and nestable tasks haven't been explicitly allowed (MessageLoop::nestable_tasks_allowed_ is set to false in RunTask).
- MessageLoop::DoDelayedWork() - same as DoWork()
- MessageLoop::DoIdleWork() will process tasks from the deferred non-nestable work queue.
The last point is a bug, as DoIdleWork() should not run tasks in a
nested loop. However, it seems like an edge case - tasks are only
added to this work queue via nested calls to DoWork() and
DoDelayedWork() when nestable tasks are allowed but the task isn't
nestable. We don't do this anywhere in Oxide, although that doesn't
mean it couldn't happen elsewhere in Chromium.
- Scenario 3: QEventLoop executed from a nested Chromium task (via RunLoop::Run)
As 2, above. Nested tasks are still blocked in DoIdle and DoDelayedWork because RunTask clears nestable_tasks_allowed_ before running the nested task. However, DoIdleWork will behave correctly here because the RunLoop::run_depth_ check in MessageLoop::ProcessNextDelayedNonNestableTask will work.
It seems like we should detect re-entrancy from a nested QEventLoop in oxide::qt::MessagePump::RunOneTask(). We could do this by adding an extra bit to RunState, that we set when calling in to MessageLoop.
- If we re-enter from a nested QEventLoop, the extra bit on the current RunState will be set. In this case, we should create a new RunLoop instance before calling in to MessageLoop.
- A nested RunLoop creates a new RunState in our MessagePump. In this case, we won't trigger the re-entrancy detection (and we don't need to)
After this is fixed, a nested QEventLoop created outside of Oxide will
process Qt events but won't run any Oxide or Chromium tasks. The only
way to run a nested loop that processes nestable Oxide or Chromium
tasks is to use MessageLoop::ScopedNestableTasksAllower and RunLoop,
but that can only be done from code in Oxide.
To manage notifications about this bug go to:
https://bugs.launchpad.net/oxide/+bug/1536797/+subscriptions
Follow ups