Skip to content

Conversation

cdumez
Copy link
Contributor

@cdumez cdumez commented Mar 4, 2024

e604d7c

PDFPlugin hangs in deallocation when data load contends with waiting for thread completion
https://bugs.webkit.org/show_bug.cgi?id=246454
rdar://101147811

Reviewed by Tim Horton.

When `PDFPlugin::teardown()` would get called (on the main thread), it would
wait for the PDF thread to complete. However, if loading is still going on,
the PDF thread might be blocked on `dataSemaphore.wait()` in
PDFIncrementalLoader::dataProviderGetBytesAtPosition(). The `dataSemaphore`
is supposed to get signaled on a task dispatched to the main thread but this
task won't run if the main thread is blocked on waiting for the thread to
exit.

To address the issue, PDFIncrementalLoader::clear() now signals the
pending dataSemaphores before waiting for the thread to exit and sets a
flag indicating we want the thread to exit. This flag is then checked
on the PDF thread to make sure we don't queue additional work / semaphores.

* LayoutTests/compositing/plugins/pdf/pdf-plugin-hang-during-destruction-expected.txt: Added.
* LayoutTests/compositing/plugins/pdf/pdf-plugin-hang-during-destruction.html: Added.
I took the test from Erica Li's earlier PR that got reverted.

* Source/WebKit/WebProcess/Plugins/PDF/PDFIncrementalLoader.h:
(WebKit::PDFIncrementalLoader::SemaphoreWrapper::create):
(WebKit::PDFIncrementalLoader::SemaphoreWrapper::wait):
(WebKit::PDFIncrementalLoader::SemaphoreWrapper::signal):
(WebKit::PDFIncrementalLoader::WTF_GUARDED_BY_LOCK):
* Source/WebKit/WebProcess/Plugins/PDF/PDFIncrementalLoader.mm:
(WebKit::PDFIncrementalLoader::clear):
(WebKit::PDFIncrementalLoader::dataProviderGetBytesAtPosition):
(WebKit::PDFIncrementalLoader::dataProviderGetByteRanges):
(WebKit::PDFIncrementalLoader::threadEntry):

Canonical link: https://commits.webkit.org/275707@main

5ffcd92

Misc iOS, tvOS & watchOS macOS Linux Windows
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ✅ 🛠 wincairo
✅ 🛠 ios-sim ✅ 🛠 mac-AS-debug ✅ 🧪 wpe-wk2
✅ 🧪 webkitperl ✅ 🧪 ios-wk2 ✅ 🧪 api-mac ✅ 🧪 api-wpe
✅ 🧪 ios-wk2-wpt ✅ 🧪 mac-wk1 ✅ 🛠 wpe-skia
✅ 🧪 api-ios ✅ 🧪 mac-wk2 ✅ 🛠 gtk
✅ 🛠 tv ✅ 🧪 mac-AS-debug-wk2 ✅ 🧪 gtk-wk2
✅ 🛠 tv-sim ✅ 🧪 mac-wk2-stress ❌ 🧪 api-gtk
✅ 🛠 🧪 merge ✅ 🛠 watch
✅ 🛠 watch-sim

