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.

227 lines
5.6KB

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