Skip to content

Commit 7bcb222

Browse files
committed
Handling WebViewWrapperFuture on operation timeout
This commit conributes to handle how webViewWrapperFuture should exceptionally complete if there happens an edge operation timeout in processOSMessagesUntil method contributes to #1466 and eclipse.platform.ui/#2734
1 parent b3e784d commit 7bcb222

File tree

1 file changed

+49
-18
lines changed
  • bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser

1 file changed

+49
-18
lines changed

bundles/org.eclipse.swt/Eclipse SWT Browser/win32/org/eclipse/swt/browser/Edge.java

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,9 @@ static int callAndWait(long[] ppv, ToIntFunction<IUnknown> callable) {
264264
phr[0] = callable.applyAsInt(completion);
265265
// "completion" callback may be called asynchronously,
266266
// so keep processing next OS message that may call it
267-
processOSMessagesUntil(() -> phr[0] != COM.S_OK || ppv[0] != 0, Display.getCurrent());
267+
processOSMessagesUntil(() -> phr[0] != COM.S_OK || ppv[0] != 0, exception -> {
268+
throw exception;
269+
}, Display.getCurrent());
268270
completion.Release();
269271
return phr[0];
270272
}
@@ -282,7 +284,9 @@ int callAndWait(String[] pstr, ToIntFunction<IUnknown> callable) {
282284
phr[0] = callable.applyAsInt(completion);
283285
// "completion" callback may be called asynchronously,
284286
// so keep processing next OS message that may call it
285-
processOSMessagesUntil(() -> phr[0] != COM.S_OK || pstr[0] != null, browser.getDisplay());
287+
processOSMessagesUntil(() -> phr[0] != COM.S_OK || pstr[0] != null, exception -> {
288+
throw exception;
289+
}, browser.getDisplay());
286290
completion.Release();
287291
return phr[0];
288292
}
@@ -298,29 +302,34 @@ class WebViewWrapper {
298302
void releaseWebViews() {
299303
if(webView != null) {
300304
webView.Release();
305+
webView = null;
301306
}
302307
if(webView_2 != null) {
303308
webView_2.Release();
309+
webView_2 = null;
304310
}
305311
if(webView_10 != null) {
306312
webView_10.Release();
313+
webView_10 = null;
307314
}
308315
if(webView_11 != null) {
309316
webView_11.Release();
317+
webView_11 = null;
310318
}
311319
if(webView_12 != null) {
312320
webView_12.Release();
321+
webView_12 = null;
313322
}
314323
if(webView_13 != null) {
315324
webView_13.Release();
325+
webView_13 = null;
316326
}
317327
}
318328
}
319329

