Skip to content

Conversation

@laeubi
Copy link
Contributor

@laeubi laeubi commented Feb 5, 2026

Fix #3059

I did not found a good way on Windows (@HeikoKlare ?) and would like to get feedback on the MacOS part, maybe @akurtakov / @jonahgraham can take a peek on the gtk side?

@laeubi laeubi force-pushed the add_interupt_support_to_sleep branch from 1d16fbe to a919984 Compare February 5, 2026 10:46
@HeikoKlare
Copy link
Contributor

I did not find any OS API method that allows to wait for a message until a timeout occurs instead of the inifinitely blocking to OS.WaitMessage().
Maybe something like this replacing the OS.WaitMessage() call in Display.sleep()could work (just as a conceptual idea, not a clean solution):

	boolean messageReceived = false;
	while (!messageReceived && !thread.isInterrupted()) {
		messageReceived = OS.PeekMessage (msg, 0, 0, 0, OS.PM_NOREMOVE);
		try {
			Thread.sleep(20);
		} catch (InterruptedException e) {
			thread.interrupt();
			break;
		}
	}

At least the test locally passes with it.

@laeubi
Copy link
Contributor Author

laeubi commented Feb 5, 2026

just as a conceptual idea, not a clean solution

Thanks for looking into it, the problem is that it will immediately return but always with 20ms delay (what might be too much), I think we can't do any better then on windows for the moment.

@jonahgraham
Copy link
Contributor

On win32 I think you can leave in waitmessage, but always queue a 50ms timer so that you never wait more than 50ms. I don't think it is particularly trivial to do that though as ideally you want the sleep method to handle that particular timer going off locally rather than waiting for the main event loop to handle it.

The gtk side looks good to me on code inspection, but I don't know the implications of changing return value, for example in cases where there are two conditions that caused loop to exit, should it still return true. I don't see any real uses of the sleep return value so far in the code base, so not enough of an issue for me to want to spend more time on it. I guess its too bad we can't throw InterruptedException as that would be a very disruptive API change.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 5, 2026

Test Results (win32)

   34 files  ±0     34 suites  ±0   4m 48s ⏱️ +2s
4 641 tests +1  4 567 ✅ ±0  74 💤 +1  0 ❌ ±0 
  170 runs  ±0    167 ✅ ±0   3 💤 ±0  0 ❌ ±0 

Results for commit a919984. ± Comparison against base commit 05d3f5c.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 5, 2026

Test Results (linux)

   88 files  +30     88 suites  +30   14m 32s ⏱️ + 4m 9s
4 567 tests +41  4 347 ✅ +33  220 💤 +8  0 ❌ ±0 
  211 runs  +71    208 ✅ +70    3 💤 +1  0 ❌ ±0 

Results for commit a919984. ± Comparison against base commit 05d3f5c.

@HeikoKlare
Copy link
Contributor

On win32 I think you can leave in waitmessage, but always queue a 50ms timer so that you never wait more than 50ms. I don't think it is particularly trivial to do that though as ideally you want the sleep method to handle that particular timer going off locally rather than waiting for the main event loop to handle it.

That's a nice idea but you would indeed need to process the timer event inside the sleep() method.

I shortly experimented with a simple timer and a timer callback and both of them do not seem to be processed by the event queue afterwards if the timer is killed after it elapsed (and thus made OS.WaitMessage() return). But I do not find anything in the Windows documentation that guarantees this behavior.

long wakeupId = OS.SetTimer(0, 0, 50, 0);
boolean result = OS.WaitMessage();
OS.KillTimer(0, wakeupId);
long timer = WakeupMessage.sendAfter(50);
boolean result = OS.WaitMessage();
OS.KillTimer(0, timer);

...

private static class WakeupMessage  {
	private final Callback osCallback;

	private WakeupMessage() {
		// Has to have TIMERPROC signature, see https://learn.microsoft.com/en-us/windows/win32/api/winuser/nc-winuser-timerproc
		osCallback = new Callback(this, "run", void.class, new Type[] { int.class, int.class, int.class, int.class} );
	}

	@SuppressWarnings("unused") // Executed as callback method referenced by signature description
	public void run(int hwnd, int msg , int idEvent, int dwTime) {
		OS.KillTimer(hwnd, idEvent);
		System.out.println("lalala");
		osCallback.dispose();
	}

	static long sendAfter(int millis) {
		try {
			WakeupMessage fakeMessage = new WakeupMessage();
			return OS.SetTimer(0, 0, millis, fakeMessage.osCallback.getAddress());
		} catch  (SWTError error) {
		}
		return 0;
	}
}

I now found that is the OS method MsgWaitForMultipleObjectsEx that is proposed when wanting to have a timeout while waiting for messages to arrive. However, there are several configuration options for that method via the parameters of which I would not be immediately sure how to use them.

@laeubi
Copy link
Contributor Author

laeubi commented Feb 6, 2026

I just wanted to mention that I don't want to overcomplicate the matter here and if its not working on windows it is fine for me
The same applies to the return value, I have never seen any use of that and it always returns true unless a mysterious "config change" in gtk.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sleep() does not react to thread interruption

3 participants