From 6ba82f32ed7611b1317b1133aea31297f3c4192f Mon Sep 17 00:00:00 2001 From: falkTX Date: Wed, 28 Dec 2016 23:44:52 +0000 Subject: [PATCH] Rework pipe code, now working under win32; Enable pipe plugins Hopefully doesn't break linux/osx stuff... --- source/backend/engine/CarlaEngineNative.cpp | 6 +- source/carla_app.py | 2 +- source/carla_utils.py | 5 +- source/externalui.py | 6 +- source/includes/CarlaDefines.h | 12 +- source/includes/CarlaNativeExtUI.hpp | 5 +- source/native-plugins/_all.c | 6 - source/native-plugins/_data.cpp | 6 - source/tests/CarlaPipeUtils.cpp | 16 +- source/tests/Makefile | 2 +- source/utils/CarlaPipeUtils.cpp | 518 ++++++++------------ 11 files changed, 245 insertions(+), 339 deletions(-) diff --git a/source/backend/engine/CarlaEngineNative.cpp b/source/backend/engine/CarlaEngineNative.cpp index 013792784..502fed73c 100644 --- a/source/backend/engine/CarlaEngineNative.cpp +++ b/source/backend/engine/CarlaEngineNative.cpp @@ -1486,9 +1486,9 @@ protected: path += CARLA_OS_SEP_STR "carla-plugin-patchbay"; else path += CARLA_OS_SEP_STR "carla-plugin"; -// #ifdef CARLA_OS_WIN -// path += ".exe"; -// #endif +#ifdef CARLA_OS_WIN + path += ".exe"; +#endif carla_stdout("Trying to start carla-plugin using \"%s\"", path.buffer()); fUiServer.setData(path, pData->sampleRate, pHost->uiName); diff --git a/source/carla_app.py b/source/carla_app.py index e4c63476e..f1de0039a 100644 --- a/source/carla_app.py +++ b/source/carla_app.py @@ -50,7 +50,7 @@ class CarlaApplication(object): QApplication.addLibraryPath(CWD) # Needed for local wine build - if WINDOWS and CWD.endswith("source") and os.getenv("CXFREEZE") is None: + if WINDOWS and CWD.endswith(("source", "resources")) and os.getenv("CXFREEZE") is None: QApplication.addLibraryPath("C:\\Python34\\Lib\\site-packages\\PyQt5\\plugins") # Use binary dir as library path (except in Windows) diff --git a/source/carla_utils.py b/source/carla_utils.py index c7342954d..eed774660 100644 --- a/source/carla_utils.py +++ b/source/carla_utils.py @@ -306,7 +306,10 @@ class CarlaUtils(object): return self.lib.carla_pipe_client_new(cargv, self._pipeClientCallback, None) def pipe_client_idle(self, handle): - self.lib.carla_pipe_client_idle(handle) + try: + self.lib.carla_pipe_client_idle(handle) + except OSError as e: + print("pipe_client_idle", e) def pipe_client_is_running(self, handle): return bool(self.lib.carla_pipe_client_is_running(handle)) diff --git a/source/externalui.py b/source/externalui.py index edf54646b..b8bd2909d 100755 --- a/source/externalui.py +++ b/source/externalui.py @@ -184,7 +184,6 @@ class ExternalUI(object): gCarla.utils.pipe_client_lock(self.fPipeClient) - # this must never fail, we need to unlock at the end try: for line in lines: if line is None: @@ -202,7 +201,6 @@ class ExternalUI(object): return gCarla.utils.pipe_client_write_msg(self.fPipeClient, line2 + "\n") - except: - pass - gCarla.utils.pipe_client_flush_and_unlock(self.fPipeClient) + finally: + gCarla.utils.pipe_client_flush_and_unlock(self.fPipeClient) diff --git a/source/includes/CarlaDefines.h b/source/includes/CarlaDefines.h index ec368038e..40013804b 100644 --- a/source/includes/CarlaDefines.h +++ b/source/includes/CarlaDefines.h @@ -86,35 +86,41 @@ /* Define various string format types */ #if defined(CARLA_OS_WIN64) -# define P_INT64 "%I64i" -# define P_UINT64 "%I64u" +# define P_INT64 "%lli" +# define P_UINT64 "%llu" # define P_INTPTR "%lli" # define P_UINTPTR "%llx" -# define P_SIZE "%I64u" +# define P_SIZE "%llu" +# define P_SSIZE "%lli" #elif defined(CARLA_OS_WIN32) # define P_INT64 "%lli" # define P_UINT64 "%llu" # define P_INTPTR "%i" # define P_UINTPTR "%x" # define P_SIZE "%u" +# define P_SSIZE "%i" #elif defined(CARLA_OS_MAC) +// FIXME adjust for 32bit bridges # define P_INT64 "%lli" # define P_UINT64 "%llu" # define P_INTPTR "%li" # define P_UINTPTR "%lx" # define P_SIZE "%lu" +# define P_SSIZE "%li" #elif defined(__WORDSIZE) && __WORDSIZE == 64 # define P_INT64 "%li" # define P_UINT64 "%lu" # define P_INTPTR "%li" # define P_UINTPTR "%lx" # define P_SIZE "%lu" +# define P_SSIZE "%li" #else # define P_INT64 "%lli" # define P_UINT64 "%llu" # define P_INTPTR "%i" # define P_UINTPTR "%x" # define P_SIZE "%u" +# define P_SSIZE "%i" #endif /* Define BINARY_NATIVE */ diff --git a/source/includes/CarlaNativeExtUI.hpp b/source/includes/CarlaNativeExtUI.hpp index 725bffbeb..3fd2f8c96 100644 --- a/source/includes/CarlaNativeExtUI.hpp +++ b/source/includes/CarlaNativeExtUI.hpp @@ -1,6 +1,6 @@ /* * Carla Native Plugin API (C++) - * Copyright (C) 2012-2014 Filipe Coelho + * Copyright (C) 2012-2016 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -40,6 +40,9 @@ public: { fExtUiPath += CARLA_OS_SEP_STR; fExtUiPath += extUiPath; +#ifdef CARLA_OS_WIN + fExtUiPath += ".exe"; +#endif } const char* getExtUiPath() const noexcept diff --git a/source/native-plugins/_all.c b/source/native-plugins/_all.c index 0622c4649..ddbd85195 100644 --- a/source/native-plugins/_all.c +++ b/source/native-plugins/_all.c @@ -84,14 +84,10 @@ void carla_register_all_native_plugins(void) // MIDI file and sequencer carla_register_native_plugin_midifile(); -#ifdef CARLA_OS_LINUX carla_register_native_plugin_midipattern(); -#endif -#ifndef CARLA_OS_WIN // Carla carla_register_native_plugin_carla(); -#endif // DISTRHO Plugins carla_register_native_plugin_distrho_3bandeq(); @@ -109,11 +105,9 @@ void carla_register_all_native_plugins(void) carla_register_native_plugin_distrho_vectorjuice(); carla_register_native_plugin_distrho_wobblejuice(); -#ifndef CARLA_OS_WIN // External-UI plugins carla_register_native_plugin_bigmeter(); carla_register_native_plugin_notes(); -#endif #ifdef HAVE_ZYN_DEPS // ZynAddSubFX diff --git a/source/native-plugins/_data.cpp b/source/native-plugins/_data.cpp index 7cd039c98..2bf5fd6d1 100644 --- a/source/native-plugins/_data.cpp +++ b/source/native-plugins/_data.cpp @@ -205,7 +205,6 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* copyright */ "GNU GPL v2+", DESCFUNCS }, -#ifdef CARLA_OS_LINUX { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, /* hints */ static_cast(NATIVE_PLUGIN_IS_RTSAFE @@ -225,12 +224,10 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* copyright */ "GNU GPL v2+", DESCFUNCS }, -#endif // ----------------------------------------------------------------------- // Carla -#ifndef CARLA_OS_WIN { /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, /* hints */ static_cast(NATIVE_PLUGIN_IS_SYNTH @@ -336,7 +333,6 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* copyright */ "GNU GPL v2+", DESCFUNCS }, -#endif // CARLA_OS_WIN // ----------------------------------------------------------------------- // DISTRHO Plugins @@ -542,7 +538,6 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { // ----------------------------------------------------------------------- // External-UI plugins -#ifndef CARLA_OS_WIN { /* category */ NATIVE_PLUGIN_CATEGORY_UTILITY, /* hints */ static_cast(NATIVE_PLUGIN_IS_RTSAFE @@ -578,7 +573,6 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { /* copyright */ "GNU GPL v2+", DESCFUNCS }, -#endif // ----------------------------------------------------------------------- // ZynAddSubFX diff --git a/source/tests/CarlaPipeUtils.cpp b/source/tests/CarlaPipeUtils.cpp index 9faa56e8b..6a69a2ab2 100644 --- a/source/tests/CarlaPipeUtils.cpp +++ b/source/tests/CarlaPipeUtils.cpp @@ -1,6 +1,6 @@ /* * Carla Utility Tests - * Copyright (C) 2013-2014 Filipe Coelho + * Copyright (C) 2013-2016 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -16,6 +16,7 @@ */ #include "CarlaPipeUtils.hpp" +#include "juce_core/juce_core.h" // ----------------------------------------------------------------------- @@ -52,6 +53,7 @@ int main(int argc, const char* argv[]) if (argc != 1) { carla_stdout("CLIENT STARTED %i", argc); + std::fflush(stdout); CarlaPipeClient2 p; const bool ok = p.initPipeClient(argv); @@ -64,20 +66,22 @@ int main(int argc, const char* argv[]) carla_msleep(500); carla_stderr2("CLIENT idle start"); + std::fflush(stdout); p.idlePipe(); carla_stderr2("CLIENT idle end"); + std::fflush(stdout); carla_msleep(500); } else { carla_stdout("SERVER STARTED %i", argc); + using juce::File; + using juce::String; + String path = File(File::getSpecialLocation(File::currentExecutableFile)).getFullPathName(); + CarlaPipeServer2 p; -#ifdef CARLA_OS_WIN - const bool ok = p.startPipeServer("H:\\Source\\falkTX\\Carla\\source\\tests\\CarlaPipeUtils.exe", "/home/falktx/Videos", "/home/falktx"); -#else - const bool ok = p.startPipeServer("/home/falktx/Source/falkTX/Carla/source/tests/CarlaPipeUtils", "/home/falktx/Videos", "/home/falktx"); -#endif + const bool ok = p.startPipeServer(path.toRawUTF8(), "/home/falktx/Videos", "/home/falktx"); CARLA_SAFE_ASSERT_RETURN(ok,1); p.lockPipe(); diff --git a/source/tests/Makefile b/source/tests/Makefile index 11b418923..6cfb58897 100644 --- a/source/tests/Makefile +++ b/source/tests/Makefile @@ -135,7 +135,7 @@ ifneq ($(WIN32),true) # ./$@ && endif -CarlaPipeUtils.exe: CarlaPipeUtils.cpp +CarlaPipeUtils.exe: CarlaPipeUtils.cpp ../utils/CarlaPipeUtils.cpp $(CXX) $< $(PEDANTIC_CXX_FLAGS) -o $@ $(MODULEDIR)/juce_core.a -lole32 -lshlwapi -lversion -lwsock32 -lwininet -lwinmm -lws2_32 -lpthread CarlaUtils1: CarlaUtils1.cpp ../utils/*.hpp diff --git a/source/utils/CarlaPipeUtils.cpp b/source/utils/CarlaPipeUtils.cpp index 44f763638..6614b2bdf 100644 --- a/source/utils/CarlaPipeUtils.cpp +++ b/source/utils/CarlaPipeUtils.cpp @@ -1,6 +1,6 @@ /* - * Carla Utility Tests - * Copyright (C) 2013-2014 Filipe Coelho + * Carla Pipe Utilities + * Copyright (C) 2013-2016 Filipe Coelho * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,12 +33,12 @@ #include #include +#include #if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) # include "juce_core/juce_core.h" #else # include -# include # include # include #endif @@ -53,101 +53,29 @@ // ----------------------------------------------------------------------- // win32 stuff -struct OverlappedEvent { - OVERLAPPED over; - - OverlappedEvent() - : over() - { - carla_zeroStruct(over); - over.hEvent = ::CreateEvent(nullptr, TRUE, FALSE, nullptr); - } - - ~OverlappedEvent() - { - ::CloseHandle(over.hEvent); - } - - CARLA_DECLARE_NON_COPY_STRUCT(OverlappedEvent) -}; - -// ----------------------------------------------------------------------- -// ReadFile - static inline -ssize_t ReadFileBlock(const HANDLE pipeh, void* const buf, const std::size_t numBytes) -{ - DWORD dsize; - - if (::ReadFile(pipeh, buf, numBytes, &dsize, nullptr) != FALSE) - return static_cast(dsize); - - return -1; -} - -static inline -ssize_t ReadFileNonBlock(const HANDLE pipeh, const HANDLE cancelh, void* const buf, const std::size_t numBytes) +ssize_t ReadFileWin32(const HANDLE pipeh, void* const buf, const std::size_t numBytes) { DWORD dsize = numBytes; - OverlappedEvent over; - - if (::ReadFile(pipeh, buf, numBytes, nullptr /*&dsize*/, &over.over) != FALSE) - return static_cast(dsize); - - if (::GetLastError() == ERROR_IO_PENDING) - { - HANDLE handles[] = { over.over.hEvent, cancelh }; - - if (::WaitForMultipleObjects(2, handles, FALSE, 0) != WAIT_OBJECT_0) - { - ::CancelIo(pipeh); - return -1; - } - - if (::GetOverlappedResult(pipeh, &over.over, nullptr /*&dsize*/, FALSE) != FALSE) - return static_cast(dsize); - } - - return -1; -} + DWORD available = 0; -// ----------------------------------------------------------------------- -// WriteFile - -static inline -ssize_t WriteFileBlock(const HANDLE pipeh, const void* const buf, const std::size_t numBytes) -{ - DWORD dsize; + if (::PeekNamedPipe(pipeh, nullptr, 0, nullptr, &available, nullptr) == FALSE || available == 0) + return -1; - if (::WriteFile(pipeh, buf, numBytes, &dsize, nullptr) != FALSE) + if (::ReadFile(pipeh, buf, dsize, &dsize, nullptr) != FALSE) return static_cast(dsize); return -1; } static inline -ssize_t WriteFileNonBlock(const HANDLE pipeh, const HANDLE cancelh, const void* const buf, const std::size_t numBytes) +ssize_t WriteFileWin32(const HANDLE pipeh, const void* const buf, const std::size_t numBytes) { DWORD dsize = numBytes; - OverlappedEvent over; - if (::WriteFile(pipeh, buf, numBytes, nullptr /*&dsize*/, &over.over) != FALSE) + if (::WriteFile(pipeh, buf, dsize, &dsize, nullptr) != FALSE) return static_cast(dsize); - if (::GetLastError() == ERROR_IO_PENDING) - { - HANDLE handles[] = { over.over.hEvent, cancelh }; - - if (::WaitForMultipleObjects(2, handles, FALSE, 0) != WAIT_OBJECT_0) - { - ::CancelIo(pipeh); - return -1; - } - - if (::GetOverlappedResult(pipeh, &over.over, &dsize, FALSE) != FALSE) - return static_cast(dsize); - } - return -1; } #endif // CARLA_OS_WIN @@ -213,20 +141,52 @@ bool startProcess(const char* const argv[], PROCESS_INFORMATION* const processIn } command = command.trim(); - carla_stdout("startProcess() command:\n%s", command.toRawUTF8()); STARTUPINFOW startupInfo; carla_zeroStruct(startupInfo); -# if 0 - startupInfo.hStdInput = INVALID_HANDLE_VALUE; - startupInfo.hStdOutput = INVALID_HANDLE_VALUE; - startupInfo.hStdError = INVALID_HANDLE_VALUE; - startupInfo.dwFlags = STARTF_USESTDHANDLES; -# endif - startupInfo.cb = sizeof(STARTUPINFOW); + startupInfo.cb = sizeof(STARTUPINFOW); return CreateProcessW(nullptr, const_cast(command.toWideCharPointer()), - nullptr, nullptr, TRUE, 0x0, nullptr, nullptr, &startupInfo, processInfo) != FALSE; + nullptr, nullptr, FALSE, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, + nullptr, nullptr, &startupInfo, processInfo) != FALSE; +} + +static inline +bool waitForClientConnect(const HANDLE pipe, const uint32_t timeOutMilliseconds) noexcept +{ + CARLA_SAFE_ASSERT_RETURN(pipe != INVALID_PIPE_VALUE, false); + CARLA_SAFE_ASSERT_RETURN(timeOutMilliseconds > 0, false); + + bool connecting = true; + const uint32_t timeoutEnd(getMillisecondCounter() + timeOutMilliseconds); + + for (; connecting && ::ConnectNamedPipe(pipe, nullptr) == FALSE;) + { + const DWORD err = ::GetLastError(); + + switch (err) + { + case ERROR_PIPE_CONNECTED: + connecting = false; + break; + + case ERROR_IO_PENDING: + case ERROR_PIPE_LISTENING: + if (getMillisecondCounter() < timeoutEnd) + { + carla_msleep(5); + continue; + } + carla_stderr("waitForClientFirstMessage() - connect timed out"); + return false; + + default: + carla_stderr("waitForClientFirstMessage() - connect returned %i", int(err)); + return false; + } + } + + return true; } #else static inline @@ -262,33 +222,41 @@ template static inline bool waitForClientFirstMessage(const P& pipe, const uint32_t timeOutMilliseconds) noexcept { -#ifdef CARLA_OS_WIN - CARLA_SAFE_ASSERT_RETURN(pipe.handle != INVALID_HANDLE_VALUE, false); - CARLA_SAFE_ASSERT_RETURN(pipe.cancel != INVALID_HANDLE_VALUE, false); -#else - CARLA_SAFE_ASSERT_RETURN(pipe > 0, false); -#endif + CARLA_SAFE_ASSERT_RETURN(pipe != INVALID_PIPE_VALUE, false); CARLA_SAFE_ASSERT_RETURN(timeOutMilliseconds > 0, false); char c; ssize_t ret; const uint32_t timeoutEnd(getMillisecondCounter() + timeOutMilliseconds); +#ifdef CARLA_OS_WIN + if (! waitForClientConnect(pipe, timeOutMilliseconds)) + return false; +#endif + for (;;) { try { #ifdef CARLA_OS_WIN - //ret = ::ReadFileBlock(pipe.handle, &c, 1); - ret = ::ReadFileNonBlock(pipe.handle, pipe.cancel, &c, 1); + ret = ::ReadFileWin32(pipe, &c, 1); #else ret = ::read(pipe, &c, 1); #endif - } CARLA_SAFE_EXCEPTION_BREAK("read pipefd"); + } CARLA_SAFE_EXCEPTION_RETURN("read pipe", false); switch (ret) { + case 1: + if (c == '\n') + return true; + + carla_stderr("waitForClientFirstMessage() - read has wrong first char '%c'", c);return false; + return false; + case -1: // failed to read -#ifndef CARLA_OS_WIN +#ifdef CARLA_OS_WIN + if (::GetLastError() == ERROR_NO_DATA) +#else if (errno == EAGAIN) #endif { @@ -297,39 +265,24 @@ bool waitForClientFirstMessage(const P& pipe, const uint32_t timeOutMilliseconds carla_msleep(5); continue; } - carla_stderr("waitForClientFirstMessage() - timed out"); + carla_stderr("waitForClientFirstMessage() - read timed out"); } -#ifndef CARLA_OS_WIN else { +#ifdef CARLA_OS_WIN carla_stderr("waitForClientFirstMessage() - read failed"); +#else CarlaString error(std::strerror(errno)); carla_stderr("waitForClientFirstMessage() - read failed: %s", error.buffer()); - } #endif - break; - - case 1: // read ok - if (c == '\n') - { - // success - return true; - } - else - { - carla_stderr("waitForClientFirstMessage() - read has wrong first char '%c'", c); } - break; + return false; default: // ??? carla_stderr("waitForClientFirstMessage() - read returned %i", int(ret)); - break; + return false; } - - break; } - - return false; } // ----------------------------------------------------------------------- @@ -342,14 +295,16 @@ bool waitForProcessToStop(const PROCESS_INFORMATION& processInfo, const uint32_t CARLA_SAFE_ASSERT_RETURN(processInfo.hProcess != INVALID_HANDLE_VALUE, false); CARLA_SAFE_ASSERT_RETURN(timeOutMilliseconds > 0, false); - // TODO - this code is completly wrong... - const uint32_t timeoutEnd(getMillisecondCounter() + timeOutMilliseconds); for (;;) { - if (WaitForSingleObject(processInfo.hProcess, 0) == WAIT_OBJECT_0) + switch (WaitForSingleObject(processInfo.hProcess, 0)) + { + case WAIT_OBJECT_0: + case -1: return true; + } if (getMillisecondCounter() >= timeoutEnd) break; @@ -370,7 +325,7 @@ void waitForProcessToStopOrKillIt(const PROCESS_INFORMATION& processInfo, const { carla_stderr("waitForProcessToStopOrKillIt() - process didn't stop, force termination"); - if (TerminateProcess(processInfo.hProcess, 0) != FALSE) + if (TerminateProcess(processInfo.hProcess, 9) != FALSE) { // wait for process to stop waitForProcessToStop(processInfo, timeOutMilliseconds); @@ -472,7 +427,6 @@ struct CarlaPipeCommon::PrivateData { // pipes #ifdef CARLA_OS_WIN PROCESS_INFORMATION processInfo; - HANDLE cancelEvent; HANDLE pipeRecv; HANDLE pipeSend; #else @@ -494,7 +448,6 @@ struct CarlaPipeCommon::PrivateData { PrivateData() noexcept #ifdef CARLA_OS_WIN : processInfo(), - cancelEvent(INVALID_HANDLE_VALUE), #else : pid(-1), #endif @@ -509,26 +462,11 @@ struct CarlaPipeCommon::PrivateData { carla_zeroStruct(processInfo); processInfo.hProcess = INVALID_HANDLE_VALUE; processInfo.hThread = INVALID_HANDLE_VALUE; - - try { - cancelEvent = ::CreateEvent(nullptr, FALSE, FALSE, nullptr); - } CARLA_SAFE_EXCEPTION("CreateEvent"); #endif carla_zeroChars(tmpBuf, 0xff+1); } - ~PrivateData() noexcept - { -#ifdef CARLA_OS_WIN - if (cancelEvent != INVALID_HANDLE_VALUE) - { - ::CloseHandle(cancelEvent); - cancelEvent = INVALID_HANDLE_VALUE; - } -#endif - } - CARLA_DECLARE_NON_COPY_STRUCT(PrivateData) }; @@ -820,23 +758,16 @@ bool CarlaPipeCommon::writeAndFixMessage(const char* const msg) const noexcept bool CarlaPipeCommon::flushMessages() const noexcept { - // TESTING remove later (replace with trylock scope) - if (pData->writeLock.tryLock()) - { - carla_safe_assert("! pData->writeLock.tryLock()", __FILE__, __LINE__); - pData->writeLock.unlock(); - return false; - } - +#ifdef CARLA_OS_WIN + // TESTING remove later + const CarlaMutexTryLocker cmtl(pData->writeLock); + CARLA_SAFE_ASSERT_RETURN(cmtl.wasNotLocked(), false); CARLA_SAFE_ASSERT_RETURN(pData->pipeSend != INVALID_PIPE_VALUE, false); try { -#ifdef CARLA_OS_WIN return (::FlushFileBuffers(pData->pipeSend) != FALSE); -#else - return (::fsync(pData->pipeSend) == 0); -#endif } CARLA_SAFE_EXCEPTION_RETURN("CarlaPipeCommon::writeMsgBuffer", false); +#endif } // ------------------------------------------------------------------- @@ -1022,8 +953,7 @@ const char* CarlaPipeCommon::_readline() const noexcept { try { #ifdef CARLA_OS_WIN - //ret = ::ReadFileBlock(pData->pipeRecv, &c, 1); - ret = ::ReadFileNonBlock(pData->pipeRecv, pData->cancelEvent, &c, 1); + ret = ::ReadFileWin32(pData->pipeRecv, &c, 1); #else ret = ::read(pData->pipeRecv, &c, 1); #endif @@ -1092,14 +1022,18 @@ bool CarlaPipeCommon::_writeMsgBuffer(const char* const msg, const std::size_t s try { #ifdef CARLA_OS_WIN - //ret = ::WriteFileBlock(pData->pipeSend, msg, size); - ret = ::WriteFileNonBlock(pData->pipeSend, pData->cancelEvent, msg, size); + ret = ::WriteFileWin32(pData->pipeSend, msg, size); #else ret = ::write(pData->pipeSend, msg, size); #endif } CARLA_SAFE_EXCEPTION_RETURN("CarlaPipeCommon::writeMsgBuffer", false); - return (ret == static_cast(size)); + if (ret == static_cast(size)) + return true; + + fprintf(stderr, "CarlaPipeCommon::_writeMsgBuffer(..., " P_SIZE ") - failed with " P_SSIZE ". Message was:\n%s", + size, ret, msg); + return false; } // ----------------------------------------------------------------------- @@ -1146,70 +1080,55 @@ bool CarlaPipeServer::startPipeServer(const char* const filename, CARLA_SAFE_ASSERT_RETURN(arg2 != nullptr, false); carla_debug("CarlaPipeServer::startPipeServer(\"%s\", \"%s\", \"%s\")", filename, arg1, arg2); + char pipeRecvServerStr[100+1]; + char pipeSendServerStr[100+1]; + char pipeRecvClientStr[100+1]; + char pipeSendClientStr[100+1]; + + pipeRecvServerStr[100] = '\0'; + pipeSendServerStr[100] = '\0'; + pipeRecvClientStr[100] = '\0'; + pipeSendClientStr[100] = '\0'; + const CarlaMutexLocker cml(pData->writeLock); //---------------------------------------------------------------- // create pipes #ifdef CARLA_OS_WIN - HANDLE pipe1[2]; // read by server, written by client - HANDLE pipe2[2]; // read by client, written by server - - SECURITY_ATTRIBUTES sa; - carla_zeroStruct(sa); - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = TRUE; + HANDLE pipe1, pipe2; std::srand(static_cast(std::time(nullptr))); - char strBuf[0xff+1]; - strBuf[0xff] = '\0'; - static ulong sCounter = 0; ++sCounter; const int randint = std::rand(); - std::snprintf(strBuf, 0xff, "\\\\.\\pipe\\carla-pipe1-%i-%li", randint, sCounter); - pipe1[0] = ::CreateNamedPipeA(strBuf, PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE|PIPE_WAIT, 1, 4096, 4096, 300, &sa); - pipe1[1] = ::CreateFileA(strBuf, GENERIC_WRITE, 0x0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, nullptr); + std::snprintf(pipeRecvServerStr, 100, "\\\\.\\pipe\\carla-pipe1-%i-%li", randint, sCounter); + std::snprintf(pipeSendServerStr, 100, "\\\\.\\pipe\\carla-pipe2-%i-%li", randint, sCounter); + std::snprintf(pipeRecvClientStr, 100, "ignored"); + std::snprintf(pipeSendClientStr, 100, "ignored"); - std::snprintf(strBuf, 0xff, "\\\\.\\pipe\\carla-pipe2-%i-%li", randint, sCounter); - pipe2[0] = ::CreateNamedPipeA(strBuf, PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE|PIPE_WAIT, 1, 4096, 4096, 300, &sa); - pipe2[1] = ::CreateFileA(strBuf, GENERIC_WRITE, 0x0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, nullptr); + pipe1 = ::CreateNamedPipeA(pipeRecvServerStr, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_NOWAIT, 2, size, size, 0, nullptr); -#if 0 - std::snprintf(strBuf, 0xff, "\\\\.\\pipe\\carla-pipe1-%i-%li", randint, sCounter); - pipe1[1] = ::CreateNamedPipeA(strBuf, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE|PIPE_NOWAIT, 1, 4096, 4096, 120*1000, &sa); - pipe1[0] = ::CreateFileA(strBuf, GENERIC_READ, 0x0, &sa, OPEN_EXISTING, 0x0, nullptr); + if (pipe1 == INVALID_HANDLE_VALUE) + { + fail("pipe creation failed"); + return false; + } - std::snprintf(strBuf, 0xff, "\\\\.\\pipe\\carla-pipe2-%i-%li", randint, sCounter); - pipe2[0] = ::CreateNamedPipeA(strBuf, PIPE_ACCESS_INBOUND, PIPE_TYPE_BYTE|PIPE_NOWAIT, 1, 4096, 4096, 120*1000, &sa); // NB - pipe2[1] = ::CreateFileA(strBuf, GENERIC_WRITE, 0x0, &sa, OPEN_EXISTING, 0x0, nullptr); -#endif + pipe2 = ::CreateNamedPipeA(pipeSendServerStr, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_NOWAIT, 2, size, size, 0, nullptr); - if (pipe1[0] == INVALID_HANDLE_VALUE || pipe1[1] == INVALID_HANDLE_VALUE || pipe2[0] == INVALID_HANDLE_VALUE || pipe2[1] == INVALID_HANDLE_VALUE) + if (pipe2 == INVALID_HANDLE_VALUE) { - if (pipe1[0] != INVALID_HANDLE_VALUE) { - try { ::CloseHandle(pipe1[0]); } CARLA_SAFE_EXCEPTION("CloseHandle(pipe1[0])"); - } - if (pipe1[1] != INVALID_HANDLE_VALUE) { - try { ::CloseHandle(pipe1[1]); } CARLA_SAFE_EXCEPTION("CloseHandle(pipe1[1])"); - } - if (pipe2[0] != INVALID_HANDLE_VALUE) { - try { ::CloseHandle(pipe2[0]); } CARLA_SAFE_EXCEPTION("CloseHandle(pipe2[0])"); - } - if (pipe2[1] != INVALID_HANDLE_VALUE) { - try { ::CloseHandle(pipe2[1]); } CARLA_SAFE_EXCEPTION("CloseHandle(pipe2[1])"); - } + try { ::CloseHandle(pipe1); } CARLA_SAFE_EXCEPTION("CloseHandle(pipe1)"); fail("pipe creation failed"); return false; } - HANDLE pipeRecvServer = pipe1[0]; - HANDLE pipeRecvClient = pipe2[0]; - HANDLE pipeSendClient = pipe1[1]; - HANDLE pipeSendServer = pipe2[1]; + const HANDLE pipeRecvClient = pipe2; + const HANDLE pipeSendClient = pipe1; #else int pipe1[2]; // read by server, written by client int pipe2[2]; // read by client, written by server @@ -1228,10 +1147,57 @@ bool CarlaPipeServer::startPipeServer(const char* const filename, return false; } - int pipeRecvServer = pipe1[0]; - int pipeRecvClient = pipe2[0]; - int pipeSendClient = pipe1[1]; - int pipeSendServer = pipe2[1]; + /* */ int pipeRecvServer = pipe1[0]; + /* */ int pipeSendServer = pipe2[1]; + const int pipeRecvClient = pipe2[0]; + const int pipeSendClient = pipe1[1]; + + std::snprintf(pipeRecvServerStr, 100, "%i", pipeRecvServer); + std::snprintf(pipeSendServerStr, 100, "%i", pipeSendServer); + std::snprintf(pipeRecvClientStr, 100, "%i", pipeRecvClient); + std::snprintf(pipeSendClientStr, 100, "%i", pipeSendClient); + + //---------------------------------------------------------------- + // set size, non-fatal + + try { + ::fcntl(pipeRecvClient, F_SETPIPE_SZ, size); + } CARLA_SAFE_EXCEPTION("Set pipe size"); + + try { + ::fcntl(pipeRecvServer, F_SETPIPE_SZ, size); + } CARLA_SAFE_EXCEPTION("Set pipe size"); + + //---------------------------------------------------------------- + // set non-block + + int ret; + + try { + ret = ::fcntl(pipeRecvClient, F_SETFL, ::fcntl(pipeRecvClient, F_GETFL) | O_NONBLOCK); + } catch (...) { + ret = -1; + fail("failed to set pipe as non-block"); + } + + if (ret == 0) + { + try { + ret = ::fcntl(pipeRecvServer, F_SETFL, ::fcntl(pipeRecvServer, F_GETFL) | O_NONBLOCK); + } catch (...) { + ret = -1; + fail("failed to set pipe as non-block"); + } + } + + if (ret < 0) + { + try { ::close(pipe1[0]); } CARLA_SAFE_EXCEPTION("close(pipe1[0])"); + try { ::close(pipe1[1]); } CARLA_SAFE_EXCEPTION("close(pipe1[1])"); + try { ::close(pipe2[0]); } CARLA_SAFE_EXCEPTION("close(pipe2[0])"); + try { ::close(pipe2[1]); } CARLA_SAFE_EXCEPTION("close(pipe2[1])"); + return false; + } #endif //---------------------------------------------------------------- @@ -1253,25 +1219,10 @@ bool CarlaPipeServer::startPipeServer(const char* const filename, //---------------------------------------------------------------- // argv[3-6] => pipes - char pipeRecvServerStr[100+1]; - char pipeRecvClientStr[100+1]; - char pipeSendServerStr[100+1]; - char pipeSendClientStr[100+1]; - - std::snprintf(pipeRecvServerStr, 100, P_INTPTR, (intptr_t)pipeRecvServer); // pipe1[0] - std::snprintf(pipeRecvClientStr, 100, P_INTPTR, (intptr_t)pipeRecvClient); // pipe2[0] - std::snprintf(pipeSendServerStr, 100, P_INTPTR, (intptr_t)pipeSendServer); // pipe2[1] - std::snprintf(pipeSendClientStr, 100, P_INTPTR, (intptr_t)pipeSendClient); // pipe1[1] - - pipeRecvServerStr[100] = '\0'; - pipeRecvClientStr[100] = '\0'; - pipeSendServerStr[100] = '\0'; - pipeSendClientStr[100] = '\0'; - - argv[3] = pipeRecvServerStr; // pipe1[0] close READ - argv[4] = pipeRecvClientStr; // pipe2[0] READ - argv[5] = pipeSendServerStr; // pipe2[1] close SEND - argv[6] = pipeSendClientStr; // pipe1[1] SEND + argv[3] = pipeRecvServerStr; + argv[4] = pipeSendServerStr; + argv[5] = pipeRecvClientStr; + argv[6] = pipeSendClientStr; //---------------------------------------------------------------- // argv[7] => null @@ -1287,17 +1238,15 @@ bool CarlaPipeServer::startPipeServer(const char* const filename, carla_zeroStruct(pData->processInfo); pData->processInfo.hProcess = INVALID_HANDLE_VALUE; pData->processInfo.hThread = INVALID_HANDLE_VALUE; - try { ::CloseHandle(pipe1[0]); } CARLA_SAFE_EXCEPTION("CloseHandle(pipe1[0])"); - try { ::CloseHandle(pipe1[1]); } CARLA_SAFE_EXCEPTION("CloseHandle(pipe1[1])"); - try { ::CloseHandle(pipe2[0]); } CARLA_SAFE_EXCEPTION("CloseHandle(pipe2[0])"); - try { ::CloseHandle(pipe2[1]); } CARLA_SAFE_EXCEPTION("CloseHandle(pipe2[1])"); + try { ::CloseHandle(pipe1); } CARLA_SAFE_EXCEPTION("CloseHandle(pipe1)"); + try { ::CloseHandle(pipe2); } CARLA_SAFE_EXCEPTION("CloseHandle(pipe2)"); fail("startProcess() failed"); return false; } // just to make sure - CARLA_SAFE_ASSERT(pData->processInfo.hThread != nullptr); - CARLA_SAFE_ASSERT(pData->processInfo.hProcess != nullptr); + CARLA_SAFE_ASSERT(pData->processInfo.hThread != INVALID_HANDLE_VALUE); + CARLA_SAFE_ASSERT(pData->processInfo.hProcess != INVALID_HANDLE_VALUE); #else if (! startProcess(argv, pData->pid)) { @@ -1309,58 +1258,23 @@ bool CarlaPipeServer::startPipeServer(const char* const filename, fail("startProcess() failed"); return false; } -#endif //---------------------------------------------------------------- // close duplicated handles used by the client -#ifdef CARLA_OS_WIN - try { ::CloseHandle(pipeRecvServer); } CARLA_SAFE_EXCEPTION("CloseHandle(pipeRecvServer)"); - try { ::CloseHandle(pipeSendServer); } CARLA_SAFE_EXCEPTION("CloseHandle(pipeSendServer)"); -#else - try { ::close (pipeRecvServer); } CARLA_SAFE_EXCEPTION("close(pipeRecvServer)"); - try { ::close (pipeSendServer); } CARLA_SAFE_EXCEPTION("close(pipeSendServer)"); -#endif + try { ::close(pipeRecvServer); } CARLA_SAFE_EXCEPTION("close(pipeRecvServer)"); + try { ::close(pipeSendServer); } CARLA_SAFE_EXCEPTION("close(pipeSendServer)"); pipeRecvServer = pipeSendServer = INVALID_PIPE_VALUE; - -#ifndef CARLA_OS_WIN - int ret; - - //---------------------------------------------------------------- - // set size - - if (size > 4096) - { - try { - ::fcntl(pipeRecvClient, F_SETPIPE_SZ, size); - } catch (...) { - // non-fatal - } - } - - //---------------------------------------------------------------- - // set non-block reading - - try { - ret = ::fcntl(pipeRecvClient, F_SETFL, ::fcntl(pipeRecvClient, F_GETFL) | O_NONBLOCK); - } catch (...) { - ret = -1; - fail("failed to set pipe as non-block"); - } #endif //---------------------------------------------------------------- // wait for client to say something + if (waitForClientFirstMessage(pipeRecvClient, 10*1000 /* 10 secs */)) + { #ifdef CARLA_OS_WIN - struct { HANDLE handle; HANDLE cancel; } pipe; - pipe.handle = pipeRecvClient; - pipe.cancel = pData->cancelEvent; - if ( waitForClientFirstMessage(pipe, 10*1000 /* 10 secs */)) -#else - if (ret != -1 && waitForClientFirstMessage(pipeRecvClient, 10*1000 /* 10 secs */)) + CARLA_SAFE_ASSERT(waitForClientConnect(pipeSendClient, 1000 /* 1 sec */)); #endif - { pData->pipeRecv = pipeRecvClient; pData->pipeSend = pipeSendClient; carla_stdout("ALL OK!"); @@ -1371,7 +1285,7 @@ bool CarlaPipeServer::startPipeServer(const char* const filename, // failed to set non-block or get first child message, cannot continue #ifdef CARLA_OS_WIN - if (TerminateProcess(pData->processInfo.hProcess, 0) != FALSE) + if (TerminateProcess(pData->processInfo.hProcess, 9) != FALSE) { // wait for process to stop waitForProcessToStop(pData->processInfo, 2*1000); @@ -1396,11 +1310,11 @@ bool CarlaPipeServer::startPipeServer(const char* const filename, // close pipes #ifdef CARLA_OS_WIN - try { ::CloseHandle(pipeRecvServer); } CARLA_SAFE_EXCEPTION("CloseHandle(pipeRecvServer)"); - try { ::CloseHandle(pipeSendServer); } CARLA_SAFE_EXCEPTION("CloseHandle(pipeSendServer)"); + try { ::CloseHandle(pipeRecvClient); } CARLA_SAFE_EXCEPTION("CloseHandle(pipeRecvClient)"); + try { ::CloseHandle(pipeSendClient); } CARLA_SAFE_EXCEPTION("CloseHandle(pipeSendClient)"); #else - try { ::close (pipeRecvServer); } CARLA_SAFE_EXCEPTION("close(pipeRecvServer)"); - try { ::close (pipeSendServer); } CARLA_SAFE_EXCEPTION("close(pipeSendServer)"); + try { ::close (pipeRecvClient); } CARLA_SAFE_EXCEPTION("close(pipeRecvClient)"); + try { ::close (pipeSendClient); } CARLA_SAFE_EXCEPTION("close(pipeSendClient)"); #endif return false; @@ -1411,12 +1325,15 @@ void CarlaPipeServer::stopPipeServer(const uint32_t timeOutMilliseconds) noexcep carla_debug("CarlaPipeServer::stopPipeServer(%i)", timeOutMilliseconds); #ifdef CARLA_OS_WIN - if (pData->processInfo.hProcess != INVALID_HANDLE_VALUE) + if (pData->processInfo.hThread != INVALID_HANDLE_VALUE || pData->processInfo.hProcess != INVALID_HANDLE_VALUE) { const CarlaMutexLocker cml(pData->writeLock); if (pData->pipeSend != INVALID_PIPE_VALUE) + { _writeMsgBuffer("quit\n", 5); + flushMessages(); + } waitForProcessToStopOrKillIt(pData->processInfo, timeOutMilliseconds); try { CloseHandle(pData->processInfo.hThread); } CARLA_SAFE_EXCEPTION("CloseHandle(pData->processInfo.hThread)"); @@ -1431,7 +1348,10 @@ void CarlaPipeServer::stopPipeServer(const uint32_t timeOutMilliseconds) noexcep const CarlaMutexLocker cml(pData->writeLock); if (pData->pipeSend != INVALID_PIPE_VALUE) + { _writeMsgBuffer("quit\n", 5); + flushMessages(); + } waitForChildToStopOrKillIt(pData->pid, timeOutMilliseconds); pData->pid = -1; @@ -1450,6 +1370,8 @@ void CarlaPipeServer::closePipeServer() noexcept if (pData->pipeRecv != INVALID_PIPE_VALUE) { #ifdef CARLA_OS_WIN + DisconnectNamedPipe(pData->pipeRecv); + try { ::CloseHandle(pData->pipeRecv); } CARLA_SAFE_EXCEPTION("CloseHandle(pData->pipeRecv)"); #else try { ::close (pData->pipeRecv); } CARLA_SAFE_EXCEPTION("close(pData->pipeRecv)"); @@ -1460,6 +1382,8 @@ void CarlaPipeServer::closePipeServer() noexcept if (pData->pipeSend != INVALID_PIPE_VALUE) { #ifdef CARLA_OS_WIN + DisconnectNamedPipe(pData->pipeSend); + try { ::CloseHandle(pData->pipeSend); } CARLA_SAFE_EXCEPTION("CloseHandle(pData->pipeSend)"); #else try { ::close (pData->pipeSend); } CARLA_SAFE_EXCEPTION("close(pData->pipeSend)"); @@ -1516,51 +1440,31 @@ bool CarlaPipeClient::initPipeClient(const char* argv[]) noexcept // read arguments #ifdef CARLA_OS_WIN - HANDLE pipeRecvServer = (HANDLE)std::atoll(argv[3]); // READ - HANDLE pipeRecvClient = (HANDLE)std::atoll(argv[4]); - HANDLE pipeSendServer = (HANDLE)std::atoll(argv[5]); // SEND - HANDLE pipeSendClient = (HANDLE)std::atoll(argv[6]); + const char* const pipeRecvServerStr = argv[3]; + const char* const pipeSendServerStr = argv[4]; + + HANDLE pipeRecvServer = ::CreateFileA(pipeRecvServerStr, GENERIC_READ, 0x0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + HANDLE pipeSendServer = ::CreateFileA(pipeSendServerStr, GENERIC_WRITE, 0x0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); CARLA_SAFE_ASSERT_RETURN(pipeRecvServer != INVALID_HANDLE_VALUE, false); - CARLA_SAFE_ASSERT_RETURN(pipeRecvClient != INVALID_HANDLE_VALUE, false); CARLA_SAFE_ASSERT_RETURN(pipeSendServer != INVALID_HANDLE_VALUE, false); - CARLA_SAFE_ASSERT_RETURN(pipeSendClient != INVALID_HANDLE_VALUE, false); #else - int pipeRecvServer = std::atoi(argv[3]); // READ - int pipeRecvClient = std::atoi(argv[4]); - int pipeSendServer = std::atoi(argv[5]); // SEND - int pipeSendClient = std::atoi(argv[6]); + const int pipeRecvServer = std::atoi(argv[3]); + const int pipeSendServer = std::atoi(argv[4]); + /* */ int pipeRecvClient = std::atoi(argv[5]); + /* */ int pipeSendClient = std::atoi(argv[6]); CARLA_SAFE_ASSERT_RETURN(pipeRecvServer > 0, false); - CARLA_SAFE_ASSERT_RETURN(pipeRecvClient > 0, false); CARLA_SAFE_ASSERT_RETURN(pipeSendServer > 0, false); + CARLA_SAFE_ASSERT_RETURN(pipeRecvClient > 0, false); CARLA_SAFE_ASSERT_RETURN(pipeSendClient > 0, false); -#endif //---------------------------------------------------------------- // close duplicated handles used by the client -#ifdef CARLA_OS_WIN - try { ::CloseHandle(pipeRecvClient); } CARLA_SAFE_EXCEPTION("CloseHandle(pipeRecvClient)"); - try { ::CloseHandle(pipeSendClient); } CARLA_SAFE_EXCEPTION("CloseHandle(pipeSendClient)"); -#else - try { ::close (pipeRecvClient); } CARLA_SAFE_EXCEPTION("close(pipeRecvClient)"); - try { ::close (pipeSendClient); } CARLA_SAFE_EXCEPTION("close(pipeSendClient)"); -#endif + try { ::close(pipeRecvClient); } CARLA_SAFE_EXCEPTION("close(pipeRecvClient)"); + try { ::close(pipeSendClient); } CARLA_SAFE_EXCEPTION("close(pipeSendClient)"); pipeRecvClient = pipeSendClient = INVALID_PIPE_VALUE; - -#ifndef CARLA_OS_WIN - //---------------------------------------------------------------- - // set non-block reading - - int ret = 0; - - try { - ret = ::fcntl(pipeRecvServer, F_SETFL, ::fcntl(pipeRecvServer, F_GETFL) | O_NONBLOCK); - } catch (...) { - ret = -1; - } - CARLA_SAFE_ASSERT_RETURN(ret != -1, false); #endif //----------------------------------------------------------------