Skip to content

Commit a919984

Browse files
committed
Let Display#sleep() react to thread interruption
Fix #3059
1 parent 05d3f5c commit a919984

File tree

3 files changed

+51
-4
lines changed

3 files changed

+51
-4
lines changed

bundles/org.eclipse.swt/Eclipse SWT/cocoa/org/eclipse/swt/widgets/Display.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5231,13 +5231,19 @@ public boolean sleep () {
52315231
try {
52325232
addPool();
52335233
allowTimers = runAsyncMessages = false;
5234-
NSRunLoop.currentRunLoop().runMode(OS.NSDefaultRunLoopMode, NSDate.distantFuture());
5234+
/*
5235+
* Use a timeout-based approach to allow checking for thread interruption.
5236+
* Sleep for a maximum of 50 milliseconds at a time, similar to GTK.
5237+
*/
5238+
do {
5239+
NSRunLoop.currentRunLoop().runMode(OS.NSDefaultRunLoopMode, NSDate.dateWithTimeIntervalSinceNow(0.05));
5240+
} while (synchronizer.isMessagesEmpty() && !thread.isInterrupted());
52355241
allowTimers = runAsyncMessages = true;
52365242
} finally {
52375243
removePool();
52385244
}
52395245
sendPostExternalEventDispatchEvent ();
5240-
return true;
5246+
return !thread.isInterrupted();
52415247
}
52425248

52435249
int sourceProc (int info) {

bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/Display.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5633,11 +5633,11 @@ public boolean sleep () {
56335633
OS.g_main_context_check (context, max_priority [0], fds, nfds);
56345634
OS.g_main_context_release (context);
56355635
}
5636-
} while (!result && synchronizer.isMessagesEmpty() && !wake);
5636+
} while (!result && synchronizer.isMessagesEmpty() && !wake && !thread.isInterrupted());
56375637
wake = false;
56385638
if (!GTK.GTK4) GDK.gdk_threads_enter ();
56395639
sendPostExternalEventDispatchEvent ();
5640-
return true;
5640+
return !thread.isInterrupted();
56415641
}
56425642

56435643
/**

tests/org.eclipse.swt.tests/JUnit Tests/org/eclipse/swt/tests/junit/Test_org_eclipse_swt_widgets_Display.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,6 +1407,47 @@ public void run() {
14071407
}
14081408
}
14091409

1410+
@Test
1411+
@DisabledOnOs(value = org.junit.jupiter.api.condition.OS.WINDOWS, disabledReason = "Windows uses WaitMessage() which does not support timeout-based interruption checking")
1412+
public void test_sleep_respondToInterrupt() {
1413+
final Display display = new Display();
1414+
Shell shell = new Shell(display);
1415+
try {
1416+
shell.open();
1417+
Thread uiThread = Thread.currentThread();
1418+
1419+
// Start a thread that will interrupt the UI thread after 1 second
1420+
Thread interrupter = new Thread(() -> {
1421+
try {
1422+
Thread.sleep(1000);
1423+
uiThread.interrupt();
1424+
} catch (InterruptedException e) {
1425+
// Ignore
1426+
}
1427+
});
1428+
interrupter.start();
1429+
1430+
// Event loop with timeout to prevent hanging if sleep() never responds to interrupt
1431+
long deadline = System.currentTimeMillis() + 5000;
1432+
while (!shell.isDisposed() && System.currentTimeMillis() < deadline) {
1433+
if (!display.readAndDispatch()) {
1434+
boolean hasMoreWork = display.sleep();
1435+
// When interrupted, sleep() returns false and interrupt flag is preserved
1436+
if (!hasMoreWork && uiThread.isInterrupted()) {
1437+
// Success! Clean up and return
1438+
Thread.interrupted(); // clear flag
1439+
return;
1440+
}
1441+
}
1442+
}
1443+
// If we get here, the test failed
1444+
fail("sleep() did not respond to thread interruption within timeout");
1445+
} finally {
1446+
shell.dispose();
1447+
display.dispose();
1448+
}
1449+
}
1450+
14101451
@Test
14111452
public void test_syncExecLjava_lang_Runnable() {
14121453
final Display display = new Display();

0 commit comments

Comments
 (0)