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.

241 lines
6.2KB

  1. /*
  2. * Carla Log Thread
  3. * Copyright (C) 2013-2023 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 _close
  26. # define dup _dup
  27. # define dup2 _dup2
  28. #endif
  29. using CARLA_BACKEND_NAMESPACE::EngineCallbackFunc;
  30. // -----------------------------------------------------------------------
  31. // Log thread
  32. class CarlaLogThread : private CarlaThread
  33. {
  34. public:
  35. CarlaLogThread()
  36. : CarlaThread("CarlaLogThread"),
  37. fStdOut(-1),
  38. fStdErr(-1),
  39. fCallback(nullptr),
  40. fCallbackPtr(nullptr) {}
  41. ~CarlaLogThread()
  42. {
  43. stop();
  44. }
  45. void init()
  46. {
  47. std::fflush(stdout);
  48. std::fflush(stderr);
  49. #ifdef CARLA_OS_WIN
  50. // TODO: use process id instead
  51. const int randint = std::rand();
  52. char strBuf[0xff+1];
  53. strBuf[0xff] = '\0';
  54. std::snprintf(strBuf, 0xff, "\\\\.\\pipe\\carlalogthread-%i", randint);
  55. fPipe[0] = CreateNamedPipeA(strBuf, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_NOWAIT, 2, 4096, 4096, 0, nullptr);
  56. fPipe[1] = CreateFileA(strBuf, GENERIC_WRITE, 0x0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
  57. CARLA_SAFE_ASSERT_RETURN(fPipe[0] != INVALID_HANDLE_VALUE,);
  58. CARLA_SAFE_ASSERT_RETURN(fPipe[1] != INVALID_HANDLE_VALUE,);
  59. const int pipe1 = _open_osfhandle((INT_PTR)fPipe[1], _O_WRONLY | _O_BINARY);
  60. const int stdout_fileno = _fileno(stdout);
  61. const int stderr_fileno = _fileno(stderr);
  62. #else
  63. CARLA_SAFE_ASSERT_RETURN(pipe(fPipe) == 0,);
  64. if (fcntl(fPipe[0], F_SETFL, O_NONBLOCK) != 0)
  65. {
  66. close(fPipe[0]);
  67. close(fPipe[1]);
  68. return;
  69. }
  70. const int pipe1 = fPipe[1];
  71. const int stdout_fileno = STDOUT_FILENO;
  72. const int stderr_fileno = STDERR_FILENO;
  73. #endif
  74. fStdOut = dup(stdout_fileno);
  75. fStdErr = dup(stderr_fileno);
  76. dup2(pipe1, stdout_fileno);
  77. dup2(pipe1, stderr_fileno);
  78. startThread();
  79. }
  80. void stop()
  81. {
  82. if (fStdOut == -1)
  83. return;
  84. stopThread(5000);
  85. std::fflush(stdout);
  86. std::fflush(stderr);
  87. #ifdef CARLA_OS_WIN
  88. CloseHandle(fPipe[0]);
  89. CloseHandle(fPipe[1]);
  90. const int stdout_fileno = _fileno(stdout);
  91. const int stderr_fileno = _fileno(stderr);
  92. #else
  93. close(fPipe[0]);
  94. close(fPipe[1]);
  95. const int stdout_fileno = STDOUT_FILENO;
  96. const int stderr_fileno = STDERR_FILENO;
  97. #endif
  98. dup2(fStdOut, stdout_fileno);
  99. dup2(fStdErr, stderr_fileno);
  100. close(fStdOut);
  101. close(fStdErr);
  102. fStdOut = -1;
  103. fStdErr = -1;
  104. }
  105. void setCallback(EngineCallbackFunc callback, void* callbackPtr)
  106. {
  107. CARLA_SAFE_ASSERT_RETURN(callback != nullptr,);
  108. fCallback = callback;
  109. fCallbackPtr = callbackPtr;
  110. }
  111. protected:
  112. void run()
  113. {
  114. CARLA_SAFE_ASSERT_RETURN(fCallback != nullptr,);
  115. size_t k, bufTempPos;
  116. ssize_t r, lastRead;
  117. char bufTemp[1024+1];
  118. char bufRead[1024+1];
  119. char bufSend[2048+1];
  120. bufTemp[0] = '\0';
  121. bufTempPos = 0;
  122. while (! shouldThreadExit())
  123. {
  124. bufRead[0] = '\0';
  125. while ((r = read(fPipe[0], bufRead, 1024)) > 0)
  126. {
  127. CARLA_SAFE_ASSERT_CONTINUE(r <= 1024);
  128. bufRead[r] = '\0';
  129. lastRead = 0;
  130. for (ssize_t i=0; i<r; ++i)
  131. {
  132. CARLA_SAFE_ASSERT_BREAK(bufRead[i] != '\0');
  133. if (bufRead[i] != '\n')
  134. continue;
  135. k = static_cast<size_t>(i-lastRead);
  136. if (bufTempPos != 0)
  137. {
  138. std::memcpy(bufSend, bufTemp, bufTempPos);
  139. std::memcpy(bufSend+bufTempPos, bufRead+lastRead, k);
  140. k += bufTempPos;
  141. }
  142. else
  143. {
  144. std::memcpy(bufSend, bufRead+lastRead, k);
  145. }
  146. lastRead = i+1;
  147. bufSend[k] = '\0';
  148. bufTemp[0] = '\0';
  149. bufTempPos = 0;
  150. fCallback(fCallbackPtr, CARLA_BACKEND_NAMESPACE::ENGINE_CALLBACK_DEBUG, 0, 0, 0, 0, 0.0f, bufSend);
  151. }
  152. if (lastRead > 0 && lastRead != r)
  153. {
  154. k = static_cast<size_t>(r-lastRead);
  155. std::memcpy(bufTemp, bufRead+lastRead, k);
  156. bufTemp[k] = '\0';
  157. bufTempPos = k;
  158. }
  159. }
  160. carla_msleep(20);
  161. }
  162. }
  163. private:
  164. #ifdef CARLA_OS_WIN
  165. HANDLE fPipe[2];
  166. #else
  167. int fPipe[2];
  168. #endif
  169. int fStdOut;
  170. int fStdErr;
  171. EngineCallbackFunc fCallback;
  172. void* fCallbackPtr;
  173. #ifdef CARLA_OS_WIN
  174. ssize_t read(const HANDLE pipeh, void* const buf, DWORD numBytes)
  175. {
  176. if (ReadFile(pipeh, buf, numBytes, &numBytes, nullptr) != FALSE)
  177. return numBytes;
  178. return -1;
  179. }
  180. #endif
  181. //CARLA_PREVENT_HEAP_ALLOCATION
  182. CARLA_DECLARE_NON_COPYABLE(CarlaLogThread)
  183. };
  184. #ifdef CARLA_OS_WIN
  185. # undef close
  186. # undef dup
  187. # undef dup2
  188. #endif
  189. // -----------------------------------------------------------------------
  190. #endif // CARLA_LOG_THREAD_HPP_INCLUDED