jack2 codebase
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.

185 lines
4.6KB

  1. /*
  2. * Copyright (C) 2004 Rui Nuno Capela, Steve Harris
  3. * Copyright (C) 2008 Nedko Arnaudov
  4. * Copyright (C) 2008 Grame
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation; either version 2.1 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19. *
  20. */
  21. #include "JackMessageBuffer.h"
  22. #include "JackGlobals.h"
  23. #include "JackError.h"
  24. namespace Jack
  25. {
  26. JackMessageBuffer* JackMessageBuffer::fInstance = NULL;
  27. JackMessageBuffer::JackMessageBuffer()
  28. :fInit(NULL),
  29. fInitArg(NULL),
  30. fThread(this),
  31. fGuard(),
  32. fInBuffer(0),
  33. fOutBuffer(0),
  34. fOverruns(0),
  35. fRunning(false)
  36. {}
  37. JackMessageBuffer::~JackMessageBuffer()
  38. {}
  39. bool JackMessageBuffer::Start()
  40. {
  41. // Before StartSync()...
  42. fRunning = true;
  43. if (fThread.StartSync() == 0) {
  44. return true;
  45. } else {
  46. fRunning = false;
  47. return false;
  48. }
  49. }
  50. bool JackMessageBuffer::Stop()
  51. {
  52. if (fOverruns > 0) {
  53. jack_error("WARNING: %d message buffer overruns!", fOverruns);
  54. } else {
  55. jack_log("no message buffer overruns");
  56. }
  57. if (fGuard.Lock()) {
  58. fRunning = false;
  59. fGuard.Signal();
  60. fGuard.Unlock();
  61. fThread.Stop();
  62. } else {
  63. fThread.Kill();
  64. }
  65. Flush();
  66. return true;
  67. }
  68. void JackMessageBuffer::Flush()
  69. {
  70. while (fOutBuffer != fInBuffer) {
  71. jack_log_function(fBuffers[fOutBuffer].level, fBuffers[fOutBuffer].message);
  72. fOutBuffer = MB_NEXT(fOutBuffer);
  73. }
  74. }
  75. void JackMessageBuffer::AddMessage(int level, const char *message)
  76. {
  77. if (fGuard.Trylock()) {
  78. fBuffers[fInBuffer].level = level;
  79. strncpy(fBuffers[fInBuffer].message, message, MB_BUFFERSIZE);
  80. fInBuffer = MB_NEXT(fInBuffer);
  81. fGuard.Signal();
  82. fGuard.Unlock();
  83. } else { /* lock collision */
  84. INC_ATOMIC(&fOverruns);
  85. }
  86. }
  87. bool JackMessageBuffer::Execute()
  88. {
  89. if (fGuard.Lock()) {
  90. while (fRunning) {
  91. fGuard.Wait();
  92. /* the client asked for all threads to run a thread
  93. initialization callback, which includes us.
  94. */
  95. if (fInit) {
  96. fInit(fInitArg);
  97. fInit = NULL;
  98. /* and we're done */
  99. fGuard.Signal();
  100. }
  101. /* releasing the mutex reduces contention */
  102. fGuard.Unlock();
  103. Flush();
  104. fGuard.Lock();
  105. }
  106. fGuard.Unlock();
  107. } else {
  108. jack_error("JackMessageBuffer::Execute lock cannot be taken");
  109. }
  110. return false;
  111. }
  112. bool JackMessageBuffer::Create()
  113. {
  114. if (fInstance == NULL) {
  115. fInstance = new JackMessageBuffer();
  116. if (!fInstance->Start()) {
  117. jack_error("JackMessageBuffer::Create cannot start thread");
  118. delete fInstance;
  119. fInstance = NULL;
  120. return false;
  121. }
  122. }
  123. return true;
  124. }
  125. bool JackMessageBuffer::Destroy()
  126. {
  127. if (fInstance != NULL) {
  128. fInstance->Stop();
  129. delete fInstance;
  130. fInstance = NULL;
  131. return true;
  132. } else {
  133. return false;
  134. }
  135. }
  136. void JackMessageBufferAdd(int level, const char *message)
  137. {
  138. if (Jack::JackMessageBuffer::fInstance == NULL) {
  139. /* Unable to print message with realtime safety. Complain and print it anyway. */
  140. jack_log_function(LOG_LEVEL_ERROR, "messagebuffer not initialized, skip message");
  141. } else {
  142. Jack::JackMessageBuffer::fInstance->AddMessage(level, message);
  143. }
  144. }
  145. int JackMessageBuffer::SetInitCallback(JackThreadInitCallback callback, void *arg)
  146. {
  147. if (fInstance && callback && fRunning && fGuard.Lock()) {
  148. /* set up the callback */
  149. fInitArg = arg;
  150. fInit = callback;
  151. /* wake msg buffer thread */
  152. fGuard.Signal();
  153. /* wait for it to be done */
  154. fGuard.Wait();
  155. /* and we're done */
  156. fGuard.Unlock();
  157. return 0;
  158. } else {
  159. jack_error("JackMessageBuffer::SetInitCallback : callback cannot be executed");
  160. return -1;
  161. }
  162. }
  163. };