Title: [290547] trunk/Source/WebKit
Revision
290547
Author
[email protected]
Date
2022-02-26 04:07:43 -0800 (Sat, 26 Feb 2022)

Log Message

Multiple concurrency violations in LibWebRTCCodecsProxy
https://bugs.webkit.org/show_bug.cgi?id=236767
<rdar://88904160>

Patch by Kimmo Kinnunen <[email protected]> on 2022-02-26
Reviewed by Antti Koivisto.

- ThreadMessageReceivers should not add IPC listeners in constructors,
as the delivery starts right away and uses the unconstructed virtual pointer.
- The work queue functions should not use GPUConnectionToWebProcess, as that is
main thread object.
- Locked m_encoders, m_decoders are sometimes accessed without lock.

Instead:
- Add the IPC listeners in initialize function.
- Remove the IPC listeners when GPUConnectionToWebProcess disconnects.
- Store the thread-safe conection, video frame object heap, process identity
objects as member variables.
- Do not lock m_encoders, m_decoders. If they are work queue instances,
just access them in the work queue functions. Add thread requirements
to the variables so that the compiler checks the access.
- Use IPC testing assertions when skipping incorrect messages.
- Use separate atomic counter (bool) to check if allowsExitUnderMemoryPressure.

No new tests, tested with existing tests and ASAN.

* GPUProcess/GPUConnectionToWebProcess.cpp:
(WebKit::GPUConnectionToWebProcess::~GPUConnectionToWebProcess):
(WebKit::GPUConnectionToWebProcess::didClose):
* GPUProcess/GPUConnectionToWebProcess.h:
* GPUProcess/webrtc/LibWebRTCCodecsProxy.h:
* GPUProcess/webrtc/LibWebRTCCodecsProxy.mm:
(WebKit::LibWebRTCCodecsProxy::create):
(WebKit::LibWebRTCCodecsProxy::LibWebRTCCodecsProxy):
(WebKit::LibWebRTCCodecsProxy::stopListeningForIPC):
(WebKit::LibWebRTCCodecsProxy::initialize):
(WebKit::LibWebRTCCodecsProxy::dispatchToThread):
(WebKit::LibWebRTCCodecsProxy::createDecoderCallback):
(WebKit::LibWebRTCCodecsProxy::createH264Decoder):
(WebKit::LibWebRTCCodecsProxy::createH265Decoder):
(WebKit::LibWebRTCCodecsProxy::createVP9Decoder):
(WebKit::LibWebRTCCodecsProxy::releaseDecoder):
(WebKit::LibWebRTCCodecsProxy::createEncoder):
(WebKit::LibWebRTCCodecsProxy::releaseEncoder):
(WebKit::LibWebRTCCodecsProxy::initializeEncoder):
(WebKit::LibWebRTCCodecsProxy::findEncoder):
(WebKit::LibWebRTCCodecsProxy::encodeFrame):
(WebKit::LibWebRTCCodecsProxy::setEncodeRates):
(WebKit::LibWebRTCCodecsProxy::setSharedVideoFrameSemaphore):
(WebKit::LibWebRTCCodecsProxy::setSharedVideoFrameMemory):
(WebKit::LibWebRTCCodecsProxy::allowsExitUnderMemoryPressure const):

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (290546 => 290547)


