13
0

Use dedicated thread to start export timespans #9798

This addresses an issue with creating a one-shot thread
directly from the realtime callback, which can be problematic
on Windows.
This commit is contained in:
Robin Gareus 2024-09-27 06:00:15 +02:00
parent d8e4e7b259
commit 3751d20ce9
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
2 changed files with 65 additions and 20 deletions

View File

@ -146,7 +146,13 @@ class LIBARDOUR_API ExportHandler : public ExportElementFactory, public sigc::tr
/* Timespan management */
static void* start_timespan_bg (void*);
void timespan_thread_wakeup ();
static void* _timespan_thread_run (void*);
pthread_t _timespan_thread;
std::atomic<int> _timespan_thread_active;
pthread_mutex_t _timespan_mutex;
pthread_cond_t _timespan_cond;
int start_timespan ();
int process_timespan (samplecnt_t samples);

View File

@ -25,6 +25,7 @@
#include "pbd/gstdio_compat.h"
#include <glibmm.h>
#include <glibmm/convert.h>
#include <pthread.h>
#include "pbd/convert.h"
@ -121,6 +122,12 @@ ExportHandler::ExportHandler (Session & session)
, cue_tracknum (0)
, cue_indexnum (0)
{
pthread_mutex_init (&_timespan_mutex, 0);
pthread_cond_init (&_timespan_cond, 0);
_timespan_thread_active.store (1);
if (pthread_create (&_timespan_thread, NULL, _timespan_thread_run, this)) {
_timespan_thread_active.store (0);
}
}
ExportHandler::~ExportHandler ()
@ -130,6 +137,56 @@ ExportHandler::~ExportHandler ()
session.surround_master ()->surround_return ()->finalize_export ();
}
graph_builder->cleanup (export_status->aborted () );
pthread_mutex_lock (&_timespan_mutex);
_timespan_thread_active.store (0);
pthread_cond_signal (&_timespan_cond);
pthread_mutex_unlock (&_timespan_mutex);
void *status;
pthread_join (_timespan_thread, &status);
pthread_cond_destroy (&_timespan_cond);
pthread_mutex_destroy (&_timespan_mutex);
}
void*
ExportHandler::_timespan_thread_run (void* me)
{
char name[64];
snprintf (name, 64, "Export-TS-%p", (void*)DEBUG_THREAD_SELF);
pthread_set_name (name);
ExportHandler* self = static_cast<ExportHandler*> (me);
SessionEvent::create_per_thread_pool (name, 512);
PBD::notify_event_loops_about_thread_creation (pthread_self(), name, 512);
pthread_mutex_lock (&self->_timespan_mutex);
while (self->_timespan_thread_active.load ()) {
pthread_cond_wait (&self->_timespan_cond, &self->_timespan_mutex);
if (!self->_timespan_thread_active.load ()) {
break;
} else {
Temporal::TempoMap::fetch ();
self->process_connection.disconnect ();
Glib::Threads::Mutex::Lock l (self->export_status->lock());
DiskReader::allocate_working_buffers ();
self->start_timespan ();
DiskReader::free_working_buffers ();
}
}
pthread_mutex_unlock (&self->_timespan_mutex);
pthread_exit (0);
return 0;
}
void
ExportHandler::timespan_thread_wakeup ()
{
if (pthread_mutex_trylock (&_timespan_mutex) == 0) {
pthread_cond_signal (&_timespan_cond);
pthread_mutex_unlock (&_timespan_mutex);
}
}
/** Add an export to the `to-do' list */
@ -372,22 +429,6 @@ ExportHandler::command_output(std::string output, size_t size)
info << output << endmsg;
}
void*
ExportHandler::start_timespan_bg (void* eh)
{
char name[64];
snprintf (name, 64, "Export-TS-%p", (void*)DEBUG_THREAD_SELF);
pthread_set_name (name);
ExportHandler* self = static_cast<ExportHandler*> (eh);
self->process_connection.disconnect ();
Glib::Threads::Mutex::Lock l (self->export_status->lock());
SessionEvent::create_per_thread_pool (name, 512);
DiskReader::allocate_working_buffers ();
self->start_timespan ();
DiskReader::free_working_buffers ();
return 0;
}
void
ExportHandler::finish_timespan ()
{
@ -543,9 +584,7 @@ ExportHandler::finish_timespan ()
/* finish timespan is called in freewheeling rt-context,
* we cannot start a new export from here */
assert (AudioEngine::instance()->freewheeling ());
pthread_t tid;
pthread_create (&tid, NULL, ExportHandler::start_timespan_bg, this);
pthread_detach (tid);
timespan_thread_wakeup ();
}
void