OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
thread_priority.hpp
1#pragma once
2
3#include <ossia/detail/sleep.hpp>
4#if defined(_WIN32)
5#include <mmsystem.h>
6#include <avrt.h>
7#endif
8
9namespace ossia
10{
11
12#if defined(_WIN32)
13namespace detail
14{
15struct mmcss_api
16{
17 using set_characteristics_t = HANDLE(WINAPI*)(LPCWSTR, LPDWORD);
18 using set_priority_t = BOOL(WINAPI*)(HANDLE, AVRT_PRIORITY);
19 using revert_t = BOOL(WINAPI*)(HANDLE);
20
21 set_characteristics_t set_characteristics{};
22 set_priority_t set_priority{};
23 revert_t revert{};
24
25 mmcss_api() noexcept
26 {
27 if(HMODULE lib = LoadLibraryW(L"avrt.dll"))
28 {
29 set_characteristics = reinterpret_cast<set_characteristics_t>(
30 reinterpret_cast<void*>(GetProcAddress(lib, "AvSetMmThreadCharacteristicsW")));
31 set_priority = reinterpret_cast<set_priority_t>(
32 reinterpret_cast<void*>(GetProcAddress(lib, "AvSetMmThreadPriority")));
33 revert = reinterpret_cast<revert_t>(
34 reinterpret_cast<void*>(GetProcAddress(lib, "AvRevertMmThreadCharacteristics")));
35 }
36 }
37};
38
39inline const mmcss_api& mmcss() noexcept
40{
41 static const mmcss_api api;
42 return api;
43}
44}
45#endif
46
47struct priority_boost_handle
48{
49public:
50 explicit priority_boost_handle(double frequencyHz)
51 {
52#if defined(_WIN32)
53 // Timer resolution already increased in main()
54
55 // MMCSS priority boost
56 DWORD taskIndex = 0;
57 const auto& mmcss = detail::mmcss();
58 if (mmcss.set_characteristics)
59 m_mmcss = mmcss.set_characteristics(L"Pro Audio", &taskIndex);
60 if (m_mmcss && mmcss.set_priority)
61 {
62 mmcss.set_priority(m_mmcss, AVRT_PRIORITY_CRITICAL);
63 }
64#elif defined(__APPLE__)
65 // Set real-time thread policy with time constraint
66 // This tells the scheduler we need periodic execution
67 mach_port_t threadPort = pthread_mach_thread_np(pthread_self());
68
69 // Convert frequency to period in mach absolute time units
70 double periodNs = 1'000'000'000.0 / frequencyHz;
71 uint32_t periodMach = static_cast<uint32_t>(periodNs * detail::g_timebase_info.denom / detail::g_timebase_info.numer);
72
73 thread_time_constraint_policy_data_t policy;
74 policy.period = periodMach; // Nominal period
75 policy.computation = periodMach / 10; // Max computation time (~10% of period)
76 policy.constraint = periodMach / 2; // Must complete within half period
77 policy.preemptible = 1; // Can be preempted
78
79 kern_return_t kr = thread_policy_set(
80 threadPort,
81 THREAD_TIME_CONSTRAINT_POLICY,
82 reinterpret_cast<thread_policy_t>(&policy),
83 THREAD_TIME_CONSTRAINT_POLICY_COUNT
84 );
85
86 m_policy_set = (kr == KERN_SUCCESS);
87
88 if (!m_policy_set)
89 {
90 // Fallback: at least set high QoS
91 pthread_set_qos_class_self_np(QOS_CLASS_USER_INTERACTIVE, 0);
92 }
93#else
94 // Save original scheduling policy
95 pthread_getschedparam(pthread_self(), &m_original_policy, &m_original_param);
96
97 // Try to set SCHED_FIFO
98 struct sched_param param;
99 param.sched_priority = sched_get_priority_max(SCHED_FIFO);
100
101 if (pthread_setschedparam(pthread_self(), SCHED_FIFO, &param) == 0)
102 {
103 m_elevated = true;
104 }
105 else
106 {
107 // Fallback: set highest nice value we can
108 setpriority(PRIO_PROCESS, 0, -20);
109 }
110#endif
111 }
112
113 ~priority_boost_handle()
114 {
115#if defined(_WIN32)
116 if (m_mmcss)
117 {
118 if (const auto& mmcss = detail::mmcss(); mmcss.revert)
119 mmcss.revert(m_mmcss);
120 m_mmcss = nullptr;
121 }
122#elif defined(__APPLE__)
123 if (m_policy_set)
124 {
125 // Revert to default policy
126 mach_port_t threadPort = pthread_mach_thread_np(pthread_self());
127 thread_standard_policy_data_t policy;
128 thread_policy_set(
129 threadPort,
130 THREAD_STANDARD_POLICY,
131 reinterpret_cast<thread_policy_t>(&policy),
132 THREAD_STANDARD_POLICY_COUNT
133 );
134 m_policy_set = false;
135 }
136#else
137 if (m_elevated)
138 {
139 pthread_setschedparam(pthread_self(), m_original_policy, &m_original_param);
140 m_elevated = false;
141 }
142#endif
143 }
144
145private:
146#if defined(_WIN32)
147 HANDLE m_mmcss = nullptr;
148 UINT m_timer_resolution = 1;
149#elif defined(__APPLE__)
150 bool m_policy_set = false;
151#else
152 int m_original_policy = SCHED_OTHER;
153 struct sched_param m_original_param = {};
154 bool m_elevated = false;
155#endif
156};
157
158}
Definition git_info.h:7