--- trunk/Source/WebKit/ChangeLog	2022-02-26 10:04:15 UTC (rev 290546)
+++ trunk/Source/WebKit/ChangeLog	2022-02-26 12:07:43 UTC (rev 290547)
@@ -1,3 +1,56 @@
+2022-02-26  Kimmo Kinnunen  <[email protected]>
+
+        Multiple concurrency violations in LibWebRTCCodecsProxy
+        https://bugs.webkit.org/show_bug.cgi?id=236767
+        <rdar://88904160>
+
+        Reviewed by Antti Koivisto.
+
+        - ThreadMessageReceivers should not add IPC listeners in constructors,
+        as the delivery starts right away and uses the unconstructed virtual pointer.
+        - The work queue functions should not use GPUConnectionToWebProcess, as that is
+        main thread object.
+        - Locked m_encoders, m_decoders are sometimes accessed without lock.
+
+        Instead:
+        - Add the IPC listeners in initialize function.
+        - Remove the IPC listeners when GPUConnectionToWebProcess disconnects.
+        - Store the thread-safe conection, video frame object heap, process identity
+        objects as member variables.
+        - Do not lock m_encoders, m_decoders. If they are work queue instances,
+        just access them in the work queue functions. Add thread requirements
+        to the variables so that the compiler checks the access.
+        - Use IPC testing assertions when skipping incorrect messages.
+        - Use separate atomic counter (bool) to check if allowsExitUnderMemoryPressure.
+
+        No new tests, tested with existing tests and ASAN.
+
+        * GPUProcess/GPUConnectionToWebProcess.cpp:
+        (WebKit::GPUConnectionToWebProcess::~GPUConnectionToWebProcess):
+        (WebKit::GPUConnectionToWebProcess::didClose):
+        * GPUProcess/GPUConnectionToWebProcess.h:
+        * GPUProcess/webrtc/LibWebRTCCodecsProxy.h:
+        * GPUProcess/webrtc/LibWebRTCCodecsProxy.mm:
+        (WebKit::LibWebRTCCodecsProxy::create):
+        (WebKit::LibWebRTCCodecsProxy::LibWebRTCCodecsProxy):
+        (WebKit::LibWebRTCCodecsProxy::stopListeningForIPC):
+        (WebKit::LibWebRTCCodecsProxy::initialize):
+        (WebKit::LibWebRTCCodecsProxy::dispatchToThread):
+        (WebKit::LibWebRTCCodecsProxy::createDecoderCallback):
+        (WebKit::LibWebRTCCodecsProxy::createH264Decoder):
+        (WebKit::LibWebRTCCodecsProxy::createH265Decoder):
+        (WebKit::LibWebRTCCodecsProxy::createVP9Decoder):
+        (WebKit::LibWebRTCCodecsProxy::releaseDecoder):
+        (WebKit::LibWebRTCCodecsProxy::createEncoder):
+        (WebKit::LibWebRTCCodecsProxy::releaseEncoder):
+        (WebKit::LibWebRTCCodecsProxy::initializeEncoder):
+        (WebKit::LibWebRTCCodecsProxy::findEncoder):
+        (WebKit::LibWebRTCCodecsProxy::encodeFrame):
+        (WebKit::LibWebRTCCodecsProxy::setEncodeRates):
+        (WebKit::LibWebRTCCodecsProxy::setSharedVideoFrameSemaphore):
+        (WebKit::LibWebRTCCodecsProxy::setSharedVideoFrameMemory):
+        (WebKit::LibWebRTCCodecsProxy::allowsExitUnderMemoryPressure const):
+
 2022-02-25  Sihui Liu  <[email protected]>
 
         [macOS] TestWebKitAPI.WebKit.MigrateLocalStorageDataToGeneralStorageDirectory is a flaky failure

Modified: trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.cpp (290546 => 290547)


--- trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.cpp	2022-02-26 10:04:15 UTC (rev 290546)
+++ trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.cpp	2022-02-26 12:07:43 UTC (rev 290547)
@@ -287,9 +287,6 @@
 #if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM)
     m_sampleBufferDisplayLayerManager->close();
 #endif
-#if PLATFORM(COCOA) && USE(LIBWEBRTC)
-    m_libWebRTCCodecsProxy->close();
-#endif
 
     --gObjectCountForTesting;
 }
@@ -324,7 +321,9 @@
         WCContentBufferManager::singleton().removeAllContentBuffersForProcess(webProcessIdentifier);
     });
 #endif
-
+#if PLATFORM(COCOA) && USE(LIBWEBRTC)
+    m_libWebRTCCodecsProxy = nullptr;
+#endif
     gpuProcess().connectionToWebProcessClosed(connection);
     gpuProcess().removeGPUConnectionToWebProcess(*this); // May destroy |this|.
 }

Modified: trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.h (290546 => 290547)


--- trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.h	2022-02-26 10:04:15 UTC (rev 290546)
+++ trunk/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.h	2022-02-26 12:07:43 UTC (rev 290547)
@@ -313,7 +313,7 @@
     IPC::ScopedActiveMessageReceiveQueue<RemoteVideoFrameObjectHeap> m_videoFrameObjectHeap;
 #endif
 #if PLATFORM(COCOA) && USE(LIBWEBRTC)
-    Ref<LibWebRTCCodecsProxy> m_libWebRTCCodecsProxy;
+    IPC::ScopedActiveMessageReceiveQueue<LibWebRTCCodecsProxy> m_libWebRTCCodecsProxy;
 #endif
 #if HAVE(AUDIT_TOKEN)
     std::optional<audit_token_t> m_presentingApplicationAuditToken;

Modified: trunk/Source/WebKit/GPUProcess/webrtc/LibWebRTCCodecsProxy.h (290546 => 290547)


--- trunk/Source/WebKit/GPUProcess/webrtc/LibWebRTCCodecsProxy.h	2022-02-26 10:04:15 UTC (rev 290546)
+++ trunk/Source/WebKit/GPUProcess/webrtc/LibWebRTCCodecsProxy.h	2022-02-26 12:07:43 UTC (rev 290547)
@@ -35,7 +35,8 @@
 #include "SharedMemory.h"
 #include "SharedVideoFrame.h"
 #include <WebCore/ProcessIdentity.h>
