Skip to content
This repository has been archived by the owner on Feb 13, 2019. It is now read-only.

Commit

Permalink
Fix broken shared 32-/64-bit semaphores on recent glibc versions.
Browse files Browse the repository at this point in the history
Recent versions of glibc have changed the memory layout of semaphores
on 64-bit, which means that 32- and 64-bit semaphores are
fundamentally incompatible and cannot be shared anymore. The symptom
is that the plugin hangs on communicating with the child process, and
eventually times out.

However, my previous assumption in 2cefab1, that pipes are not
realtime safe on Linux, was incorrect. They are used by Jack all the
time. So the problem is fixed by switching to pipes for process
synchronization. Shared memory is still used for the data though, as
well as to store the pipe descriptors.

Another nice side effect of this fix is that we now get notified again
when the child process dies or otherwise breaks the connection.

Signed-off-by: Kristian Amlie <kristian@amlie.name>
  • Loading branch information
kramlie committed Mar 30, 2018
1 parent 9462b34 commit 229efec
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 37 deletions.
15 changes: 5 additions & 10 deletions rdwrops.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,11 @@ struct RingBuffer

struct ShmControl
{
// 32 and 64-bit binaries align semaphores differently.
// Let's make sure there's plenty of room for either one.
union {
sem_t runServer;
char alignServerSem[32];
};
union {
sem_t runClient;
char alignClientSem[32];
};
// Pipe will be used by both 64- and 32- bit, so store as the former.
int64_t runServerRead;
int64_t runServerWrite;
int64_t runClientRead;
int64_t runClientWrite;
RingBuffer ringBuffer;
};

Expand Down
31 changes: 22 additions & 9 deletions remotepluginclient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,17 @@ RemotePluginClient::RemotePluginClient() :
}

memset(m_shmControl, 0, sizeof(ShmControl));
if (sem_init(&m_shmControl->runServer, 1, 0)) {
throw((std::string)"Failed to initialize shared memory semaphore");
int pipeFds[2];
if (pipe(pipeFds) != 0) {
throw((std::string)"Failed to initialize communication pipe");
}
if (sem_init(&m_shmControl->runClient, 1, 0)) {
throw((std::string)"Failed to initialize shared memory semaphore");
m_shmControl->runServerRead = pipeFds[0];
m_shmControl->runServerWrite = pipeFds[1];
if (pipe(pipeFds) != 0) {
throw((std::string)"Failed to initialize communication pipe");
}
m_shmControl->runClientRead = pipeFds[0];
m_shmControl->runClientWrite = pipeFds[1];

sprintf(tmpFileBase, "/dssi-vst-rplugin_shm_XXXXXX");
m_shmFd = shm_mkstemp(tmpFileBase);
Expand Down Expand Up @@ -160,6 +165,14 @@ RemotePluginClient::cleanup()
m_shm = 0;
}
if (m_shmControl) {
if (m_shmControl->runServerRead)
close(m_shmControl->runServerRead);
if (m_shmControl->runServerWrite)
close(m_shmControl->runServerWrite);
if (m_shmControl->runClientRead)
close(m_shmControl->runClientRead);
if (m_shmControl->runClientWrite)
close(m_shmControl->runClientWrite);
munmap(m_shmControl, sizeof(ShmControl));
m_shmControl = 0;
}
Expand Down Expand Up @@ -469,12 +482,12 @@ RemotePluginClient::process(float **inputs, float **outputs)
void
RemotePluginClient::waitForServer()
{
sem_post(&m_shmControl->runServer);
char msg = 0;
if (write(m_shmControl->runServerWrite, &msg, 1) != 1) {
throw RemotePluginClosedException();
}

timespec ts_timeout;
clock_gettime(CLOCK_REALTIME, &ts_timeout);
ts_timeout.tv_sec += 5;
if (sem_timedwait(&m_shmControl->runClient, &ts_timeout) != 0) {
if (read(m_shmControl->runClientRead, &msg, 1) != 1) {
throw RemotePluginClosedException();
}
}
Expand Down
24 changes: 6 additions & 18 deletions remotepluginserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,30 +207,18 @@ RemotePluginServer::dispatchControl(int timeout)
void
RemotePluginServer::dispatchProcess(int timeout)
{
timespec ts_timeout;
clock_gettime(CLOCK_REALTIME, &ts_timeout);
time_t seconds = timeout / 1000;
ts_timeout.tv_sec += seconds;
ts_timeout.tv_nsec += (timeout - seconds * 1000) * 1000000;
if (ts_timeout.tv_nsec >= 1000000000) {
ts_timeout.tv_nsec -= 1000000000;
ts_timeout.tv_sec++;
}

if (sem_timedwait(&m_shmControl->runServer, &ts_timeout)) {
if (errno == ETIMEDOUT) {
return;
} else {
throw RemotePluginClosedException();
}
char msg;
if (read(m_shmControl->runServerRead, &msg, 1) != 1) {
throw RemotePluginClosedException();
}

while (dataAvailable(&m_shmControl->ringBuffer)) {
dispatchProcessEvents();
}

if (sem_post(&m_shmControl->runClient)) {
std::cerr << "Could not post to semaphore\n";
msg = 0;
if (write(m_shmControl->runClientWrite, &msg, 1) != 1) {
throw RemotePluginClosedException();
}
}

Expand Down

0 comments on commit 229efec

Please sign in to comment.