diff --git a/libs/ardour/rt_tasklist.cc b/libs/ardour/rt_tasklist.cc index ccdf96e348..18fcad8e3f 100644 --- a/libs/ardour/rt_tasklist.cc +++ b/libs/ardour/rt_tasklist.cc @@ -96,7 +96,7 @@ RTTaskList::reset_thread_list () PBD::fatal << _("Cannot create thread for TaskList!") << " (" << strerror(rv) << ")" << endmsg; /* NOT REACHED */ } - pbd_mach_set_realtime_policy (thread_id, 5. * 1e-5); + pbd_mach_set_realtime_policy (thread_id, 5. * 1e-5, false); _threads.push_back (thread_id); } } diff --git a/libs/backends/coreaudio/coreaudio_backend.cc b/libs/backends/coreaudio/coreaudio_backend.cc index 20aeef9ff6..e95220f1dd 100644 --- a/libs/backends/coreaudio/coreaudio_backend.cc +++ b/libs/backends/coreaudio/coreaudio_backend.cc @@ -339,10 +339,10 @@ CoreAudioBackend::set_buffer_size (uint32_t bs) } _pcmio->set_samples_per_period(bs); if (_run) { - pbd_mach_set_realtime_policy (_main_thread, 1e9 * bs / _samplerate); + pbd_mach_set_realtime_policy (_main_thread, 1e9 * bs / _samplerate, true); } for (std::vector::const_iterator i = _threads.begin (); i != _threads.end (); ++i) { - pbd_mach_set_realtime_policy (*i, 1e9 * bs / _samplerate); + pbd_mach_set_realtime_policy (*i, 1e9 * bs / _samplerate, false); } return 0; } @@ -854,7 +854,7 @@ CoreAudioBackend::create_process_thread (boost::function func) PBD::warning << _("AudioEngine: process thread failed to acquire realtime permissions.") << endmsg; } - if (pbd_mach_set_realtime_policy (thread_id, 1e9 * _samples_per_period / _samplerate)) { + if (pbd_mach_set_realtime_policy (thread_id, 1e9 * _samples_per_period / _samplerate, false)) { PBD::warning << _("AudioEngine: process thread failed to set mach realtime policy.") << endmsg; } @@ -1321,7 +1321,7 @@ CoreAudioBackend::freewheel_thread () AudioEngine::thread_init_callback (this); _midiio->set_enabled(false); reset_midi_parsers (); - pbd_mach_set_realtime_policy (_main_thread, 1e9 * _samples_per_period / _samplerate); + pbd_mach_set_realtime_policy (_main_thread, 1e9 * _samples_per_period / _samplerate, true); } // process port updates first in every cycle. @@ -1388,7 +1388,7 @@ CoreAudioBackend::process_callback (const uint32_t n_samples, const uint64_t hos _reinit_thread_callback = false; _main_thread = pthread_self(); AudioEngine::thread_init_callback (this); - pbd_mach_set_realtime_policy (_main_thread, 1e9 * _samples_per_period / _samplerate); + pbd_mach_set_realtime_policy (_main_thread, 1e9 * _samples_per_period / _samplerate, true); } if (pthread_mutex_trylock (&_process_callback_mutex)) { diff --git a/libs/pbd/pbd/pthread_utils.h b/libs/pbd/pbd/pthread_utils.h index af7094439e..64c8ee551e 100644 --- a/libs/pbd/pbd/pthread_utils.h +++ b/libs/pbd/pbd/pthread_utils.h @@ -80,7 +80,7 @@ LIBPBD_API int pbd_realtime_pthread_create ( LIBPBD_API int pbd_absolute_rt_priority (int policy, int priority); LIBPBD_API int pbd_set_thread_priority (pthread_t, const int policy, int priority); -LIBPBD_API bool pbd_mach_set_realtime_policy (pthread_t thread_id, double period_ns); +LIBPBD_API bool pbd_mach_set_realtime_policy (pthread_t thread_id, double period_ns, bool main); namespace PBD { LIBPBD_API extern void notify_event_loops_about_thread_creation (pthread_t, const std::string&, int requests = 256); diff --git a/libs/pbd/pthread_utils.cc b/libs/pbd/pthread_utils.cc index cdc24499a1..dc948a00e8 100644 --- a/libs/pbd/pthread_utils.cc +++ b/libs/pbd/pthread_utils.cc @@ -339,40 +339,75 @@ pbd_set_thread_priority (pthread_t thread, const int policy, int priority) } bool -pbd_mach_set_realtime_policy (pthread_t thread_id, double period_ns) +pbd_mach_set_realtime_policy (pthread_t thread_id, double period_ns, bool main) { #ifdef __APPLE__ + /* https://opensource.apple.com/source/xnu/xnu-4570.61.1/osfmk/mach/thread_policy.h.auto.html + * https://opensource.apple.com/source/xnu/xnu-4570.61.1/:sposfmk/kern/sched.h.auto.html + */ + kern_return_t res; + + /* Ask for fixed priority */ + thread_extended_policy_data_t tep; + tep.timeshare = false; + + res = thread_policy_set (pthread_mach_thread_np (thread_id), + THREAD_EXTENDED_POLICY, + (thread_policy_t)&tep, + THREAD_EXTENDED_POLICY_COUNT); +#ifndef NDEBUG + printf ("Mach Thread(%p) set timeshare: %d OK: %d\n", thread_id, tep.timeshare, res == KERN_SUCCESS); +#endif + + /* relative value of the computation compared to the other threads in the task. */ + thread_precedence_policy_data_t tpp; + tpp.importance = main ? 63 : 62; // MAXPRI_USER = 63 + + res = thread_policy_set (pthread_mach_thread_np (thread_id), + THREAD_PRECEDENCE_POLICY, + (thread_policy_t)&tpp, + THREAD_PRECEDENCE_POLICY_COUNT); +#ifndef NDEBUG + printf ("Mach Thread(%p) set precedence: %d OK: %d\n", thread_id, tpp.importance, res == KERN_SUCCESS); +#endif + + /* Realtime constraints */ double ticks_per_ns = 1.; mach_timebase_info_data_t timebase; if (KERN_SUCCESS == mach_timebase_info (&timebase)) { ticks_per_ns = timebase.denom / timebase.numer; } - thread_time_constraint_policy_data_t policy; + thread_time_constraint_policy_data_t tcp; #ifndef NDEBUG mach_msg_type_number_t msgt = 4; boolean_t dflt = false; kern_return_t rv = thread_policy_get (pthread_mach_thread_np (thread_id), - THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&policy, &msgt, &dflt); + THREAD_TIME_CONSTRAINT_POLICY, + (thread_policy_t)&tcp, + &msgt, &dflt); - printf ("Mach Thread(%p) get: period=%d comp=%d constraint=%d preemt=%d OK: %d\n", thread_id, policy.period, policy.computation, policy.constraint, policy.preemptible, rv == KERN_SUCCESS); + printf ("Mach Thread(%p) get: period=%d comp=%d constraint=%d preemt=%d OK: %d\n", thread_id, tcp.period, tcp.computation, tcp.constraint, tcp.preemptible, rv == KERN_SUCCESS); #endif mach_timebase_info_data_t timebase_info; mach_timebase_info (&timebase_info); const double period_clk = period_ns * (double)timebase_info.denom / (double)timebase_info.numer; - policy.period = ticks_per_ns * period_clk; - policy.computation = ticks_per_ns * period_clk * .9; - policy.constraint = ticks_per_ns * period_clk * .95; - policy.preemptible = true; - kern_return_t res = thread_policy_set (pthread_mach_thread_np (thread_id), - THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t)&policy, - THREAD_TIME_CONSTRAINT_POLICY_COUNT); + tcp.period = ticks_per_ns * period_clk; + tcp.computation = ticks_per_ns * period_clk * .9; + tcp.constraint = ticks_per_ns * period_clk * .95; + tcp.preemptible = true; + + res = thread_policy_set (pthread_mach_thread_np (thread_id), + THREAD_TIME_CONSTRAINT_POLICY, + (thread_policy_t)&tcp, + THREAD_TIME_CONSTRAINT_POLICY_COUNT); #ifndef NDEBUG - printf ("Mach Thread(%p) set: period=%d comp=%d constraint=%d preemt=%d OK: %d\n", thread_id, policy.period, policy.computation, policy.constraint, policy.preemptible, res == KERN_SUCCESS); + printf ("Mach Thread(%p) set: period=%d comp=%d constraint=%d preemt=%d OK: %d\n", thread_id, tcp.period, tcp.computation, tcp.constraint, tcp.preemptible, res == KERN_SUCCESS); #endif + return res != KERN_SUCCESS; #endif return false; // OK