Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

229 lines
5.7KB

  1. /*
  2. * Carla Log Thread
  3. * Copyright (C) 2013-2016 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #ifndef CARLA_LOG_THREAD_HPP_INCLUDED
  18. #define CARLA_LOG_THREAD_HPP_INCLUDED
  19. #include "CarlaBackend.h"
  20. #include "CarlaString.hpp"
  21. #include "CarlaThread.hpp"
  22. #include <fcntl.h>
  23. #ifdef CARLA_OS_WIN
  24. # include <io.h>
  25. # define _close(fd) close(fd)
  26. # define _dup2(f1,f2) dup2(f1,f2)
  27. #endif
  28. using CarlaBackend::EngineCallbackFunc;
  29. // -----------------------------------------------------------------------
  30. // Log thread
  31. class CarlaLogThread : private CarlaThread
  32. {
  33. public:
  34. CarlaLogThread()
  35. : CarlaThread("CarlaLogThread"),
  36. fStdOut(-1),
  37. fStdErr(-1),
  38. fCallback(nullptr),
  39. fCallbackPtr(nullptr) {}
  40. ~CarlaLogThread()
  41. {
  42. stop();
  43. }
  44. void init()
  45. {
  46. std::fflush(stdout);
  47. std::fflush(stderr);
  48. #ifdef CARLA_OS_WIN
  49. // TODO: use process id instead
  50. const int randint = std::rand();
  51. char strBuf[0xff+1];
  52. strBuf[0xff] = '\0';
  53. std::snprintf(strBuf, 0xff, "\\\\.\\pipe\\carlalogthread-%i", randint);
  54. fPipe[0] = CreateNamedPipeA(strBuf, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_NOWAIT, 2, 4096, 4096, 0, nullptr);
  55. fPipe[1] = CreateFileA(strBuf, GENERIC_WRITE, 0x0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
  56. CARLA_SAFE_ASSERT_RETURN(fPipe[0] != INVALID_HANDLE_VALUE,);
  57. CARLA_SAFE_ASSERT_RETURN(fPipe[1] != INVALID_HANDLE_VALUE,);
  58. const int pipe1 = _open_osfhandle((INT_PTR)fPipe[1], _O_WRONLY | _O_BINARY);
  59. #else
  60. CARLA_SAFE_ASSERT_RETURN(pipe(fPipe) == 0,);
  61. if (fcntl(fPipe[0], F_SETFL, O_NONBLOCK) != 0)
  62. {
  63. close(fPipe[0]);
  64. close(fPipe[1]);
  65. return;
  66. }
  67. const int pipe1 = fPipe[1];
  68. #endif
  69. fStdOut = dup(STDOUT_FILENO);
  70. fStdErr = dup(STDERR_FILENO);
  71. dup2(pipe1, STDOUT_FILENO);
  72. dup2(pipe1, STDERR_FILENO);
  73. startThread();
  74. }
  75. void stop()
  76. {
  77. if (fStdOut == -1)
  78. return;
  79. stopThread(5000);
  80. std::fflush(stdout);
  81. std::fflush(stderr);
  82. #ifdef CARLA_OS_WIN
  83. CloseHandle(fPipe[0]);
  84. CloseHandle(fPipe[1]);
  85. #else
  86. close(fPipe[0]);
  87. close(fPipe[1]);
  88. #endif
  89. dup2(fStdOut, STDOUT_FILENO);
  90. dup2(fStdErr, STDERR_FILENO);
  91. close(fStdOut);
  92. close(fStdErr);
  93. fStdOut = -1;
  94. fStdErr = -1;
  95. }
  96. void setCallback(EngineCallbackFunc callback, void* callbackPtr)
  97. {
  98. CARLA_SAFE_ASSERT_RETURN(callback != nullptr,);
  99. fCallback = callback;
  100. fCallbackPtr = callbackPtr;
  101. }
  102. protected:
  103. void run()
  104. {
  105. CARLA_SAFE_ASSERT_RETURN(fCallback != nullptr,);
  106. size_t k, bufTempPos;
  107. ssize_t r, lastRead;
  108. char bufTemp[1024+1];
  109. char bufRead[1024+1];
  110. char bufSend[2048+1];
  111. bufTemp[0] = '\0';
  112. bufTempPos = 0;
  113. while (! shouldThreadExit())
  114. {
  115. bufRead[0] = '\0';
  116. while ((r = read(fPipe[0], bufRead, 1024)) > 0)
  117. {
  118. CARLA_SAFE_ASSERT_CONTINUE(r <= 1024);
  119. bufRead[r] = '\0';
  120. lastRead = 0;
  121. for (ssize_t i=0; i<r; ++i)
  122. {
  123. CARLA_SAFE_ASSERT_BREAK(bufRead[i] != '\0');
  124. if (bufRead[i] != '\n')
  125. continue;
  126. k = static_cast<size_t>(i-lastRead);
  127. if (bufTempPos != 0)
  128. {
  129. std::memcpy(bufSend, bufTemp, bufTempPos);
  130. std::memcpy(bufSend+bufTempPos, bufRead+lastRead, k);
  131. k += bufTempPos;
  132. }
  133. else
  134. {
  135. std::memcpy(bufSend, bufRead+lastRead, k);
  136. }
  137. lastRead = i+1;
  138. bufSend[k] = '\0';
  139. bufTemp[0] = '\0';
  140. bufTempPos = 0;
  141. fCallback(fCallbackPtr, CarlaBackend::ENGINE_CALLBACK_DEBUG, 0, 0, 0, 0.0f, bufSend);
  142. }
  143. if (lastRead > 0 && lastRead != r)
  144. {
  145. k = static_cast<size_t>(r-lastRead);
  146. std::memcpy(bufTemp, bufRead+lastRead, k);
  147. bufTemp[k] = '\0';
  148. bufTempPos = k;
  149. }
  150. }
  151. carla_msleep(20);
  152. }
  153. }
  154. private:
  155. #ifdef CARLA_OS_WIN
  156. HANDLE fPipe[2];
  157. #else
  158. int fPipe[2];
  159. #endif
  160. int fStdOut;
  161. int fStdErr;
  162. EngineCallbackFunc fCallback;
  163. void* fCallbackPtr;
  164. #ifdef CARLA_OS_WIN
  165. ssize_t read(const HANDLE pipeh, void* const buf, DWORD numBytes)
  166. {
  167. if (ReadFile(pipeh, buf, numBytes, &numBytes, nullptr) != FALSE)
  168. return numBytes;
  169. return -1;
  170. }
  171. #endif
  172. //CARLA_PREVENT_HEAP_ALLOCATION
  173. CARLA_DECLARE_NON_COPY_CLASS(CarlaLogThread)
  174. };
  175. #ifdef CARLA_OS_WIN
  176. # undef close
  177. # undef dup2
  178. #endif
  179. // -----------------------------------------------------------------------
  180. #endif // CARLA_LOG_THREAD_HPP_INCLUDED