use Xthreads in session butler.
(hopefully) fixes export randomly stalling on windows: dequeue_request() was a single request (no queue) on Windows. Butler::queue_request() is called -> Butler goes to work.. -> while working, another request is queued -> butler never sees this -> deadlock during Freewheeling/Export wait_until_finished() waits for the 2nd request to be handled, and never returns.
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
#include "pbd/glib_semaphore.h"
|
||||
#endif
|
||||
|
||||
#include "pbd/crossthread.h"
|
||||
#include "pbd/ringbuffer.h"
|
||||
#include "pbd/pool.h"
|
||||
#include "ardour/libardour_visibility.h"
|
||||
@@ -86,38 +87,17 @@ class LIBARDOUR_API Butler : public SessionHandleRef
|
||||
uint32_t midi_dstream_buffer_size;
|
||||
RingBuffer<CrossThreadPool*> pool_trash;
|
||||
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
PBD::atomic_counter m_request_state;
|
||||
PBD::GlibSemaphore m_request_sem;
|
||||
#else
|
||||
int request_pipe[2];
|
||||
#endif
|
||||
|
||||
private:
|
||||
void empty_pool_trash ();
|
||||
void config_changed (std::string);
|
||||
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
int setup_request_pipe ();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* return true if there are requests to be processed
|
||||
*/
|
||||
bool wait_for_requests ();
|
||||
|
||||
/**
|
||||
* Remove request from butler request queue
|
||||
*
|
||||
* return true if there was another request and req is valid
|
||||
*/
|
||||
bool dequeue_request (Request::Type& req);
|
||||
|
||||
/**
|
||||
* Add request to butler thread request queue
|
||||
*/
|
||||
void queue_request (Request::Type r);
|
||||
|
||||
CrossThreadChannel _xthread;
|
||||
|
||||
};
|
||||
|
||||
} // namespace ARDOUR
|
||||
|
||||
@@ -49,6 +49,7 @@ Butler::Butler(Session& s)
|
||||
, audio_dstream_playback_buffer_size(0)
|
||||
, midi_dstream_buffer_size(0)
|
||||
, pool_trash(16)
|
||||
, _xthread (true)
|
||||
{
|
||||
g_atomic_int_set(&should_do_transport_work, 0);
|
||||
SessionEvent::pool->set_trash (&pool_trash);
|
||||
@@ -74,31 +75,6 @@ Butler::config_changed (std::string p)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
int
|
||||
Butler::setup_request_pipe ()
|
||||
{
|
||||
if (pipe (request_pipe)) {
|
||||
error << string_compose(_("Cannot create transport request signal pipe (%1)"),
|
||||
strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl (request_pipe[0], F_SETFL, O_NONBLOCK)) {
|
||||
error << string_compose(_("UI: cannot set O_NONBLOCK on butler request pipe (%1)"),
|
||||
strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl (request_pipe[1], F_SETFL, O_NONBLOCK)) {
|
||||
error << string_compose(_("UI: cannot set O_NONBLOCK on butler request pipe (%1)"),
|
||||
strerror (errno)) << endmsg;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
Butler::start_thread()
|
||||
{
|
||||
@@ -118,10 +94,6 @@ Butler::start_thread()
|
||||
|
||||
should_run = false;
|
||||
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
if (setup_request_pipe() != 0) return -1;
|
||||
#endif
|
||||
|
||||
if (pthread_create_and_store ("disk butler", &thread, _thread_work, this)) {
|
||||
error << _("Session: could not create butler thread") << endmsg;
|
||||
return -1;
|
||||
@@ -151,69 +123,6 @@ Butler::_thread_work (void* arg)
|
||||
return ((Butler *) arg)->thread_work ();
|
||||
}
|
||||
|
||||
bool
|
||||
Butler::wait_for_requests ()
|
||||
{
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
struct pollfd pfd[1];
|
||||
|
||||
pfd[0].fd = request_pipe[0];
|
||||
pfd[0].events = POLLIN|POLLERR|POLLHUP;
|
||||
|
||||
while(true) {
|
||||
if (poll (pfd, 1, -1) < 0) {
|
||||
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
|
||||
error << string_compose (_("poll on butler request pipe failed (%1)"),
|
||||
strerror (errno))
|
||||
<< endmsg;
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: butler awake at @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
|
||||
|
||||
if (pfd[0].revents & ~POLLIN) {
|
||||
error << string_compose (_("Error on butler thread request pipe: fd=%1 err=%2"), pfd[0].fd, pfd[0].revents) << endmsg;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pfd[0].revents & POLLIN) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
m_request_sem.wait ();
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
Butler::dequeue_request (Request::Type& r)
|
||||
{
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
char req;
|
||||
size_t nread = ::read (request_pipe[0], &req, sizeof (req));
|
||||
if (nread == 1) {
|
||||
r = (Request::Type) req;
|
||||
return true;
|
||||
} else if (nread == 0) {
|
||||
return false;
|
||||
} else if (errno == EAGAIN) {
|
||||
return false;
|
||||
} else {
|
||||
fatal << _("Error reading from butler request pipe") << endmsg;
|
||||
abort(); /*NOTREACHED*/
|
||||
}
|
||||
#else
|
||||
r = (Request::Type) m_request_state.get();
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void *
|
||||
Butler::thread_work ()
|
||||
{
|
||||
@@ -227,16 +136,12 @@ Butler::thread_work ()
|
||||
|
||||
if(!disk_work_outstanding) {
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("%1 butler waits for requests @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
|
||||
if (wait_for_requests ()) {
|
||||
Request::Type req;
|
||||
|
||||
/* empty the pipe of all current requests */
|
||||
#ifdef PLATFORM_WINDOWS
|
||||
dequeue_request (req);
|
||||
#else
|
||||
while (dequeue_request(req)) {
|
||||
#endif
|
||||
switch (req) {
|
||||
char msg;
|
||||
/* empty the pipe of all current requests */
|
||||
if (_xthread.receive (msg, true) >= 0) {
|
||||
Request::Type req = (Request::Type) msg;
|
||||
switch (req) {
|
||||
|
||||
case Request::Run:
|
||||
DEBUG_TRACE (DEBUG::Butler, string_compose ("%1: butler asked to run @ %2\n", DEBUG_THREAD_SELF, g_get_monotonic_time()));
|
||||
@@ -256,10 +161,7 @@ Butler::thread_work ()
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -425,13 +327,8 @@ Butler::schedule_transport_work ()
|
||||
void
|
||||
Butler::queue_request (Request::Type r)
|
||||
{
|
||||
#ifndef PLATFORM_WINDOWS
|
||||
char c = r;
|
||||
(void) ::write (request_pipe[1], &c, 1);
|
||||
#else
|
||||
m_request_state.set (r);
|
||||
m_request_sem.post ();
|
||||
#endif
|
||||
_xthread.deliver (c);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user