Jack2
1.9.8
|
00001 /* 00002 * Copyright (C) 2004 Rui Nuno Capela, Steve Harris 00003 * Copyright (C) 2008 Nedko Arnaudov 00004 * Copyright (C) 2008 Grame 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as published by 00008 * the Free Software Foundation; either version 2.1 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00019 * 00020 */ 00021 00022 #include "JackMessageBuffer.h" 00023 #include "JackGlobals.h" 00024 #include "JackError.h" 00025 00026 namespace Jack 00027 { 00028 00029 JackMessageBuffer* JackMessageBuffer::fInstance = NULL; 00030 00031 JackMessageBuffer::JackMessageBuffer() 00032 :fInit(NULL),fInitArg(NULL),fThread(this),fInBuffer(0),fOutBuffer(0),fOverruns(0),fRunning(false) 00033 {} 00034 00035 JackMessageBuffer::~JackMessageBuffer() 00036 {} 00037 00038 void JackMessageBuffer::Start() 00039 { 00040 fRunning = true; 00041 fThread.StartSync(); 00042 } 00043 00044 void JackMessageBuffer::Stop() 00045 { 00046 if (fOverruns > 0) { 00047 jack_error("WARNING: %d message buffer overruns!", fOverruns); 00048 } else { 00049 jack_log("no message buffer overruns"); 00050 } 00051 00052 if (fGuard.Lock()) { 00053 fRunning = false; 00054 fGuard.Signal(); 00055 fGuard.Unlock(); 00056 fThread.Stop(); 00057 } else { 00058 fThread.Kill(); 00059 } 00060 00061 Flush(); 00062 } 00063 00064 void JackMessageBuffer::Flush() 00065 { 00066 while (fOutBuffer != fInBuffer) { 00067 jack_log_function(fBuffers[fOutBuffer].level, fBuffers[fOutBuffer].message); 00068 fOutBuffer = MB_NEXT(fOutBuffer); 00069 } 00070 } 00071 00072 void JackMessageBuffer::AddMessage(int level, const char *message) 00073 { 00074 if (fGuard.Trylock()) { 00075 fBuffers[fInBuffer].level = level; 00076 strncpy(fBuffers[fInBuffer].message, message, MB_BUFFERSIZE); 00077 fInBuffer = MB_NEXT(fInBuffer); 00078 fGuard.Signal(); 00079 fGuard.Unlock(); 00080 } else { /* lock collision */ 00081 INC_ATOMIC(&fOverruns); 00082 } 00083 } 00084 00085 bool JackMessageBuffer::Execute() 00086 { 00087 if (fGuard.Lock()) { 00088 while (fRunning) { 00089 fGuard.Wait(); 00090 /* the client asked for all threads to run a thread 00091 initialization callback, which includes us. 00092 */ 00093 if (fInit) { 00094 fInit(fInitArg); 00095 fInit = NULL; 00096 /* and we're done */ 00097 fGuard.Signal(); 00098 } 00099 00100 /* releasing the mutex reduces contention */ 00101 fGuard.Unlock(); 00102 Flush(); 00103 fGuard.Lock(); 00104 } 00105 fGuard.Unlock(); 00106 } else { 00107 jack_error("JackMessageBuffer::Execute lock cannot be taken"); 00108 } 00109 00110 return false; 00111 } 00112 00113 void JackMessageBuffer::Create() 00114 { 00115 if (fInstance == NULL) { 00116 fInstance = new JackMessageBuffer(); 00117 fInstance->Start(); 00118 } 00119 } 00120 00121 void JackMessageBuffer::Destroy() 00122 { 00123 if (fInstance != NULL) { 00124 fInstance->Stop(); 00125 delete fInstance; 00126 fInstance = NULL; 00127 } 00128 } 00129 00130 void JackMessageBufferAdd(int level, const char *message) 00131 { 00132 if (Jack::JackMessageBuffer::fInstance == NULL) { 00133 /* Unable to print message with realtime safety. Complain and print it anyway. */ 00134 jack_log_function(LOG_LEVEL_ERROR, "messagebuffer not initialized, skip message"); 00135 } else { 00136 Jack::JackMessageBuffer::fInstance->AddMessage(level, message); 00137 } 00138 } 00139 00140 void JackMessageBuffer::SetInitCallback(JackThreadInitCallback callback, void *arg) 00141 { 00142 if (fGuard.Lock()) { 00143 /* set up the callback */ 00144 fInitArg = arg; 00145 fInit = callback; 00146 /* wake msg buffer thread */ 00147 fGuard.Signal(); 00148 /* wait for it to be done */ 00149 fGuard.Wait(); 00150 /* and we're done */ 00151 fGuard.Unlock(); 00152 } else { 00153 jack_error("JackMessageBuffer::SetInitCallback lock cannot be taken"); 00154 } 00155 } 00156 00157 }; 00158