diff foosdk/sdk/pfc/threads.h @ 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/pfc/threads.h	Mon Jan 05 02:15:46 2026 -0500
@@ -0,0 +1,117 @@
+#pragma once
+
+#include <functional>
+
+#ifdef _WIN32
+#include <process.h>
+#else
+#include <pthread.h>
+#endif
+namespace pfc {
+	unsigned getOptimalWorkerThreadCount();
+	unsigned getOptimalWorkerThreadCountEx(size_t taskCountLimit);
+
+	//! IMPORTANT: all classes derived from thread must call waitTillDone() in their destructor, to avoid object destruction during a virtual function call!
+	class thread {
+	public:
+#ifdef _WIN32
+        typedef HANDLE handle_t;
+#else
+        typedef pthread_t handle_t;
+#endif
+        // Returns a psuedo-handle meant only for local use, see win32 GetCurrentThread() semantics
+        static handle_t handleToCurrent();
+
+        struct arg_t {
+#ifdef _WIN32
+            int winThreadPriority = 0; // THREAD_PRIORITY_NORMAL
+#endif
+#ifdef __APPLE__
+            // see: pthread_set_qos_class_self_np
+            int appleThreadQOS = 0; // QOS_CLASS_UNSPECIFIED
+            int appleRealtivePriority = 0; // valid only if appleThreadQOS is set
+#endif
+#ifndef _WIN32
+            int nixSchedPolicy = -1; // not set - cannot use 0 because SCHED_OTHER is 0 on Linux
+            sched_param nixSchedParam = {}; // valid only if nixSchedPolicy is set
+#endif
+        };
+
+		static arg_t argDefault();        
+        static arg_t argCurrentThread();
+        static arg_t argBackground();
+        static arg_t argHighPriority();
+        static arg_t argPlayback();
+        static arg_t argUserInitiated();
+#ifdef _WIN32
+        static arg_t argWinPriority(int priority);
+#endif
+#ifdef __APPLE__
+		static arg_t argAppleQOS(int qos);
+#endif
+#ifndef _WIN32
+		static arg_t argNixPriority( int policy, int percent );
+#endif
+
+		//! Critical error handler function, never returns
+		PFC_NORETURN static void couldNotCreateThread();
+
+		thread();
+		~thread() {PFC_ASSERT(!isActive()); waitTillDone();}
+        void start( arg_t const & arg = argCurrentThread() );
+        //! Valid thread object (created and not joined)?
+		bool isActive() const;
+        //! Joins the thread: blocks until complete, releases resources. \n
+        //! After waitTillDone() returns, isActive() becomes false. \n
+		//! No-op if thread not started.
+		void waitTillDone() {close();}
+#ifdef _WIN32
+		void winStart(int priority, DWORD * outThreadID); 
+		HANDLE winThreadHandle() { return m_thread; }
+#else
+		pthread_t posixThreadHandle() { return m_thread; }
+#endif
+#ifdef __APPLE__
+		static void appleStartThreadPrologue();
+#endif
+        
+        static void setCurrentPriority(arg_t const&);
+	protected:
+		virtual void threadProc() {PFC_ASSERT(!"Stub thread entry - should not get here");}
+	private:
+		void close();
+#ifdef _WIN32
+		static unsigned CALLBACK g_entry(void* p_instance);
+#else
+		static void * g_entry( void * arg );
+#endif
+        void entry();
+        
+        handle_t m_thread;
+#ifndef _WIN32
+        bool m_threadValid; // there is no invalid pthread_t, so we keep a separate 'valid' flag
+#endif
+        
+		PFC_CLASS_NOT_COPYABLE_EX(thread)
+	};
+
+	//! Thread class using lambda entrypoint rather than function override
+	class thread2 : public thread {
+	public:
+		~thread2() { waitTillDone(); }
+		void startHere(std::function<void()> e);
+		void startHere(arg_t const& arg, std::function<void()> e);
+		void setEntry(std::function<void()> e);
+	private:
+		void threadProc();
+
+		std::function<void()> m_entryPoint;
+	};
+
+	void splitThread(std::function<void() > f);
+    void splitThread(pfc::thread::arg_t const & arg, std::function<void()> f);
+
+	//! Apple specific; executes the function in a release pool scope. \n
+	//! On non Apple platforms it just invokes the function.
+	void inAutoReleasePool(std::function<void()> f);
+}