-#include <wtf/Lock.h>
+#include <atomic>
+#include <wtf/ThreadAssertions.h>
 
 namespace IPC {
 class Connection;
@@ -58,18 +59,19 @@
 class RemoteVideoFrameObjectHeap;
 class SharedVideoFrameReader;
 
-class LibWebRTCCodecsProxy : public IPC::Connection::ThreadMessageReceiverRefCounted {
+class LibWebRTCCodecsProxy final : public IPC::Connection::ThreadMessageReceiverRefCounted {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    static Ref<LibWebRTCCodecsProxy> create(GPUConnectionToWebProcess& process) { return adoptRef(*new LibWebRTCCodecsProxy(process)); }
+    static Ref<LibWebRTCCodecsProxy> create(GPUConnectionToWebProcess&);
     ~LibWebRTCCodecsProxy();
-
-    void close();
-
+    void stopListeningForIPC(Ref<LibWebRTCCodecsProxy>&& refFromConnection);
     bool allowsExitUnderMemoryPressure() const;
 
 private:
     explicit LibWebRTCCodecsProxy(GPUConnectionToWebProcess&);
+    void initialize();
+    auto createDecoderCallback(RTCDecoderIdentifier, bool useRemoteFrames);
+    WorkQueue& workQueue() const { return m_queue; }
 
     // IPC::Connection::ThreadMessageReceiver
     void dispatchToThread(Function<void()>&&) final;
@@ -92,20 +94,19 @@
     void setSharedVideoFrameMemory(RTCEncoderIdentifier, const SharedMemory::IPCHandle&);
     void setRTCLoggingLevel(WTFLogLevel);
 
-    GPUConnectionToWebProcess& m_gpuConnectionToWebProcess;
-
     struct Encoder {
         webrtc::LocalEncoder webrtcEncoder { nullptr };
         std::unique_ptr<SharedVideoFrameReader> frameReader;
     };
-    Encoder* findEncoderWithoutLock(RTCEncoderIdentifier);
+    Encoder* findEncoder(RTCEncoderIdentifier) WTF_REQUIRES_CAPABILITY(workQueue());
 
-    mutable Lock m_lock;
-    HashMap<RTCDecoderIdentifier, webrtc::LocalDecoder> m_decoders WTF_GUARDED_BY_LOCK(m_lock); // Only modified on the libWebRTCCodecsQueue but may get accessed from the main thread.
-    HashMap<RTCEncoderIdentifier, Encoder> m_encoders WTF_GUARDED_BY_LOCK(m_lock); // Only modified on the libWebRTCCodecsQueue but may get accessed from the main thread.
+    Ref<IPC::Connection> m_connection;
     Ref<WorkQueue> m_queue;
     Ref<RemoteVideoFrameObjectHeap> m_videoFrameObjectHeap;
     WebCore::ProcessIdentity m_resourceOwner;
+    HashMap<RTCDecoderIdentifier, webrtc::LocalDecoder> m_decoders WTF_GUARDED_BY_CAPABILITY(workQueue());
+    HashMap<RTCEncoderIdentifier, Encoder> m_encoders WTF_GUARDED_BY_CAPABILITY(workQueue());
+    std::atomic<bool> m_hasEncodersOrDecoders { false };
 };
 
 }

Modified: trunk/Source/WebKit/GPUProcess/webrtc/LibWebRTCCodecsProxy.mm (290546 => 290547)


--- trunk/Source/WebKit/GPUProcess/webrtc/LibWebRTCCodecsProxy.mm	2022-02-26 10:04:15 UTC (rev 290546)
+++ trunk/Source/WebKit/GPUProcess/webrtc/LibWebRTCCodecsProxy.mm	2022-02-26 12:07:43 UTC (rev 290547)
@@ -30,6 +30,7 @@
 
 #import "GPUConnectionToWebProcess.h"
 #import "GPUProcess.h"
+#import "IPCTester.h"
 #import "LibWebRTCCodecsMessages.h"
 #import "LibWebRTCCodecsProxyMessages.h"
 #import "RemoteVideoFrameIdentifier.h"
@@ -49,30 +50,29 @@
 
 namespace WebKit {
 
-LibWebRTCCodecsProxy::LibWebRTCCodecsProxy(GPUConnectionToWebProcess& connection)
-    : m_gpuConnectionToWebProcess(connection)
-    , m_queue(connection.gpuProcess().libWebRTCCodecsQueue())
-    , m_videoFrameObjectHeap(connection.videoFrameObjectHeap())
-    , m_resourceOwner(connection.webProcessIdentity())
+Ref<LibWebRTCCodecsProxy> LibWebRTCCodecsProxy::create(GPUConnectionToWebProcess& webProcessConnection)
 {
-    m_gpuConnectionToWebProcess.connection().addThreadMessageReceiver(Messages::LibWebRTCCodecsProxy::messageReceiverName(), this);
+    auto instance = adoptRef(*new LibWebRTCCodecsProxy(webProcessConnection));
+    instance->initialize();
+    return instance;
 }
 
-LibWebRTCCodecsProxy::~LibWebRTCCodecsProxy()
+LibWebRTCCodecsProxy::LibWebRTCCodecsProxy(GPUConnectionToWebProcess& webProcessConnection)
+    : m_connection(webProcessConnection.connection())
+    , m_queue(webProcessConnection.gpuProcess().libWebRTCCodecsQueue())
+    , m_videoFrameObjectHeap(webProcessConnection.videoFrameObjectHeap())
+    , m_resourceOwner(webProcessConnection.webProcessIdentity())
 {
 }
 
-void LibWebRTCCodecsProxy::dispatchToThread(Function<void()>&& function)
-{
-    m_queue->dispatch(WTFMove(function));
-}
+LibWebRTCCodecsProxy::~LibWebRTCCodecsProxy() = default;
 
-void LibWebRTCCodecsProxy::close()
+void LibWebRTCCodecsProxy::stopListeningForIPC(Ref<LibWebRTCCodecsProxy>&& refFromConnection)
 {
-    m_gpuConnectionToWebProcess.connection().removeThreadMessageReceiver(Messages::LibWebRTCCodecsProxy::messageReceiverName());
+    m_connection->removeThreadMessageReceiver(Messages::LibWebRTCCodecsProxy::messageReceiverName());
 
-    dispatchToThread([this, protectedThis = Ref { *this }] {
-        Locker locker { m_lock };
+    dispatchToThread([this, protectedThis = WTFMove(refFromConnection)] {
+        assertIsCurrent(workQueue());
         auto decoders = WTFMove(m_decoders);
         for (auto decoder : decoders.values())
             webrtc::releaseLocalDecoder(decoder);
@@ -82,15 +82,28 @@
     });
 }
 
-static Function<void(CVPixelBufferRef pixelBuffer, uint32_t timeStampNs, uint32_t timeStamp)> createDecoderCallback(RTCDecoderIdentifier identifier, GPUConnectionToWebProcess& gpuConnectionToWebProcess, bool useRemoteFrames)
+void LibWebRTCCodecsProxy::initialize()
 {
-    return [connection = Ref { gpuConnectionToWebProcess.connection() }, resourceOwner = gpuConnectionToWebProcess.webProcessIdentity(), videoFrameObjectHeap = Ref { gpuConnectionToWebProcess.videoFrameObjectHeap() }, identifier, useRemoteFrames] (CVPixelBufferRef pixelBuffer, uint32_t timeStampNs, uint32_t timeStamp)  mutable {
+    m_connection->addThreadMessageReceiver(Messages::LibWebRTCCodecsProxy::messageReceiverName(), this);
+}
+
+void LibWebRTCCodecsProxy::dispatchToThread(Function<void()>&& function)
+{
+    m_queue->dispatch(WTFMove(function));
+}
+
+auto LibWebRTCCodecsProxy::createDecoderCallback(RTCDecoderIdentifier identifier, bool useRemoteFrames)
+{
+    RefPtr<RemoteVideoFrameObjectHeap> videoFrameObjectHeap;
+    if (useRemoteFrames)
+        videoFrameObjectHeap = m_videoFrameObjectHeap.ptr();
+    return [identifier, connection = m_connection, resourceOwner = m_resourceOwner, videoFrameObjectHeap = WTFMove(videoFrameObjectHeap)] (CVPixelBufferRef pixelBuffer, uint32_t timeStampNs, uint32_t timeStamp) mutable {
         auto sample = WebCore::MediaSampleAVFObjC::createImageSample(pixelBuffer, WebCore::MediaSample::VideoRotation::None, false, MediaTime(timeStampNs, 1), { });
         if (!sample)
             return;
         if (resourceOwner)
             sample->setOwnershipIdentity(resourceOwner);
-        if (useRemoteFrames) {
+        if (videoFrameObjectHeap) {
             auto properties = videoFrameObjectHeap->add(sample.releaseNonNull());
             connection->send(Messages::LibWebRTCCodecs::CompletedDecoding { identifier, timeStamp, WTFMove(properties) }, 0);
             return;
@@ -104,105 +117,104 @@
 
 void LibWebRTCCodecsProxy::createH264Decoder(RTCDecoderIdentifier identifier, bool useRemoteFrames)
 {
-    ASSERT(!isMainRunLoop());
-    Locker locker { m_lock };
-    ASSERT(!m_decoders.contains(identifier));
-    m_decoders.add(identifier, webrtc::createLocalH264Decoder(makeBlockPtr(createDecoderCallback(identifier, m_gpuConnectionToWebProcess, useRemoteFrames)).get()));
+    assertIsCurrent(workQueue());
+    auto result = m_decoders.add(identifier, webrtc::createLocalH264Decoder(makeBlockPtr(createDecoderCallback(identifier, useRemoteFrames)).get()));
+    ASSERT_UNUSED(result, result.isNewEntry || isTestingIPC());
+    m_hasEncodersOrDecoders = true;
 }
 
 void LibWebRTCCodecsProxy::createH265Decoder(RTCDecoderIdentifier identifier, bool useRemoteFrames)
 {
-    ASSERT(!isMainRunLoop());
-    Locker locker { m_lock };
-    ASSERT(!m_decoders.contains(identifier));
-    m_decoders.add(identifier, webrtc::createLocalH265Decoder(makeBlockPtr(createDecoderCallback(identifier, m_gpuConnectionToWebProcess, useRemoteFrames)).get()));
+    assertIsCurrent(workQueue());
+    auto result = m_decoders.add(identifier, webrtc::createLocalH265Decoder(makeBlockPtr(createDecoderCallback(identifier, useRemoteFrames)).get()));
+    ASSERT_UNUSED(result, result.isNewEntry || isTestingIPC());
+    m_hasEncodersOrDecoders = true;
 }
 
 void LibWebRTCCodecsProxy::createVP9Decoder(RTCDecoderIdentifier identifier, bool useRemoteFrames)
 {
-    ASSERT(!isMainRunLoop());
-    Locker locker { m_lock };
-    ASSERT(!m_decoders.contains(identifier));
-    m_decoders.add(identifier, webrtc::createLocalVP9Decoder(makeBlockPtr(createDecoderCallback(identifier, m_gpuConnectionToWebProcess, useRemoteFrames)).get()));
+    assertIsCurrent(workQueue());
+    auto result = m_decoders.add(identifier, webrtc::createLocalVP9Decoder(makeBlockPtr(createDecoderCallback(identifier, useRemoteFrames)).get()));
+    ASSERT_UNUSED(result, result.isNewEntry || isTestingIPC());
+    m_hasEncodersOrDecoders = true;
 }
 
 void LibWebRTCCodecsProxy::releaseDecoder(RTCDecoderIdentifier identifier)
 {
-    ASSERT(!isMainRunLoop());
-    Locker locker { m_lock };
-    ASSERT(m_decoders.contains(identifier));
-    if (auto decoder = m_decoders.take(identifier))
-        webrtc::releaseLocalDecoder(decoder);
+    assertIsCurrent(workQueue());
+    auto decoder = m_decoders.take(identifier);
+    if (!decoder) {
+        ASSERT_IS_TESTING_IPC();
+        return;
+    }
+    webrtc::releaseLocalDecoder(decoder);
+    m_hasEncodersOrDecoders = !m_encoders.isEmpty() || !m_decoders.isEmpty();
 }
 
-// For performance reasons, this function accesses m_decoders without locking. This is safe because this function runs on the libWebRTCCodecsQueue
-// and m_decoders only get modified on this queue.
 void LibWebRTCCodecsProxy::decodeFrame(RTCDecoderIdentifier identifier, uint32_t timeStamp, const IPC::DataReference& data) WTF_IGNORES_THREAD_SAFETY_ANALYSIS
 {
-    ASSERT(!isMainRunLoop());
-    ASSERT(m_decoders.contains(identifier));
+    assertIsCurrent(workQueue());
     auto decoder = m_decoders.get(identifier);
-    if (!decoder)
+    if (!decoder) {
+        ASSERT_IS_TESTING_IPC();
         return;
-
+    }
     if (webrtc::decodeFrame(decoder, timeStamp, data.data(), data.size()))
-        m_gpuConnectionToWebProcess.connection().send(Messages::LibWebRTCCodecs::FailedDecoding { identifier }, 0);
+        m_connection->send(Messages::LibWebRTCCodecs::FailedDecoding { identifier }, 0);
 }
 
-// For performance reasons, this function accesses m_decoders without locking. This is safe because this function runs on the libWebRTCCodecsQueue
-// and m_decoders only get modified on this queue.
 void LibWebRTCCodecsProxy::setFrameSize(RTCDecoderIdentifier identifier, uint16_t width, uint16_t height) WTF_IGNORES_THREAD_SAFETY_ANALYSIS
 {
-    ASSERT(!isMainRunLoop());
-    ASSERT(m_decoders.contains(identifier));
+    assertIsCurrent(workQueue());
     auto decoder = m_decoders.get(identifier);
-    if (!decoder)
+    if (!decoder) {
+        ASSERT_IS_TESTING_IPC();
         return;
-
+    }
     webrtc::setDecoderFrameSize(decoder, width, height);
 }
 
 void LibWebRTCCodecsProxy::createEncoder(RTCEncoderIdentifier identifier, const String& formatName, const Vector<std::pair<String, String>>& parameters, bool useLowLatency)
 {
-    ASSERT(!isMainRunLoop());
-    Locker locker { m_lock };
-    ASSERT(!m_encoders.contains(identifier));
-
+    assertIsCurrent(workQueue());
     std::map<std::string, std::string> rtcParameters;
     for (auto& parameter : parameters)
         rtcParameters.emplace(parameter.first.utf8().data(), parameter.second.utf8().data());
 
-    auto* encoder = webrtc::createLocalEncoder(webrtc::SdpVideoFormat { formatName.utf8().data(), rtcParameters }, makeBlockPtr([connection = Ref { m_gpuConnectionToWebProcess.connection() }, identifier](const uint8_t* buffer, size_t size, const webrtc::WebKitEncodedFrameInfo& info) {
+    auto* encoder = webrtc::createLocalEncoder(webrtc::SdpVideoFormat { formatName.utf8().data(), rtcParameters }, makeBlockPtr([connection = m_connection, identifier](const uint8_t* buffer, size_t size, const webrtc::WebKitEncodedFrameInfo& info) {
         connection->send(Messages::LibWebRTCCodecs::CompletedEncoding { identifier, IPC::DataReference { buffer, size }, info }, 0);
     }).get());
     webrtc::setLocalEncoderLowLatency(encoder, useLowLatency);
-    m_encoders.add(identifier, Encoder { encoder, nullptr });
+    auto result = m_encoders.add(identifier, Encoder { encoder, nullptr });
+    ASSERT_UNUSED(result, result.isNewEntry || isTestingIPC());
+    m_hasEncodersOrDecoders = true;
 }
 
 void LibWebRTCCodecsProxy::releaseEncoder(RTCEncoderIdentifier identifier)
 {
-    ASSERT(!isMainRunLoop());
-    Locker locker { m_lock };
-    ASSERT(m_encoders.contains(identifier));
+    assertIsCurrent(workQueue());
     auto encoder = m_encoders.take(identifier);
-    if (encoder.webrtcEncoder)
-        webrtc::releaseLocalEncoder(encoder.webrtcEncoder);
+    if (!encoder.webrtcEncoder) {
+        ASSERT_IS_TESTING_IPC();
+        return;
+    }
+    webrtc::releaseLocalEncoder(encoder.webrtcEncoder);
+    m_hasEncodersOrDecoders = !m_encoders.isEmpty() || !m_decoders.isEmpty();
 }
 
-// For performance reasons, this function accesses m_encoders without locking. This is safe because this function runs on the libWebRTCCodecsQueue
-// and m_encoders only get modified on this queue.
 void LibWebRTCCodecsProxy::initializeEncoder(RTCEncoderIdentifier identifier, uint16_t width, uint16_t height, unsigned startBitrate, unsigned maxBitrate, unsigned minBitrate, uint32_t maxFramerate)
 {
-    auto* encoder = findEncoderWithoutLock(identifier);
-    if (!encoder)
+    assertIsCurrent(workQueue());
+    auto* encoder = findEncoder(identifier);
+    if (!encoder) {
+        ASSERT_IS_TESTING_IPC();
         return;
-
+    }
     webrtc::initializeLocalEncoder(encoder->webrtcEncoder, width, height, startBitrate, maxBitrate, minBitrate, maxFramerate);
 }
 
-LibWebRTCCodecsProxy::Encoder* LibWebRTCCodecsProxy::findEncoderWithoutLock(RTCEncoderIdentifier identifier) WTF_IGNORES_THREAD_SAFETY_ANALYSIS
+LibWebRTCCodecsProxy::Encoder* LibWebRTCCodecsProxy::findEncoder(RTCEncoderIdentifier identifier)
 {
-    ASSERT(!isMainRunLoop());
     auto iterator = m_encoders.find(identifier);
     if (iterator == m_encoders.end())
         return nullptr;
@@ -225,10 +237,9 @@
     return webrtc::kVideoRotation_0;
 }
 
-// For performance reasons, this function accesses m_encoders without locking. This is safe because this function runs on the libWebRTCCodecsQueue
-// and m_encoders only get modified on this queue.
 void LibWebRTCCodecsProxy::encodeFrame(RTCEncoderIdentifier identifier, WebCore::RemoteVideoSample&& sample, uint32_t timeStamp, bool shouldEncodeAsKeyFrame, std::optional<RemoteVideoFrameReadReference> sampleReference)
 {
+    assertIsCurrent(workQueue());
     RetainPtr<CVPixelBufferRef> pixelBuffer;
     if (sampleReference) {
         auto sample = m_videoFrameObjectHeap->get(WTFMove(*sampleReference));
@@ -240,10 +251,11 @@
         pixelBuffer = static_cast<CVPixelBufferRef>(PAL::CMSampleBufferGetImageBuffer(platformSample.sample.cmSampleBuffer));
     }
 
-    ASSERT(findEncoderWithoutLock(identifier));
-    auto* encoder = findEncoderWithoutLock(identifier);
-    if (!encoder)
+    auto* encoder = findEncoder(identifier);
+    if (!encoder) {
+        ASSERT_IS_TESTING_IPC();
         return;
+    }
 
 #if !PLATFORM(MACCATALYST)
     if (!pixelBuffer) {
@@ -261,25 +273,26 @@
 #endif
 }
 
-// For performance reasons, this function accesses m_encoders without locking. This is safe because this function runs on the libWebRTCCodecsQueue
-// and m_encoders only get modified on this queue.
 void LibWebRTCCodecsProxy::setEncodeRates(RTCEncoderIdentifier identifier, uint32_t bitRate, uint32_t frameRate)
 {
-    auto* encoder = findEncoderWithoutLock(identifier);
-    if (!encoder)
+    assertIsCurrent(workQueue());
+    auto* encoder = findEncoder(identifier);
+    if (!encoder) {
+        ASSERT_IS_TESTING_IPC();
         return;
+    }
 
     webrtc::setLocalEncoderRates(encoder->webrtcEncoder, bitRate, frameRate);
 }
 
-// For performance reasons, this function accesses m_encoders without locking. This is safe because this function runs on the libWebRTCCodecsQueue
-// and m_encoders only get modified on this queue.
 void LibWebRTCCodecsProxy::setSharedVideoFrameSemaphore(RTCEncoderIdentifier identifier, IPC::Semaphore&& semaphore)
 {
-    ASSERT(findEncoderWithoutLock(identifier));
-    auto* encoder = findEncoderWithoutLock(identifier);
-    if (!encoder)
+    assertIsCurrent(workQueue());
+    auto* encoder = findEncoder(identifier);
+    if (!encoder) {
+        ASSERT_IS_TESTING_IPC();
         return;
+    }
 
     if (!encoder->frameReader)
         encoder->frameReader = makeUnique<SharedVideoFrameReader>(Ref { m_videoFrameObjectHeap }, m_resourceOwner);
@@ -286,14 +299,14 @@
     encoder->frameReader->setSemaphore(WTFMove(semaphore));
 }
 
-// For performance reasons, this function accesses m_encoders without locking. This is safe because this function runs on the libWebRTCCodecsQueue
-// and m_encoders only get modified on this queue.
 void LibWebRTCCodecsProxy::setSharedVideoFrameMemory(RTCEncoderIdentifier identifier, const SharedMemory::IPCHandle& ipcHandle)
 {
-    ASSERT(findEncoderWithoutLock(identifier));
-    auto* encoder = findEncoderWithoutLock(identifier);
-    if (!encoder)
+    assertIsCurrent(workQueue());
+    auto* encoder = findEncoder(identifier);
+    if (!encoder) {
+        ASSERT_IS_TESTING_IPC();
         return;
+    }
 
     if (!encoder->frameReader)
         encoder->frameReader = makeUnique<SharedVideoFrameReader>(Ref { m_videoFrameObjectHeap }, m_resourceOwner);
@@ -302,9 +315,8 @@
 
 bool LibWebRTCCodecsProxy::allowsExitUnderMemoryPressure() const
 {
-    ASSERT(isMainRunLoop());
-    Locker locker { m_lock };
-    return m_encoders.isEmpty() && m_decoders.isEmpty();
+    assertIsMainRunLoop();
+    return !m_hasEncodersOrDecoders;
 }
 
 void LibWebRTCCodecsProxy::setRTCLoggingLevel(WTFLogLevel level)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to