Skip to content

Commit 5192586

Browse files
committed
WIP: Edge Browser Scheduled Job timeout
1 parent 422f742 commit 5192586

File tree

1 file changed

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

1 file changed

+70
-20
lines changed

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

Lines changed: 70 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ static int callAndWait(long[] ppv, ToIntFunction<IUnknown> callable) {
263263
phr[0] = callable.applyAsInt(completion);
264264
// "completion" callback may be called asynchronously,
265265
// so keep processing next OS message that may call it
266-
processOSMessagesUntil(() -> phr[0] != COM.S_OK || ppv[0] != 0, Display.getCurrent());
266+
processOSMessagesUntil(() -> phr[0] != COM.S_OK || ppv[0] != 0, Optional.empty(), Display.getCurrent());
267267
completion.Release();
268268
return phr[0];
269269
}
@@ -281,7 +281,7 @@ int callAndWait(String[] pstr, ToIntFunction<IUnknown> callable) {
281281
phr[0] = callable.applyAsInt(completion);
282282
// "completion" callback may be called asynchronously,
283283
// so keep processing next OS message that may call it
284-
processOSMessagesUntil(() -> phr[0] != COM.S_OK || pstr[0] != null, browser.getDisplay());
284+
processOSMessagesUntil(() -> phr[0] != COM.S_OK || pstr[0] != null, Optional.empty(), browser.getDisplay());
285285
completion.Release();
286286
return phr[0];
287287
}
@@ -293,12 +293,32 @@ class WebViewWrapper {
293293
private ICoreWebView2_11 webView_11;
294294
private ICoreWebView2_12 webView_12;
295295
private ICoreWebView2_13 webView_13;
296+
297+
void releaseWebViews() {
298+
if(webView != null) {
299+
webView.Release();
300+
}
301+
if(webView_2 != null) {
302+
webView_2.Release();
303+
}
304+
if(webView_10 != null) {
305+
webView_10.Release();
306+
}
307+
if(webView_11 != null) {
308+
webView_11.Release();
309+
}
310+
if(webView_12 != null) {
311+
webView_12.Release();
312+
}
313+
if(webView_13 != null) {
314+
webView_13.Release();
315+
}
316+
}
296317
}
297318

