Browse Source

Rework pipe code, now working under win32; Enable pipe plugins

Hopefully doesn't break linux/osx stuff...
tags/1.9.7
falkTX 7 years ago
parent
commit
6ba82f32ed
11 changed files with 245 additions and 339 deletions
  1. +3
    -3
      source/backend/engine/CarlaEngineNative.cpp
  2. +1
    -1
      source/carla_app.py
  3. +4
    -1
      source/carla_utils.py
  4. +2
    -4
      source/externalui.py
  5. +9
    -3
      source/includes/CarlaDefines.h
  6. +4
    -1
      source/includes/CarlaNativeExtUI.hpp
  7. +0
    -6
      source/native-plugins/_all.c
  8. +0
    -6
      source/native-plugins/_data.cpp
  9. +10
    -6
      source/tests/CarlaPipeUtils.cpp
  10. +1
    -1
      source/tests/Makefile
  11. +211
    -307
      source/utils/CarlaPipeUtils.cpp

+ 3
- 3
source/backend/engine/CarlaEngineNative.cpp View File

@@ -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);


+ 1
- 1
source/carla_app.py View File

@@ -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)


+ 4
- 1
source/carla_utils.py View File

@@ -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))


+ 2
- 4
source/externalui.py View File

@@ -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)

+ 9
- 3
source/includes/CarlaDefines.h View File

@@ -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 */


+ 4
- 1
source/includes/CarlaNativeExtUI.hpp View File

@@ -1,6 +1,6 @@
/*
* Carla Native Plugin API (C++)
* Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com>
*
* 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


+ 0
- 6
source/native-plugins/_all.c View File

@@ -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


+ 0
- 6
source/native-plugins/_data.cpp View File

@@ -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<NativePluginHints>(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<NativePluginHints>(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<NativePluginHints>(NATIVE_PLUGIN_IS_RTSAFE
@@ -578,7 +573,6 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = {
/* copyright */ "GNU GPL v2+",
DESCFUNCS
},
#endif

// -----------------------------------------------------------------------
// ZynAddSubFX


+ 10
- 6
source/tests/CarlaPipeUtils.cpp View File

@@ -1,6 +1,6 @@
/*
* Carla Utility Tests
* Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
* Copyright (C) 2013-2016 Filipe Coelho <falktx@falktx.com>
*
* 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();


+ 1
- 1
source/tests/Makefile View File

@@ -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


+ 211
- 307
source/utils/CarlaPipeUtils.cpp View File

@@ -1,6 +1,6 @@
/*
* Carla Utility Tests
* Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
* Carla Pipe Utilities
* Copyright (C) 2013-2016 Filipe Coelho <falktx@falktx.com>
*
* 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 <clocale>
#include <ctime>
#include <fcntl.h>

#if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)
# include "juce_core/juce_core.h"
#else
# include <cerrno>
# include <fcntl.h>
# include <signal.h>
# include <sys/wait.h>
#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<ssize_t>(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<ssize_t>(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<ssize_t>(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<ssize_t>(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<ssize_t>(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<ssize_t>(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<LPWSTR>(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<typename P>
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<ssize_t>(size));
if (ret == static_cast<ssize_t>(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<uint>(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

//----------------------------------------------------------------


Loading…
Cancel
Save