Changeset 293270 in webkit
- Timestamp:
- Apr 22, 2022, 5:04:16 PM (4 years ago)
- Location:
- branches/safari-613.2.7.1-branch/Source/WebKit
- Files:
-
- 5 edited
-
ChangeLog (modified) (1 diff)
-
GPUProcess/GPUConnectionToWebProcess.cpp (modified) (2 diffs)
-
GPUProcess/GPUConnectionToWebProcess.h (modified) (1 diff)
-
GPUProcess/webrtc/LibWebRTCCodecsProxy.h (modified) (3 diffs)
-
GPUProcess/webrtc/LibWebRTCCodecsProxy.mm (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/safari-613.2.7.1-branch/Source/WebKit/ChangeLog
r293269 r293270 1 2022-04-22 Russell Epstein <repstein@apple.com> 2 3 Apply patch. rdar://problem/88904160 4 5 2022-04-22 Kimmo Kinnunen <kkinnunen@apple.com> 6 7 Multiple concurrency violations in LibWebRTCCodecsProxy 8 https://bugs.webkit.org/show_bug.cgi?id=236767 9 <rdar://88904160> 10 11 Reviewed by Antti Koivisto. 12 13 - ThreadMessageReceivers should not add IPC listeners in constructors, 14 as the delivery starts right away and uses the unconstructed virtual pointer. 15 - The work queue functions should not use GPUConnectionToWebProcess, as that is 16 main thread object. 17 - Locked m_encoders, m_decoders are sometimes accessed without lock. 18 19 Instead: 20 - Add the IPC listeners in initialize function. 21 - Remove the IPC listeners when GPUConnectionToWebProcess disconnects. 22 - Store the thread-safe conection, video frame object heap, process identity 23 objects as member variables. 24 - Do not lock m_encoders, m_decoders. If they are work queue instances, 25 just access them in the work queue functions. Add thread requirements 26 to the variables so that the compiler checks the access. 27 - Use IPC testing assertions when skipping incorrect messages. 28 - Use separate atomic counter (bool) to check if allowsExitUnderMemoryPressure. 29 30 No new tests, tested with existing tests and ASAN. 31 32 * GPUProcess/GPUConnectionToWebProcess.cpp: 33 (WebKit::GPUConnectionToWebProcess::~GPUConnectionToWebProcess): 34 (WebKit::GPUConnectionToWebProcess::didClose): 35 * GPUProcess/GPUConnectionToWebProcess.h: 36 * GPUProcess/webrtc/LibWebRTCCodecsProxy.h: 37 * GPUProcess/webrtc/LibWebRTCCodecsProxy.mm: 38 (WebKit::LibWebRTCCodecsProxy::create): 39 (WebKit::LibWebRTCCodecsProxy::LibWebRTCCodecsProxy): 40 (WebKit::LibWebRTCCodecsProxy::stopListeningForIPC): 41 (WebKit::LibWebRTCCodecsProxy::initialize): 42 (WebKit::LibWebRTCCodecsProxy::dispatchToThread): 43 (WebKit::LibWebRTCCodecsProxy::createDecoderCallback): 44 (WebKit::LibWebRTCCodecsProxy::createH264Decoder): 45 (WebKit::LibWebRTCCodecsProxy::createH265Decoder): 46 (WebKit::LibWebRTCCodecsProxy::createVP9Decoder): 47 (WebKit::LibWebRTCCodecsProxy::releaseDecoder): 48 (WebKit::LibWebRTCCodecsProxy::createEncoder): 49 (WebKit::LibWebRTCCodecsProxy::releaseEncoder): 50 (WebKit::LibWebRTCCodecsProxy::initializeEncoder): 51 (WebKit::LibWebRTCCodecsProxy::findEncoder): 52 (WebKit::LibWebRTCCodecsProxy::encodeFrame): 53 (WebKit::LibWebRTCCodecsProxy::setEncodeRates): 54 (WebKit::LibWebRTCCodecsProxy::setSharedVideoFrameSemaphore): 55 (WebKit::LibWebRTCCodecsProxy::setSharedVideoFrameMemory): 56 (WebKit::LibWebRTCCodecsProxy::allowsExitUnderMemoryPressure const): 57 1 58 2022-04-22 Russell Epstein <repstein@apple.com> 2 59 -
branches/safari-613.2.7.1-branch/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.cpp
r287288 r293270 275 275 m_sampleBufferDisplayLayerManager->close(); 276 276 #endif 277 #if PLATFORM(COCOA) && USE(LIBWEBRTC)278 m_libWebRTCCodecsProxy->close();279 #endif280 277 281 278 --gObjectCountForTesting; … … 310 307 }); 311 308 #endif 312 309 #if PLATFORM(COCOA) && USE(LIBWEBRTC) 310 m_libWebRTCCodecsProxy = nullptr; 311 #endif 313 312 gpuProcess().connectionToWebProcessClosed(connection); 314 313 gpuProcess().removeGPUConnectionToWebProcess(*this); // May destroy |this|. -
branches/safari-613.2.7.1-branch/Source/WebKit/GPUProcess/GPUConnectionToWebProcess.h
r287288 r293270 286 286 PAL::SessionID m_sessionID; 287 287 #if PLATFORM(COCOA) && USE(LIBWEBRTC) 288 Ref<LibWebRTCCodecsProxy> m_libWebRTCCodecsProxy;288 IPC::ScopedActiveMessageReceiveQueue<LibWebRTCCodecsProxy> m_libWebRTCCodecsProxy; 289 289 #endif 290 290 #if PLATFORM(COCOA) && ENABLE(MEDIA_STREAM) -
branches/safari-613.2.7.1-branch/Source/WebKit/GPUProcess/webrtc/LibWebRTCCodecsProxy.h
r283036 r293270 32 32 #include "RTCDecoderIdentifier.h" 33 33 #include "RTCEncoderIdentifier.h" 34 #include <wtf/Lock.h> 34 #include <atomic> 35 #include <wtf/ThreadAssertions.h> 35 36 36 37 namespace IPC { … … 52 53 class GPUConnectionToWebProcess; 53 54 54 class LibWebRTCCodecsProxy : public IPC::Connection::ThreadMessageReceiverRefCounted {55 class LibWebRTCCodecsProxy final : public IPC::Connection::ThreadMessageReceiverRefCounted { 55 56 WTF_MAKE_FAST_ALLOCATED; 56 57 public: 57 static Ref<LibWebRTCCodecsProxy> create(GPUConnectionToWebProcess& process) { return adoptRef(*new LibWebRTCCodecsProxy(process)); }58 static Ref<LibWebRTCCodecsProxy> create(GPUConnectionToWebProcess&); 58 59 ~LibWebRTCCodecsProxy(); 59 60 void close(); 61 60 void stopListeningForIPC(Ref<LibWebRTCCodecsProxy>&& refFromConnection); 62 61 bool allowsExitUnderMemoryPressure() const; 63 62 64 63 private: 65 64 explicit LibWebRTCCodecsProxy(GPUConnectionToWebProcess&); 65 void initialize(); 66 auto createDecoderCallback(RTCDecoderIdentifier, bool useRemoteFrames); 67 WorkQueue& workQueue() const { return m_queue; } 66 68 67 69 // IPC::Connection::ThreadMessageReceiver … … 86 88 CFDictionaryRef ioSurfacePixelBufferCreationOptions(IOSurfaceRef); 87 89 88 GPUConnectionToWebProcess& m_gpuConnectionToWebProcess;89 90 mutable Lock m_lock;91 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.92 HashMap<RTCEncoderIdentifier, webrtc::LocalEncoder> m_encoders WTF_GUARDED_BY_LOCK(m_lock); // Only modified on the libWebRTCCodecsQueue but may get accessed from the main thread.93 90 94 91 Ref<WorkQueue> m_queue; 92 HashMap<RTCDecoderIdentifier, webrtc::LocalDecoder> m_decoders WTF_GUARDED_BY_LOCK(workQueue()); 93 HashMap<RTCEncoderIdentifier, webrtc::LocalEncoder> m_encoders WTF_GUARDED_BY_LOCK(workQueue()); 94 std::atomic<bool> m_hasEncodersOrDecoders { false }; 95 95 }; 96 96 -
branches/safari-613.2.7.1-branch/Source/WebKit/GPUProcess/webrtc/LibWebRTCCodecsProxy.mm
r286838 r293270 31 31 #import "GPUConnectionToWebProcess.h" 32 32 #import "GPUProcess.h" 33 #import "IPCTester.h" 33 34 #import "LibWebRTCCodecsMessages.h" 34 35 #import "LibWebRTCCodecsProxyMessages.h" … … 44 45 namespace WebKit { 45 46 46 LibWebRTCCodecsProxy::LibWebRTCCodecsProxy(GPUConnectionToWebProcess& connection)47 : m_gpuConnectionToWebProcess(connection) 48 , m_queue(connection.gpuProcess().libWebRTCCodecsQueue())49 { 50 m_gpuConnectionToWebProcess.connection().addThreadMessageReceiver(Messages::LibWebRTCCodecsProxy::messageReceiverName(), this);51 } 52 53 LibWebRTCCodecsProxy:: ~LibWebRTCCodecsProxy()54 { 55 } 56 57 void LibWebRTCCodecsProxy::dispatchToThread(Function<void()>&& function) 58 { 59 m_queue->dispatch(WTFMove(function)); 60 } 61 62 void LibWebRTCCodecsProxy:: close()63 { 64 m_ gpuConnectionToWebProcess.connection().removeThreadMessageReceiver(Messages::LibWebRTCCodecsProxy::messageReceiverName());65 66 dispatchToThread([this, protectedThis = Ref { *this }] {67 Locker locker { m_lock };47 Ref<LibWebRTCCodecsProxy> LibWebRTCCodecsProxy::create(GPUConnectionToWebProcess& webProcessConnection) 48 { 49 auto instance = adoptRef(*new LibWebRTCCodecsProxy(webProcessConnection)); 50 instance->initialize(); 51 return instance; 52 } 53 54 LibWebRTCCodecsProxy::LibWebRTCCodecsProxy(GPUConnectionToWebProcess& webProcessConnection) 55 : m_connection(webProcessConnection.connection()) 56 , m_queue(webProcessConnection.gpuProcess().libWebRTCCodecsQueue()) 57 , m_resourceOwner(webProcessConnection.webProcessIdentity()) 58 { 59 } 60 61 LibWebRTCCodecsProxy::~LibWebRTCCodecsProxy() = default; 62 63 void LibWebRTCCodecsProxy::stopListeningForIPC(Ref<LibWebRTCCodecsProxy>&& refFromConnection) 64 { 65 m_connection->removeThreadMessageReceiver(Messages::LibWebRTCCodecsProxy::messageReceiverName()); 66 67 dispatchToThread([this, protectedThis = WTFMove(refFromConnection)] { 68 assertIsCurrent(workQueue()); 68 69 auto decoders = WTFMove(m_decoders); 69 70 for (auto decoder : decoders.values()) … … 75 76 } 76 77 77 static Function<void(CVPixelBufferRef pixelBuffer, uint32_t timeStampNs, uint32_t timeStamp)> createDecoderCallback(RTCDecoderIdentifier identifier, GPUConnectionToWebProcess& gpuConnectionToWebProcess) 78 { 79 return [connection = Ref { gpuConnectionToWebProcess.connection() }, resourceOwner = gpuConnectionToWebProcess.webProcessIdentity(), identifier] (CVPixelBufferRef pixelBuffer, uint32_t timeStampNs, uint32_t timeStamp) { 80 if (auto sample = WebCore::RemoteVideoSample::create(pixelBuffer, MediaTime(timeStampNs, 1))) { 81 if (resourceOwner) 82 sample->setOwnershipIdentity(resourceOwner); 83 connection->send(Messages::LibWebRTCCodecs::CompletedDecoding { identifier, timeStamp, *sample }, 0); 84 } 78 void LibWebRTCCodecsProxy::initialize() 79 { 80 m_connection->addThreadMessageReceiver(Messages::LibWebRTCCodecsProxy::messageReceiverName(), this); 81 } 82 83 void LibWebRTCCodecsProxy::dispatchToThread(Function<void()>&& function) 84 { 85 m_queue->dispatch(WTFMove(function)); 86 } 87 88 auto LibWebRTCCodecsProxy::createDecoderCallback(RTCDecoderIdentifier identifier) 89 { 90 return [identifier, connection = m_connection, resourceOwner = m_resourceOwner] (CVPixelBufferRef pixelBuffer, uint32_t timeStampNs, uint32_t timeStamp) mutable { 91 auto sample = WebCore::MediaSampleAVFObjC::createImageSample(pixelBuffer, WebCore::MediaSample::VideoRotation::None, false, MediaTime(timeStampNs, 1), { }); 92 if (!sample) 93 return; 94 if (resourceOwner) 95 sample->setOwnershipIdentity(resourceOwner); 96 connection->send(Messages::LibWebRTCCodecs::CompletedDecoding { identifier, timeStamp, *sample }, 0); 85 97 }; 86 98 } … … 88 100 void LibWebRTCCodecsProxy::createH264Decoder(RTCDecoderIdentifier identifier) 89 101 { 90 ASSERT(!isMainRunLoop());91 Locker locker { m_lock };92 ASSERT (!m_decoders.contains(identifier));93 m_ decoders.add(identifier, webrtc::createLocalH264Decoder(makeBlockPtr(createDecoderCallback(identifier, m_gpuConnectionToWebProcess)).get()));102 assertIsCurrent(workQueue()); 103 auto result = m_decoders.add(identifier, webrtc::createLocalH264Decoder(makeBlockPtr(createDecoderCallback(identifier)).get())); 104 ASSERT_UNUSED(result, result.isNewEntry || isTestingIPC()); 105 m_hasEncodersOrDecoders = true; 94 106 } 95 107 96 108 void LibWebRTCCodecsProxy::createH265Decoder(RTCDecoderIdentifier identifier) 97 109 { 98 ASSERT(!isMainRunLoop());99 Locker locker { m_lock };100 ASSERT (!m_decoders.contains(identifier));101 m_ decoders.add(identifier, webrtc::createLocalH265Decoder(makeBlockPtr(createDecoderCallback(identifier, m_gpuConnectionToWebProcess)).get()));110 assertIsCurrent(workQueue()); 111 auto result = m_decoders.add(identifier, webrtc::createLocalH265Decoder(makeBlockPtr(createDecoderCallback(identifier)).get())); 112 ASSERT_UNUSED(result, result.isNewEntry || isTestingIPC()); 113 m_hasEncodersOrDecoders = true; 102 114 } 103 115 104 116 void LibWebRTCCodecsProxy::createVP9Decoder(RTCDecoderIdentifier identifier) 105 117 { 106 ASSERT(!isMainRunLoop());107 Locker locker { m_lock };108 ASSERT (!m_decoders.contains(identifier));109 m_ decoders.add(identifier, webrtc::createLocalVP9Decoder(makeBlockPtr(createDecoderCallback(identifier, m_gpuConnectionToWebProcess)).get()));118 assertIsCurrent(workQueue()); 119 auto result = m_decoders.add(identifier, webrtc::createLocalVP9Decoder(makeBlockPtr(createDecoderCallback(identifier)).get())); 120 ASSERT_UNUSED(result, result.isNewEntry || isTestingIPC()); 121 m_hasEncodersOrDecoders = true; 110 122 } 111 123 112 124 void LibWebRTCCodecsProxy::releaseDecoder(RTCDecoderIdentifier identifier) 113 125 { 114 ASSERT(!isMainRunLoop());115 Locker locker { m_lock };116 ASSERT(m_decoders.contains(identifier));117 if (auto decoder = m_decoders.take(identifier))118 webrtc::releaseLocalDecoder(decoder);119 }120 121 // For performance reasons, this function accesses m_decoders without locking. This is safe because this function runs on the libWebRTCCodecsQueue 122 // and m_decoders only get modified on this queue. 123 void LibWebRTCCodecsProxy::decodeFrame(RTCDecoderIdentifier identifier, uint32_t timeStamp, const IPC::DataReference& data) WTF_IGNORES_THREAD_SAFETY_ANALYSIS 124 { 125 ASSERT(!isMainRunLoop()); 126 ASSERT(m_decoders.contains(identifier));126 assertIsCurrent(workQueue()); 127 auto decoder = m_decoders.take(identifier); 128 if (!decoder) { 129 ASSERT_IS_TESTING_IPC(); 130 return; 131 } 132 webrtc::releaseLocalDecoder(decoder); 133 m_hasEncodersOrDecoders = !m_encoders.isEmpty() || !m_decoders.isEmpty();} 134 } 135 136 void LibWebRTCCodecsProxy::decodeFrame(RTCDecoderIdentifier identifier, uint32_t timeStamp, const IPC::DataReference& data) 137 { 138 assertIsCurrent(workQueue()); 127 139 auto decoder = m_decoders.get(identifier); 128 if (!decoder) 129 return; 130 140 if (!decoder) { 141 ASSERT_IS_TESTING_IPC(); 142 return; 143 } 131 144 if (webrtc::decodeFrame(decoder, timeStamp, data.data(), data.size())) 132 m_gpuConnectionToWebProcess.connection().send(Messages::LibWebRTCCodecs::FailedDecoding { identifier }, 0); 133 } 134 135 // For performance reasons, this function accesses m_decoders without locking. This is safe because this function runs on the libWebRTCCodecsQueue 136 // and m_decoders only get modified on this queue. 137 void LibWebRTCCodecsProxy::setFrameSize(RTCDecoderIdentifier identifier, uint16_t width, uint16_t height) WTF_IGNORES_THREAD_SAFETY_ANALYSIS 138 { 139 ASSERT(!isMainRunLoop()); 140 ASSERT(m_decoders.contains(identifier)); 145 m_connection->send(Messages::LibWebRTCCodecs::FailedDecoding { identifier }, 0); 146 } 147 148 void LibWebRTCCodecsProxy::setFrameSize(RTCDecoderIdentifier identifier, uint16_t width, uint16_t height) 149 { 150 assertIsCurrent(workQueue()); 141 151 auto decoder = m_decoders.get(identifier); 142 if (!decoder) 143 return; 144 152 if (!decoder) { 153 ASSERT_IS_TESTING_IPC(); 154 return; 155 } 145 156 webrtc::setDecoderFrameSize(decoder, width, height); 146 157 } … … 148 159 void LibWebRTCCodecsProxy::createEncoder(RTCEncoderIdentifier identifier, const String& formatName, const Vector<std::pair<String, String>>& parameters, bool useLowLatency) 149 160 { 150 ASSERT(!isMainRunLoop()); 151 Locker locker { m_lock }; 152 ASSERT(!m_encoders.contains(identifier)); 153 161 assertIsCurrent(workQueue()); 154 162 std::map<std::string, std::string> rtcParameters; 155 163 for (auto& parameter : parameters) 156 164 rtcParameters.emplace(parameter.first.utf8().data(), parameter.second.utf8().data()); 157 165 158 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) {166 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) { 159 167 connection->send(Messages::LibWebRTCCodecs::CompletedEncoding { identifier, IPC::DataReference { buffer, size }, info }, 0); 160 168 }).get()); 161 169 webrtc::setLocalEncoderLowLatency(encoder, useLowLatency); 162 m_encoders.add(identifier, encoder); 170 auto result = m_encoders.add(identifier, Encoder { encoder, nullptr }); 171 ASSERT_UNUSED(result, result.isNewEntry || isTestingIPC()); 172 m_hasEncodersOrDecoders = true; 163 173 } 164 174 165 175 void LibWebRTCCodecsProxy::releaseEncoder(RTCEncoderIdentifier identifier) 166 176 { 167 ASSERT(!isMainRunLoop()); 168 Locker locker { m_lock }; 169 ASSERT(m_encoders.contains(identifier)); 170 if (auto encoder = m_encoders.take(identifier)) 171 webrtc::releaseLocalEncoder(encoder); 172 } 173 174 // For performance reasons, this function accesses m_encoders without locking. This is safe because this function runs on the libWebRTCCodecsQueue 175 // and m_encoders only get modified on this queue. 176 void LibWebRTCCodecsProxy::initializeEncoder(RTCEncoderIdentifier identifier, uint16_t width, uint16_t height, unsigned startBitrate, unsigned maxBitrate, unsigned minBitrate, uint32_t maxFramerate) WTF_IGNORES_THREAD_SAFETY_ANALYSIS 177 { 178 ASSERT(!isMainRunLoop()); 179 ASSERT(m_encoders.contains(identifier)); 180 auto encoder = m_encoders.get(identifier); 181 if (!encoder) 182 return; 183 184 webrtc::initializeLocalEncoder(encoder, width, height, startBitrate, maxBitrate, minBitrate, maxFramerate); 177 assertIsCurrent(workQueue()); 178 auto encoder = m_encoders.take(identifier); 179 if (!encoder.webrtcEncoder) { 180 ASSERT_IS_TESTING_IPC(); 181 return; 182 } 183 webrtc::releaseLocalEncoder(encoder.webrtcEncoder); 184 m_hasEncodersOrDecoders = !m_encoders.isEmpty() || !m_decoders.isEmpty(); 185 } 186 187 void LibWebRTCCodecsProxy::initializeEncoder(RTCEncoderIdentifier identifier, uint16_t width, uint16_t height, unsigned startBitrate, unsigned maxBitrate, unsigned minBitrate, uint32_t maxFramerate) 188 { 189 assertIsCurrent(workQueue()); 190 auto* encoder = findEncoder(identifier); 191 if (!encoder) { 192 ASSERT_IS_TESTING_IPC(); 193 return; 194 } 195 webrtc::initializeLocalEncoder(encoder->webrtcEncoder, width, height, startBitrate, maxBitrate, minBitrate, maxFramerate); 185 196 } 186 197 … … 201 212 } 202 213 203 // For performance reasons, this function accesses m_encoders without locking. This is safe because this function runs on the libWebRTCCodecsQueue 204 // and m_encoders only get modified on this queue. 205 void LibWebRTCCodecsProxy::encodeFrame(RTCEncoderIdentifier identifier, WebCore::RemoteVideoSample&& sample, uint32_t timeStamp, bool shouldEncodeAsKeyFrame) WTF_IGNORES_THREAD_SAFETY_ANALYSIS 206 { 207 ASSERT(!isMainRunLoop()); 214 void LibWebRTCCodecsProxy::encodeFrame(RTCEncoderIdentifier identifier, WebCore::RemoteVideoSample&& sample, uint32_t timeStamp, bool shouldEncodeAsKeyFrame) 215 { 216 assertIsCurrent(workQueue()); 208 217 ASSERT(m_encoders.contains(identifier)); 209 218 auto encoder = m_encoders.get(identifier); … … 221 230 } 222 231 223 // For performance reasons, this function accesses m_encoders without locking. This is safe because this function runs on the libWebRTCCodecsQueue 224 // and m_encoders only get modified on this queue. 225 void LibWebRTCCodecsProxy::setEncodeRates(RTCEncoderIdentifier identifier, uint32_t bitRate, uint32_t frameRate) WTF_IGNORES_THREAD_SAFETY_ANALYSIS 226 { 227 ASSERT(!isMainRunLoop()); 232 void LibWebRTCCodecsProxy::setEncodeRates(RTCEncoderIdentifier identifier, uint32_t bitRate, uint32_t frameRate) 233 { 234 assertIsCurrent(workQueue()); 228 235 auto encoder = m_encoders.get(identifier); 229 236 if (!encoder) … … 235 242 bool LibWebRTCCodecsProxy::allowsExitUnderMemoryPressure() const 236 243 { 237 ASSERT(isMainRunLoop()); 238 Locker locker { m_lock }; 239 return m_encoders.isEmpty() && m_decoders.isEmpty(); 244 assertIsMainRunLoop(); 245 return !m_hasEncodersOrDecoders; 240 246 } 241 247
Note:
See TracChangeset
for help on using the changeset viewer.