298319
class WebViewProvider {
299-
300320
private CompletableFuture<WebViewWrapper> webViewWrapperFuture = wakeDisplayAfterFuture(new CompletableFuture<>());
301-
private CompletableFuture<Void> lastWebViewTask = webViewWrapperFuture.thenRun(() -> {});;
321+
private CompletableFuture<Void> lastWebViewTask = webViewWrapperFuture.thenRun(() -> {});
302322

303323
ICoreWebView2 initializeWebView(ICoreWebView2Controller controller) {
304324
long[] ppv = new long[1];
@@ -310,15 +330,19 @@ ICoreWebView2 initializeWebView(ICoreWebView2Controller controller) {
310330
webViewWrapper.webView_10 = initializeWebView_10(webView);
311331
webViewWrapper.webView_11 = initializeWebView_11(webView);
312332
webViewWrapper.webView_12 = initializeWebView_12(webView);
313-
webViewWrapper.webView_13 = initializeWebView_13(webView);
314-
webViewWrapperFuture.complete(webViewWrapper);
333+
webViewWrapper.webView_13= initializeWebView_13(webView);
334+
boolean success = webViewWrapperFuture.complete(webViewWrapper);
335+
// Release the webViews if the webViewWrapperFuture has already timed out and completed exceptionally
336+
if(!success && webViewWrapperFuture.isCompletedExceptionally()) {
337+
webViewWrapper.releaseWebViews();
338+
return null;
339+
}
315340
return webView;
316341
}
317342

318343
private void abortInitialization() {
319344
webViewWrapperFuture.cancel(true);
320345
}
321-
322346
private ICoreWebView2_2 initializeWebView_2(ICoreWebView2 webView) {
323347
long[] ppv = new long[1];
324348
int hr = webView.QueryInterface(COM.IID_ICoreWebView2_2, ppv);
@@ -366,13 +390,18 @@ private ICoreWebView2_13 initializeWebView_13(ICoreWebView2 webView) {
366390

367391
private WebViewWrapper getWebViewWrapper(boolean waitForPendingWebviewTasksToFinish) {
368392
if(waitForPendingWebviewTasksToFinish) {
369-
processOSMessagesUntil(lastWebViewTask::isDone, browser.getDisplay());
393+
processOSMessagesUntil(lastWebViewTask::isDone, Optional.empty(), browser.getDisplay());
370394
}
371395
return webViewWrapperFuture.join();
372396
}
373397

398+
void releaseWebView() {
399+
processOSMessagesUntil(webViewWrapperFuture::isDone, Optional.of(() -> webViewWrapperFuture.completeExceptionally(createTimeOutException())), browser.getDisplay());
400+
webViewWrapperFuture.join().releaseWebViews();
401+
}
402+
374403
private WebViewWrapper getWebViewWrapper() {
375-
processOSMessagesUntil(webViewWrapperFuture::isDone, browser.getDisplay());
404+
processOSMessagesUntil(webViewWrapperFuture::isDone, Optional.of(() -> webViewWrapperFuture.completeExceptionally(createTimeOutException())), browser.getDisplay());
376405
return webViewWrapperFuture.join();
377406
}
378407

@@ -457,7 +486,7 @@ private <T> CompletableFuture<T> wakeDisplayAfterFuture(CompletableFuture<T> fut
457486
* events for initialization. Thus, this method does not implement an ordinary
458487
* readAndDispatch loop, but waits for an OS event to be processed.
459488
*/
460-
private static void processOSMessagesUntil(Supplier<Boolean> condition, Display display) {
489+
private static void processOSMessagesUntil(Supplier<Boolean> condition, Optional<Runnable> timeoutHandler, Display display) {
461490
MSG msg = new MSG();
462491
AtomicBoolean timeoutOccurred = new AtomicBoolean();
463492
// The timer call also wakes up the display to avoid being stuck in display.sleep()
@@ -470,10 +499,15 @@ private static void processOSMessagesUntil(Supplier<Boolean> condition, Display
470499
}
471500
}
472501
if (!condition.get()) {
502+
timeoutHandler.ifPresent(handler -> handler.run());
473503
SWT.error(SWT.ERROR_UNSPECIFIED, null, " Waiting for Edge operation to terminate timed out");
474504
}
475505
}
476506

507+
private static SWTException createTimeOutException() {
508+
return new SWTException(SWT.ERROR_UNSPECIFIED, " Waiting for Edge operation to terminate timed out");
509+
}
510+
477511
static ICoreWebView2CookieManager getCookieManager() {
478512
WebViewEnvironment environmentWrapper = webViewEnvironments.get(Display.getCurrent());
479513
if (environmentWrapper == null) {
@@ -503,6 +537,10 @@ void checkDeadlock() {
503537
}
504538
}
505539

540+
void errorTimedOut(Throwable throwable) {
541+
SWT.error(SWT.ERROR_UNSPECIFIED, throwable, "Edge Browser initialization timed out");
542+
}
543+
506544
WebViewEnvironment createEnvironment() {
507545
Display display = Display.getCurrent();
508546
WebViewEnvironment existingEnvironment = webViewEnvironments.get(display);
@@ -609,12 +647,16 @@ private IUnknown createControllerInitializationCallback(int previousAttempts) {
609647
if (result == OS.HRESULT_FROM_WIN32(OS.ERROR_INVALID_STATE)) {
610648
initializationAbortion.run();
611649
SWT.error(SWT.ERROR_INVALID_ARGUMENT, null,
612-
" Edge instance with same data folder but different environment options already exists");
650+
"Edge Initialization Timed Out");
613651
}
614652
switch ((int) result) {
615653
case COM.S_OK:
616654
new IUnknown(pv).AddRef();
617-
setupBrowser((int) result, pv);
655+
boolean success = setupBrowser((int) result, pv);
656+
if(!success) {
657+
rollbackInitialization();
658+
errorTimedOut(null);
659+
}
618660
break;
619661
case COM.E_WRONG_THREAD:
620662
initializationAbortion.run();
@@ -624,7 +666,7 @@ private IUnknown createControllerInitializationCallback(int previousAttempts) {
624666
initializationAbortion.run();
625667
break;
626668
default:
627-
initializationRollback.run();
669+
rollbackInitialization();
628670
if (previousAttempts < MAXIMUM_CREATION_RETRIES) {
629671
System.err.println(String.format("Edge initialization failed, retrying (attempt %d / %d)", previousAttempts + 1, MAXIMUM_CREATION_RETRIES));
630672
createInstance(previousAttempts + 1);
@@ -638,10 +680,22 @@ private IUnknown createControllerInitializationCallback(int previousAttempts) {
638680
});
639681
}
640682

641-
void setupBrowser(int hr, long pv) {
683+
private void rollbackInitialization() {
684+
webViewProvider.abortInitialization();
685+
if (environment2 != null) {
686+
environment2.Release();
687+
environment2 = null;
688+
}
689+
containingEnvironment.instances().remove(this);
690+
}
691+
692+
boolean setupBrowser(int hr, long pv) {
642693
long[] ppv = new long[] {pv};
643694
controller = new ICoreWebView2Controller(ppv[0]);
644695
final ICoreWebView2 webView = webViewProvider.initializeWebView(controller);
696+
if(webView == null) {
697+
return false;
698+
}
645699
webView.get_Settings(ppv);
646700
settings = new ICoreWebView2Settings(ppv[0]);
647701

@@ -741,19 +795,15 @@ void setupBrowser(int hr, long pv) {
741795
if (browser.isFocusControl()) {
742796
browserFocusIn(new Event());
743797
}
798+
return true;
744799
}
745800

746801
void browserDispose(Event event) {
747802
containingEnvironment.instances.remove(this);
748803
webViewProvider.scheduleWebViewTask(() -> {
749-
webViewProvider.getWebView(false).Release();
804+
webViewProvider.releaseWebView();
750805
if (environment2 != null) environment2.Release();
751806
if (settings != null) settings.Release();
752-
if (webViewProvider.isWebView_2Available()) webViewProvider.getWebView_2(false).Release();
753-
if (webViewProvider.isWebView_10Available()) webViewProvider.getWebView_10(false).Release();
754-
if (webViewProvider.isWebView_11Available()) webViewProvider.getWebView_11(false).Release();
755-
if (webViewProvider.isWebView_12Available()) webViewProvider.getWebView_12(false).Release();
756-
if (webViewProvider.isWebView_13Available()) webViewProvider.getWebView_13(false).Release();
757807
if(controller != null) {
758808
// Bug in WebView2. Closing the controller from an event handler results
759809
// in a crash. The fix is to delay the closure with asyncExec.

0 commit comments

Comments
 (0)