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.

181 lines
4.5KB

  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. if (fThread.StartSync() == 0) {
  42. fRunning = true;
  43. return true;
  44. } else {
  45. return false;
  46. }
  47. }
  48. bool JackMessageBuffer::Stop()
  49. {
  50. if (fOverruns > 0) {
  51. jack_error("WARNING: %d message buffer overruns!", fOverruns);
  52. } else {
  53. jack_log("no message buffer overruns");
  54. }
  55. if (fGuard.Lock()) {
  56. fRunning = false;
  57. fGuard.Signal();
  58. fGuard.Unlock();
  59. fThread.Stop();
  60. } else {
  61. fThread.Kill();
  62. }
  63. Flush();
  64. return true;
  65. }
  66. void JackMessageBuffer::Flush()
  67. {
  68. while (fOutBuffer != fInBuffer) {
  69. jack_log_function(fBuffers[fOutBuffer].level, fBuffers[fOutBuffer].message);
  70. fOutBuffer = MB_NEXT(fOutBuffer);
  71. }
  72. }
  73. void JackMessageBuffer::AddMessage(int level, const char *message)
  74. {
  75. if (fGuard.Trylock()) {
  76. fBuffers[fInBuffer].level = level;
  77. strncpy(fBuffers[fInBuffer].message, message, MB_BUFFERSIZE);
  78. fInBuffer = MB_NEXT(fInBuffer);
  79. fGuard.Signal();
  80. fGuard.Unlock();
  81. } else { /* lock collision */
  82. INC_ATOMIC(&fOverruns);
  83. }
  84. }
  85. bool JackMessageBuffer::Execute()
  86. {
  87. if (fGuard.Lock()) {
  88. while (fRunning) {
  89. fGuard.Wait();
  90. /* the client asked for all threads to run a thread
  91. initialization callback, which includes us.
  92. */
  93. if (fInit) {
  94. fInit(fInitArg);
  95. fInit = NULL;
  96. /* and we're done */
  97. fGuard.Signal();
  98. }
  99. /* releasing the mutex reduces contention */
  100. fGuard.Unlock();
  101. Flush();
  102. fGuard.Lock();
  103. }
  104. fGuard.Unlock();
  105. } else {
  106. jack_error("JackMessageBuffer::Execute lock cannot be taken");
  107. }
  108. return false;
  109. }
  110. bool JackMessageBuffer::Create()
  111. {
  112. if (fInstance == NULL) {
  113. fInstance = new JackMessageBuffer();
  114. if (!fInstance->Start()) {
  115. jack_error("JackMessageBuffer::Create cannot start thread");
  116. delete fInstance;
  117. fInstance = NULL;
  118. return false;
  119. }
  120. }
  121. return true;
  122. }
  123. bool JackMessageBuffer::Destroy()
  124. {
  125. if (fInstance != NULL) {
  126. fInstance->Stop();
  127. delete fInstance;
  128. fInstance = NULL;
  129. return true;
  130. } else {
  131. return false;
  132. }
  133. }
  134. void JackMessageBufferAdd(int level, const char *message)
  135. {
  136. if (Jack::JackMessageBuffer::fInstance == NULL) {
  137. /* Unable to print message with realtime safety. Complain and print it anyway. */
  138. jack_log_function(LOG_LEVEL_ERROR, "messagebuffer not initialized, skip message");
  139. } else {
  140. Jack::JackMessageBuffer::fInstance->AddMessage(level, message);
  141. }
  142. }
  143. void JackMessageBuffer::SetInitCallback(JackThreadInitCallback callback, void *arg)
  144. {
  145. if (fInstance && fInit && fRunning && fGuard.Lock()) {
  146. /* set up the callback */
  147. fInitArg = arg;
  148. fInit = callback;
  149. /* wake msg buffer thread */
  150. fGuard.Signal();
  151. /* wait for it to be done */
  152. fGuard.Wait();
  153. /* and we're done */
  154. fGuard.Unlock();
  155. } else {
  156. jack_error("JackMessageBuffer::SetInitCallback : callback cannot be executed");
  157. }
  158. }
  159. };