320330
class WebViewProvider {
321-
322331
private CompletableFuture<WebViewWrapper> webViewWrapperFuture = wakeDisplayAfterFuture(new CompletableFuture<>());
323-
private CompletableFuture<Void> lastWebViewTask = webViewWrapperFuture.thenRun(() -> {});;
332+
private CompletableFuture<Void> lastWebViewTask = webViewWrapperFuture.thenRun(() -> {});
324333

325334
ICoreWebView2 initializeWebView(ICoreWebView2Controller controller) {
326335
long[] ppv = new long[1];
@@ -333,7 +342,12 @@ ICoreWebView2 initializeWebView(ICoreWebView2Controller controller) {
333342
webViewWrapper.webView_11 = initializeWebView_11(webView);
334343
webViewWrapper.webView_12 = initializeWebView_12(webView);
335344
webViewWrapper.webView_13 = initializeWebView_13(webView);
336-
webViewWrapperFuture.complete(webViewWrapper);
345+
boolean success = webViewWrapperFuture.complete(webViewWrapper);
346+
// Release the webViews if the webViewWrapperFuture has already timed out and completed exceptionally
347+
if(!success && webViewWrapperFuture.isCompletedExceptionally()) {
348+
webViewWrapper.releaseWebViews();
349+
return null;
350+
}
337351
return webView;
338352
}
339353

@@ -392,13 +406,19 @@ private ICoreWebView2_13 initializeWebView_13(ICoreWebView2 webView) {
392406

393407
private WebViewWrapper getWebViewWrapper(boolean waitForPendingWebviewTasksToFinish) {
394408
if(waitForPendingWebviewTasksToFinish) {
395-
processOSMessagesUntil(lastWebViewTask::isDone, browser.getDisplay());
409+
processOSMessagesUntil(lastWebViewTask::isDone, exception -> {
410+
lastWebViewTask.completeExceptionally(exception);
411+
throw exception;
412+
}, browser.getDisplay());
396413
}
397414
return webViewWrapperFuture.join();
398415
}
399416

400417
private WebViewWrapper getWebViewWrapper() {
401-
processOSMessagesUntil(webViewWrapperFuture::isDone, browser.getDisplay());
418+
processOSMessagesUntil(webViewWrapperFuture::isDone, exception -> {
419+
webViewWrapperFuture.completeExceptionally(exception);
420+
throw exception;
421+
}, browser.getDisplay());
402422
return webViewWrapperFuture.join();
403423
}
404424

@@ -482,8 +502,9 @@ private <T> CompletableFuture<T> wakeDisplayAfterFuture(CompletableFuture<T> fut
482502
* leads to a failure in browser initialization if processed in between the OS
483503
* events for initialization. Thus, this method does not implement an ordinary
484504
* readAndDispatch loop, but waits for an OS event to be processed.
505+
* @throws Throwable
485506
*/
486-
private static void processOSMessagesUntil(Supplier<Boolean> condition, Display display) {
507+
private static void processOSMessagesUntil(Supplier<Boolean> condition, Consumer<SWTException> timeoutHandler, Display display) {
487508
MSG msg = new MSG();
488509
AtomicBoolean timeoutOccurred = new AtomicBoolean();
489510
// The timer call also wakes up the display to avoid being stuck in display.sleep()
@@ -496,10 +517,14 @@ private static void processOSMessagesUntil(Supplier<Boolean> condition, Display
496517
}
497518
}
498519
if (!condition.get()) {
499-
SWT.error(SWT.ERROR_UNSPECIFIED, null, " Waiting for Edge operation to terminate timed out");
520+
timeoutHandler.accept(createTimeOutException());
500521
}
501522
}
502523

524+
private static SWTException createTimeOutException() {
525+
return new SWTException(SWT.ERROR_UNSPECIFIED, "Waiting for Edge operation to terminate timed out");
526+
}
527+
503528
static ICoreWebView2CookieManager getCookieManager() {
504529
WebViewEnvironment environmentWrapper = webViewEnvironments.get(Display.getCurrent());
505530
if (environmentWrapper == null) {
@@ -616,16 +641,9 @@ private void createInstance(int previousAttempts) {
616641
}
617642

618643
private IUnknown createControllerInitializationCallback(int previousAttempts) {
619-
Runnable initializationRollback = () -> {
620-
if (environment2 != null) {
621-
environment2.Release();
622-
environment2 = null;
623-
}
624-
containingEnvironment.instances().remove(this);
625-
};
626644
Runnable initializationAbortion = () -> {
627645
webViewProvider.abortInitialization();
628-
initializationRollback.run();
646+
releaseEnvironment();
629647
};
630648
return newCallback((resultAsLong, pv) -> {
631649
int result = (int) resultAsLong;
@@ -651,7 +669,7 @@ private IUnknown createControllerInitializationCallback(int previousAttempts) {
651669
initializationAbortion.run();
652670
break;
653671
default:
654-
initializationRollback.run();
672+
releaseEnvironment();
655673
if (previousAttempts < MAXIMUM_CREATION_RETRIES) {
656674
System.err.println(String.format("Edge initialization failed, retrying (attempt %d / %d)", previousAttempts + 1, MAXIMUM_CREATION_RETRIES));
657675
createInstance(previousAttempts + 1);
@@ -665,10 +683,23 @@ private IUnknown createControllerInitializationCallback(int previousAttempts) {
665683
});
666684
}
667685

686+
private void releaseEnvironment() {
687+
if (environment2 != null) {
688+
environment2.Release();
689+
environment2 = null;
690+
}
691+
containingEnvironment.instances().remove(this);
692+
}
693+
668694
void setupBrowser(int hr, long pv) {
669695
long[] ppv = new long[] {pv};
670696
controller = new ICoreWebView2Controller(ppv[0]);
671697
final ICoreWebView2 webView = webViewProvider.initializeWebView(controller);
698+
if(webView == null) {
699+
controller.Release();
700+
releaseEnvironment();
701+
return;
702+
}
672703
webView.get_Settings(ppv);
673704
settings = new ICoreWebView2Settings(ppv[0]);
674705

0 commit comments

Comments
 (0)