diff foosdk/sdk/foobar2000/helpers/ThreadUtils.cpp @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/foosdk/sdk/foobar2000/helpers/ThreadUtils.cpp	Mon Jan 05 02:15:46 2026 -0500
@@ -0,0 +1,161 @@
+#include "StdAfx.h"
+
+#include "ThreadUtils.h"
+#include "rethrow.h"
+
+#include <exception>
+
+namespace ThreadUtils {
+	bool CRethrow::exec( std::function<void () > f ) throw() {
+		m_exception = nullptr;
+		bool rv = false;
+		try {
+			f();
+			rv = true;
+		} catch( ... ) {
+			m_exception = std::current_exception();
+		}  
+
+		return rv;
+	}
+
+	void CRethrow::rethrow() const {
+		if (m_exception) std::rethrow_exception(m_exception);
+	}
+}
+#ifdef _WIN32
+
+#include "win32_misc.h"
+
+#ifdef FOOBAR2000_MOBILE
+#include <pfc/pp-winapi.h>
+#endif
+
+
+namespace ThreadUtils {
+	bool WaitAbortable(HANDLE ev, abort_callback & abort, DWORD timeout) {
+		const HANDLE handles[2] = {ev, abort.get_abort_event()};
+		SetLastError(0);
+		const DWORD status = WaitForMultipleObjects(2, handles, FALSE, timeout);
+		switch(status) {
+			case WAIT_TIMEOUT:
+				PFC_ASSERT( timeout != INFINITE );
+				return false;
+			case WAIT_OBJECT_0:
+				return true;
+			case WAIT_OBJECT_0 + 1:
+				throw exception_aborted();
+			case WAIT_FAILED:
+				WIN32_OP_FAIL();
+			default:
+				uBugCheck();
+		}
+	}
+#ifdef FOOBAR2000_DESKTOP_WINDOWS
+	void ProcessPendingMessagesWithDialog(HWND hDialog) {
+		MSG msg = {};
+		while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+			if (!IsDialogMessage(hDialog, &msg)) {
+				DispatchMessage(&msg);
+			}
+		}
+	}
+	void ProcessPendingMessages() {
+		MSG msg = {};
+		while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+			DispatchMessage(&msg);
+		}
+	}
+	void WaitAbortable_MsgLoop(HANDLE ev, abort_callback & abort) {
+		abort.check();
+		const HANDLE handles[2] = {ev, abort.get_abort_event()};
+		MultiWait_MsgLoop(handles, 2);
+		abort.check();
+	
+	}
+	t_size MultiWaitAbortable_MsgLoop2(const HANDLE* ev, t_size evCount, abort_callback& abort) {
+		abort.check();
+		const size_t evCountEx = evCount + 1;
+		HANDLE handles1[16];
+		pfc::array_staticsize_t<HANDLE> handles2;
+		HANDLE* pHandles = handles1;
+		if (evCountEx > 16) {
+			handles2.set_size_discard(evCountEx);
+			pHandles = handles2.get_ptr();
+		}
+		pHandles[0] = abort.get_abort_event();
+		pfc::memcpy_t(pHandles + 1, ev, evCount);
+		DWORD status = MultiWait_MsgLoop(pHandles, (DWORD) evCountEx);
+		abort.check();
+		size_t ret = (size_t)(status - WAIT_OBJECT_0 - 1);
+		PFC_ASSERT(ret < evCount);
+		return ret;
+	}
+
+	t_size MultiWaitAbortable_MsgLoop(const HANDLE * ev, t_size evCount, abort_callback & abort) {
+		// Retval is 1-based!
+		// Originally a bug, now kept for compatibility if someone relies on this
+		// Use MultiWaitAbortable_MsgLoop2() instead
+		return MultiWaitAbortable_MsgLoop2(ev, evCount, abort) + 1;
+	}
+
+	void SleepAbortable_MsgLoop(abort_callback & abort, DWORD timeout) {
+		HANDLE handles[] = { abort.get_abort_event() };
+		MultiWait_MsgLoop(handles, 1, timeout);
+		abort.check();
+	}
+
+	bool WaitAbortable_MsgLoop(HANDLE ev, abort_callback & abort, DWORD timeout) {
+		abort.check();
+		HANDLE handles[2] = { abort.get_abort_event(), ev };
+		DWORD status = MultiWait_MsgLoop(handles, 2, timeout);
+		abort.check();
+		return status != WAIT_TIMEOUT;
+	}
+	
+	DWORD MultiWait_MsgLoop(const HANDLE* ev, DWORD evCount) {
+		for (;; ) {
+			SetLastError(0);
+			const DWORD status = MsgWaitForMultipleObjects((DWORD) evCount, ev, FALSE, INFINITE, QS_ALLINPUT);
+			if (status == WAIT_FAILED) WIN32_OP_FAIL();
+			if (status == WAIT_OBJECT_0 + evCount) {
+				ProcessPendingMessages();
+			} else if ( status >= WAIT_OBJECT_0 && status < WAIT_OBJECT_0 + evCount ) {
+				return status;
+			} else {
+				uBugCheck();
+			}
+		}
+	}
+
+	DWORD MultiWait_MsgLoop(const HANDLE* ev, DWORD evCount, DWORD timeout) {
+		if (timeout == INFINITE) return MultiWait_MsgLoop(ev, evCount);
+		const DWORD entry = GetTickCount();
+		DWORD now = entry;
+		for (;;) {
+			const DWORD done = now - entry;
+			if (done >= timeout) return WAIT_TIMEOUT;
+			SetLastError(0);
+			const DWORD status = MsgWaitForMultipleObjects((DWORD)evCount, ev, FALSE, timeout - done, QS_ALLINPUT);
+			if (status == WAIT_FAILED) WIN32_OP_FAIL();
+			if (status == WAIT_OBJECT_0 + evCount) {
+				ProcessPendingMessages();
+			} else if (status == WAIT_TIMEOUT || (status >= WAIT_OBJECT_0 && status < WAIT_OBJECT_0 + evCount) ) {
+				return status;
+			} else {
+				uBugCheck();
+			}
+			now = GetTickCount();
+		}
+	}
+
+	bool pfcWaitMsgLoop(HANDLE ev, double timeout) {
+		DWORD ms = pfc::event::g_calculate_wait_time(timeout);
+		DWORD status = MultiWait_MsgLoop(&ev, 1, ms);
+		return status == WAIT_OBJECT_0;
+	}
+
+#endif // FOOBAR2000_DESKTOP_WINDOWS
+
+}
+#endif
\ No newline at end of file