@cdumez cdumez self-assigned this Mar 4, 2024
@cdumez cdumez added the PDF For bugs in WebKit's built-in PDF support. label Mar 4, 2024
@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Mar 4, 2024
@cdumez cdumez removed the merging-blocked Applied to prevent a change from being merged label Mar 4, 2024
@cdumez cdumez force-pushed the 246454_PDFPlugin_hang branch from 93c2661 to 6ac3495 Compare March 4, 2024 22:08
@webkit-ews-buildbot webkit-ews-buildbot added the merging-blocked Applied to prevent a change from being merged label Mar 5, 2024
@cdumez cdumez removed the merging-blocked Applied to prevent a change from being merged label Mar 5, 2024
@cdumez cdumez force-pushed the 246454_PDFPlugin_hang branch from 6ac3495 to f9f5332 Compare March 5, 2024 02:52
@cdumez cdumez marked this pull request as ready for review March 5, 2024 04:17
@cdumez cdumez requested review from smfr, hortont424 and beidson March 5, 2024 04:17
for (size_t i = 0; i < count; ++i) {
protectedLoader->getResourceBytesAtPosition(ranges[i].length, ranges[i].location, [i, &dataResults, &dataSemaphore](const uint8_t* bytes, size_t bytesCount) {
protectedLoader->getResourceBytesAtPosition(ranges[i].length, ranges[i].location, [i, &dataResults, callbackAggregator](const uint8_t* bytes, size_t bytesCount) {
Copy link
Contributor

@lericaa lericaa Mar 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔 not sure how callbackAggregator works but will it get called for each loop? if that is the case, we just wait one time, and it is a BinarySemaphore. (i was quite hesitate if we should also address for this callback)

Copy link
Contributor Author

@cdumez cdumez Mar 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

callbackAggregator calls its lambda on destruction. Since I capture it by value in each lambda inside the loop, we will only signal the semaphore ONCE, when all getResourceBytesAtPosition() calls have completed. As a result, we only need a single semaphore / a single wait(). This simplifies the code.

@cdumez cdumez force-pushed the 246454_PDFPlugin_hang branch 2 times, most recently from 506a859 to 5ffcd92 Compare March 5, 2024 05:44
@cdumez cdumez added the merge-queue Applied to send a pull request to merge-queue label Mar 5, 2024
…for thread completion

https://bugs.webkit.org/show_bug.cgi?id=246454
rdar://101147811

Reviewed by Tim Horton.

When `PDFPlugin::teardown()` would get called (on the main thread), it would
wait for the PDF thread to complete. However, if loading is still going on,
the PDF thread might be blocked on `dataSemaphore.wait()` in
PDFIncrementalLoader::dataProviderGetBytesAtPosition(). The `dataSemaphore`
is supposed to get signaled on a task dispatched to the main thread but this
task won't run if the main thread is blocked on waiting for the thread to
exit.

To address the issue, PDFIncrementalLoader::clear() now signals the
pending dataSemaphores before waiting for the thread to exit and sets a
flag indicating we want the thread to exit. This flag is then checked
on the PDF thread to make sure we don't queue additional work / semaphores.

* LayoutTests/compositing/plugins/pdf/pdf-plugin-hang-during-destruction-expected.txt: Added.
* LayoutTests/compositing/plugins/pdf/pdf-plugin-hang-during-destruction.html: Added.
I took the test from Erica Li's earlier PR that got reverted.

* Source/WebKit/WebProcess/Plugins/PDF/PDFIncrementalLoader.h:
(WebKit::PDFIncrementalLoader::SemaphoreWrapper::create):
(WebKit::PDFIncrementalLoader::SemaphoreWrapper::wait):
(WebKit::PDFIncrementalLoader::SemaphoreWrapper::signal):
(WebKit::PDFIncrementalLoader::WTF_GUARDED_BY_LOCK):
* Source/WebKit/WebProcess/Plugins/PDF/PDFIncrementalLoader.mm:
(WebKit::PDFIncrementalLoader::clear):
(WebKit::PDFIncrementalLoader::dataProviderGetBytesAtPosition):
(WebKit::PDFIncrementalLoader::dataProviderGetByteRanges):
(WebKit::PDFIncrementalLoader::threadEntry):

Canonical link: https://commits.webkit.org/275707@main
@webkit-commit-queue
Copy link
Collaborator

Committed 275707@main (e604d7c): https://commits.webkit.org/275707@main

Reviewed commits have been landed. Closing PR #25448 and removing active labels.

@webkit-commit-queue webkit-commit-queue merged commit e604d7c into WebKit:main Mar 5, 2024
@webkit-commit-queue webkit-commit-queue removed the merge-queue Applied to send a pull request to merge-queue label Mar 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PDF For bugs in WebKit's built-in PDF support.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants