diff --git a/source/bridges-ui/CarlaBridgeUI.cpp b/source/bridges-ui/CarlaBridgeUI.cpp index b3920f1e2..45e6cb446 100644 --- a/source/bridges-ui/CarlaBridgeUI.cpp +++ b/source/bridges-ui/CarlaBridgeUI.cpp @@ -57,19 +57,15 @@ CarlaBridgeUI::~CarlaBridgeUI() /*noexcept*/ { carla_debug("CarlaBridgeUI::~CarlaBridgeUI()"); + if (isPipeRunning() && ! fQuitReceived) + writeExitingMessageAndWait(); + if (fLib != nullptr) { lib_close(fLib); fLib = nullptr; } - if (isPipeRunning() && ! fQuitReceived) - { - const CarlaMutexLocker cml(getPipeLock()); - writeMessage("exiting\n", 8); - flushMessages(); - } - if (fToolkit != nullptr) { fToolkit->quit(); @@ -318,11 +314,7 @@ bool CarlaBridgeUI::init(const int argc, const char* argv[]) if (! fGotOptions) { carla_stderr2("CarlaBridgeUI::init() - did not get options on time, quitting..."); - { - const CarlaMutexLocker cml(getPipeLock()); - writeMessage("exiting\n", 8); - flushMessages(); - } + writeExitingMessageAndWait(); closePipeClient(); return false; } diff --git a/source/externalui.py b/source/externalui.py index b8bd2909d..78e817995 100755 --- a/source/externalui.py +++ b/source/externalui.py @@ -60,6 +60,7 @@ class ExternalUI(object): if self.fPipeClient is None: return + # FIXME if not self.fQuitReceived: self.send(["exiting"]) diff --git a/source/native-plugins/zynaddsubfx-ui.cpp b/source/native-plugins/zynaddsubfx-ui.cpp index 936ca45b1..1fe7cedcf 100644 --- a/source/native-plugins/zynaddsubfx-ui.cpp +++ b/source/native-plugins/zynaddsubfx-ui.cpp @@ -136,10 +136,7 @@ public: if (fQuitReceived) return; - const CarlaMutexLocker cml(getPipeLock()); - - writeMessage("exiting\n"); - flushMessages(); + writeExitingMessageAndWait(); } protected: diff --git a/source/utils/CarlaPipeUtils.cpp b/source/utils/CarlaPipeUtils.cpp index 35dc5274d..a6842256a 100644 --- a/source/utils/CarlaPipeUtils.cpp +++ b/source/utils/CarlaPipeUtils.cpp @@ -411,9 +411,18 @@ struct CarlaPipeCommon::PrivateData { // read functions must only be called in context of idlePipe() bool isReading; + // the client side is closing down, only waiting for response from server + bool clientClosingDown; + + // other side of pipe has closed + bool pipeClosed; + // print error only once bool lastMessageFailed; + // for debugging + bool isServer; + // common write lock CarlaMutex writeLock; @@ -430,7 +439,10 @@ struct CarlaPipeCommon::PrivateData { pipeRecv(INVALID_PIPE_VALUE), pipeSend(INVALID_PIPE_VALUE), isReading(false), + clientClosingDown(false), + pipeClosed(true), lastMessageFailed(false), + isServer(false), writeLock(), tmpBuf(), tmpStr() @@ -466,7 +478,7 @@ CarlaPipeCommon::~CarlaPipeCommon() /*noexcept*/ bool CarlaPipeCommon::isPipeRunning() const noexcept { - return (pData->pipeRecv != INVALID_PIPE_VALUE && pData->pipeSend != INVALID_PIPE_VALUE); + return (pData->pipeRecv != INVALID_PIPE_VALUE && pData->pipeSend != INVALID_PIPE_VALUE && ! pData->pipeClosed); } void CarlaPipeCommon::idlePipe(const bool onlyOnce) noexcept @@ -488,15 +500,22 @@ void CarlaPipeCommon::idlePipe(const bool onlyOnce) noexcept pData->isReading = true; - try { - msgReceived(msg); - } CARLA_SAFE_EXCEPTION("msgReceived"); + if (std::strcmp(msg, "__carla-quit__") == 0) + { + pData->pipeClosed = true; + } + else if (! pData->clientClosingDown) + { + try { + msgReceived(msg); + } CARLA_SAFE_EXCEPTION("msgReceived"); + } pData->isReading = false; delete[] msg; - if (onlyOnce) + if (onlyOnce || pData->pipeRecv == INVALID_PIPE_VALUE) break; } @@ -1015,12 +1034,18 @@ bool CarlaPipeCommon::_writeMsgBuffer(const char* const msg, const std::size_t s return true; } +#if 0 + // ignore errors if the other side of the pipe has closed + if (pData->pipeClosed) + return false; +#endif + if (! pData->lastMessageFailed) { pData->lastMessageFailed = true; fprintf(stderr, - "CarlaPipeCommon::_writeMsgBuffer(..., " P_SIZE ") - failed with " P_SSIZE ", message was:\n%s", - size, ret, msg); + "CarlaPipeCommon::_writeMsgBuffer(..., " P_SIZE ") - failed with " P_SSIZE " (%s), message was:\n%s", + size, ret, bool2str(pData->isServer), msg); } return false; @@ -1032,6 +1057,7 @@ CarlaPipeServer::CarlaPipeServer() noexcept : CarlaPipeCommon() { carla_debug("CarlaPipeServer::CarlaPipeServer()"); + pData->isServer = true; } CarlaPipeServer::~CarlaPipeServer() /*noexcept*/ @@ -1269,6 +1295,7 @@ bool CarlaPipeServer::startPipeServer(const char* const filename, #endif pData->pipeRecv = pipeRecvClient; pData->pipeSend = pipeSendClient; + pData->pipeClosed = false; carla_stdout("ALL OK!"); return true; } @@ -1323,7 +1350,7 @@ void CarlaPipeServer::stopPipeServer(const uint32_t timeOutMilliseconds) noexcep if (pData->pipeSend != INVALID_PIPE_VALUE) { - _writeMsgBuffer("quit\n", 5); + _writeMsgBuffer("__carla-quit__\n", 15); flushMessages(); } @@ -1341,7 +1368,7 @@ void CarlaPipeServer::stopPipeServer(const uint32_t timeOutMilliseconds) noexcep if (pData->pipeSend != INVALID_PIPE_VALUE) { - _writeMsgBuffer("quit\n", 5); + _writeMsgBuffer("__carla-quit__\n", 15); flushMessages(); } @@ -1357,6 +1384,8 @@ void CarlaPipeServer::closePipeServer() noexcept { carla_debug("CarlaPipeServer::closePipeServer()"); + pData->pipeClosed = true; + const CarlaMutexLocker cml(pData->writeLock); if (pData->pipeRecv != INVALID_PIPE_VALUE) @@ -1472,6 +1501,8 @@ bool CarlaPipeClient::initPipeClient(const char* argv[]) noexcept pData->pipeRecv = pipeRecvServer; pData->pipeSend = pipeSendServer; + pData->pipeClosed = false; + pData->clientClosingDown = false; writeMessage("\n", 1); flushMessages(); @@ -1483,6 +1514,8 @@ void CarlaPipeClient::closePipeClient() noexcept { carla_debug("CarlaPipeClient::closePipeClient()"); + pData->pipeClosed = true; + const CarlaMutexLocker cml(pData->writeLock); if (pData->pipeRecv != INVALID_PIPE_VALUE) @@ -1506,6 +1539,25 @@ void CarlaPipeClient::closePipeClient() noexcept } } +void CarlaPipeClient::writeExitingMessageAndWait() noexcept +{ + { + const CarlaMutexLocker cml(pData->writeLock); + _writeMsgBuffer("exiting\n", 8); + flushMessages(); + } + + // NOTE: no more messages are handled after this point + pData->clientClosingDown = true; + + // FIXME: don't sleep forever + for (; ! pData->pipeClosed;) + { + carla_msleep(50); + idlePipe(true); + } +} + // ----------------------------------------------------------------------- ScopedEnvVar::ScopedEnvVar(const char* const key, const char* const value) noexcept diff --git a/source/utils/CarlaPipeUtils.hpp b/source/utils/CarlaPipeUtils.hpp index 6fed61dca..cad4b962b 100644 --- a/source/utils/CarlaPipeUtils.hpp +++ b/source/utils/CarlaPipeUtils.hpp @@ -320,6 +320,14 @@ public: */ void closePipeClient() noexcept; + // ------------------------------------------------------------------- + // write prepared messages, no lock or flush needed (done internally) + + /*! + * Write a single "exiting" message and wait for server to respond. + */ + void writeExitingMessageAndWait() noexcept; + CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPipeClient) };