⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 269046 in webkit


Ignore:
Timestamp:
Oct 27, 2020, 10:08:50 AM (6 years ago)
Author:
Chris Lord
Message:

[GLIB] imported/w3c/web-platform-tests/html/canvas/offscreen/line-styles/2d.line.width.transformed.html is a flaky crash
​https://bugs.webkit.org/show_bug.cgi?id=217986

Reviewed by Simon Fraser.

Fix race condition caused by use of OffscreenCanvas::scriptExecutionContext() on main thread.
Instead of passing a reference to the OffscreenCanvas object when dealing with the placeholder
canvas on the main thread, encapsulate the necessary data in a separate, ThreadSafeRefCounted
object and pass that instead, negating the need to call back to the Worker thread to release
the reference.

Covered by existing tests.

  • html/OffscreenCanvas.cpp:

(WebCore::OffscreenCanvas::create):
(WebCore::OffscreenCanvas::OffscreenCanvas):
(WebCore::OffscreenCanvas::detach):
(WebCore::OffscreenCanvas::setPlaceholderCanvas):
(WebCore::OffscreenCanvas::pushBufferToPlaceholder):
(WebCore::OffscreenCanvas::commitToPlaceholderCanvas):

  • html/OffscreenCanvas.h:
Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/platform/glib/TestExpectations

    r269043 r269046  
    392392
    393393webkit.org/b/215462 imported/w3c/web-platform-tests/html/canvas/offscreen/manual/the-offscreen-canvas/offscreencanvas.commit.html [ Failure Pass ]
    394 
    395 # Flaky crash on pushBufferToPlaceholder().
    396 webkit.org/b/217986 imported/w3c/web-platform-tests/html/canvas/offscreen/line-styles/2d.line.width.transformed.html [ Crash Pass ]
    397 webkit.org/b/217986 imported/w3c/web-platform-tests/html/canvas/offscreen/path-objects/2d.path.arc.selfintersect.1.worker.html [ Crash Pass ]
    398 webkit.org/b/217986 imported/w3c/web-platform-tests/html/canvas/offscreen/path-objects/2d.path.arc.selfintersect.1.html [ Crash Pass ]
    399394
    400395#////////////////////////////////////////////////////////////////////////////////////////
  • trunk/Source/WebCore/ChangeLog

    r269041 r269046  
     12020-10-27  Chris Lord  <clord@igalia.com>
     2
     3        [GLIB] imported/w3c/web-platform-tests/html/canvas/offscreen/line-styles/2d.line.width.transformed.html is a flaky crash
     4        https://bugs.webkit.org/show_bug.cgi?id=217986
     5
     6        Reviewed by Simon Fraser.
     7
     8        Fix race condition caused by use of OffscreenCanvas::scriptExecutionContext() on main thread.
     9        Instead of passing a reference to the OffscreenCanvas object when dealing with the placeholder
     10        canvas on the main thread, encapsulate the necessary data in a separate, ThreadSafeRefCounted
     11        object and pass that instead, negating the need to call back to the Worker thread to release
     12        the reference.
     13
     14        Covered by existing tests.
     15
     16        * html/OffscreenCanvas.cpp:
     17        (WebCore::OffscreenCanvas::create):
     18        (WebCore::OffscreenCanvas::OffscreenCanvas):
     19        (WebCore::OffscreenCanvas::detach):
     20        (WebCore::OffscreenCanvas::setPlaceholderCanvas):
     21        (WebCore::OffscreenCanvas::pushBufferToPlaceholder):
     22        (WebCore::OffscreenCanvas::commitToPlaceholderCanvas):
     23        * html/OffscreenCanvas.h:
     24
    1252020-10-27  Antti Koivisto  <antti@apple.com>
    226
  • trunk/Source/WebCore/html/OffscreenCanvas.cpp

    r267735 r269046  
    8686        clone->setOriginTainted();
    8787
    88     callOnMainThread([detachedCanvas = WTFMove(detachedCanvas), offscreenCanvas = makeRef(clone.get())] () mutable {
    89         offscreenCanvas->m_placeholderCanvas = detachedCanvas->takePlaceholderCanvas();
    90         if (offscreenCanvas->m_placeholderCanvas) {
    91             auto& placeholderContext = downcast<PlaceholderRenderingContext>(*offscreenCanvas->m_placeholderCanvas->renderingContext());
     88    callOnMainThread([detachedCanvas = WTFMove(detachedCanvas), placeholderData = makeRef(*clone->m_placeholderData)] () mutable {
     89        placeholderData->canvas = detachedCanvas->takePlaceholderCanvas();
     90        if (placeholderData->canvas) {
     91            auto& placeholderContext = downcast<PlaceholderRenderingContext>(*placeholderData->canvas->renderingContext());
    9292            auto& imageBufferPipe = placeholderContext.imageBufferPipe();
    9393            if (imageBufferPipe)
    94                 offscreenCanvas->m_bufferPipeSource = imageBufferPipe->source();
     94                placeholderData->bufferPipeSource = imageBufferPipe->source();
    9595        }
    96         offscreenCanvas->scriptExecutionContext()->postTask({ ScriptExecutionContext::Task::CleanupTask,
    97             [releaseOffscreenCanvas = WTFMove(offscreenCanvas)] (ScriptExecutionContext&) { } });
    9896    });
    9997
    … …  
    111109    : CanvasBase(IntSize(width, height))
    112110    , ContextDestructionObserver(&context)
     111    , m_placeholderData(PlaceholderData::create())
    113112{
    114113}
    … …  
    390389
    391390    auto detached = makeUnique<DetachedOffscreenCanvas>(takeImageBuffer(), size(), originClean());
    392     detached->m_placeholderCanvas = std::exchange(m_placeholderCanvas, nullptr);
     391    detached->m_placeholderCanvas = std::exchange(m_placeholderData->canvas, nullptr);
    393392
    394393    return detached;
    … …  
    399398    ASSERT(!m_context);
    400399    ASSERT(isMainThread());
    401     m_placeholderCanvas = makeWeakPtr(canvas);
     400    m_placeholderData->canvas = makeWeakPtr(canvas);
    402401    auto& placeholderContext = downcast<PlaceholderRenderingContext>(*canvas.renderingContext());
    403402    auto& imageBufferPipe = placeholderContext.imageBufferPipe();
    404403    if (imageBufferPipe)
    405         m_bufferPipeSource = imageBufferPipe->source();
     404        m_placeholderData->bufferPipeSource = imageBufferPipe->source();
    406405}
    407406
    408407void OffscreenCanvas::pushBufferToPlaceholder()
    409408{
    410     callOnMainThread([protectedThis = makeRef(*this), this] () mutable {
    411         {
    412             auto locker = holdLock(m_commitLock);
    413             if (m_placeholderCanvas && m_pendingCommitBuffer)
    414                 m_placeholderCanvas->setImageBufferAndMarkDirty(WTFMove(m_pendingCommitBuffer));
    415             m_pendingCommitBuffer = nullptr;
    416         }
    417 
    418         scriptExecutionContext()->postTask({ ScriptExecutionContext::Task::CleanupTask,
    419             [releaseThis = WTFMove(protectedThis)] (ScriptExecutionContext&) { } });
     409    callOnMainThread([placeholderData = makeRef(*m_placeholderData)] () mutable {
     410        auto locker = holdLock(placeholderData->bufferLock);
     411        if (placeholderData->canvas && placeholderData->pendingCommitBuffer)
     412            placeholderData->canvas->setImageBufferAndMarkDirty(WTFMove(placeholderData->pendingCommitBuffer));
     413        placeholderData->pendingCommitBuffer = nullptr;
    420414    });
    421415}
    … …  
    431425        m_context->paintRenderingResultsToCanvas();
    432426
    433     if (m_bufferPipeSource) {
     427    if (m_placeholderData->bufferPipeSource) {
    434428        auto bufferCopy = imageBuffer->copyRectToBuffer(FloatRect(FloatPoint(), imageBuffer->logicalSize()), ColorSpace::SRGB, imageBuffer->context());
    435429        if (bufferCopy)
    436             m_bufferPipeSource->handle(WTFMove(bufferCopy));
    437     }
    438 
    439     auto locker = holdLock(m_commitLock);
    440     bool shouldPushBuffer = !m_pendingCommitBuffer;
    441     m_pendingCommitBuffer = imageBuffer->copyRectToBuffer(FloatRect(FloatPoint(), imageBuffer->logicalSize()), ColorSpace::SRGB, imageBuffer->context());
    442     if (m_pendingCommitBuffer && shouldPushBuffer)
     430            m_placeholderData->bufferPipeSource->handle(WTFMove(bufferCopy));
     431    }
     432
     433    auto locker = holdLock(m_placeholderData->bufferLock);
     434    bool shouldPushBuffer = !m_placeholderData->pendingCommitBuffer;
     435    m_placeholderData->pendingCommitBuffer = imageBuffer->copyRectToBuffer(FloatRect(FloatPoint(), imageBuffer->logicalSize()), ColorSpace::SRGB, imageBuffer->context());
     436    if (m_placeholderData->pendingCommitBuffer && shouldPushBuffer)
    443437        pushBufferToPlaceholder();
    444438}
  • trunk/Source/WebCore/html/OffscreenCanvas.h

    r267735 r269046  
    4040#include <wtf/Forward.h>
    4141#include <wtf/RefCounted.h>
     42#include <wtf/ThreadSafeRefCounted.h>
    4243#include <wtf/WeakPtr.h>
    4344#include <wtf/text/WTFString.h>
    … …  
    188189
    189190    bool m_hasScheduledCommit { false };
    190     WeakPtr<HTMLCanvasElement> m_placeholderCanvas;
    191     RefPtr<ImageBufferPipe::Source> m_bufferPipeSource;
    192 
    193     mutable Lock m_commitLock;
    194     std::unique_ptr<ImageBuffer> m_pendingCommitBuffer;
     191
     192    class PlaceholderData : public ThreadSafeRefCounted<PlaceholderData> {
     193    public:
     194        static Ref<PlaceholderData> create()
     195        {
     196            return adoptRef(*new PlaceholderData);
     197        }
     198
     199        WeakPtr<HTMLCanvasElement> canvas;
     200        RefPtr<ImageBufferPipe::Source> bufferPipeSource;
     201        std::unique_ptr<ImageBuffer> pendingCommitBuffer;
     202        mutable Lock bufferLock;
     203    };
     204
     205    RefPtr<PlaceholderData> m_placeholderData;
    195206};
    196207
Note: See TracChangeset for help on using the changeset viewer.