Jack2 1.9.10
|
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 #include "JackTime.h" 00026 00027 namespace Jack 00028 { 00029 00030 JackMessageBuffer* JackMessageBuffer::fInstance = NULL; 00031 00032 JackMessageBuffer::JackMessageBuffer() 00033 :fInit(NULL), 00034 fInitArg(NULL), 00035 fThread(this), 00036 fGuard(), 00037 fInBuffer(0), 00038 fOutBuffer(0), 00039 fOverruns(0), 00040 fRunning(false) 00041 {} 00042 00043 JackMessageBuffer::~JackMessageBuffer() 00044 {} 00045 00046 bool JackMessageBuffer::Start() 00047 { 00048 // Before StartSync()... 00049 fRunning = true; 00050 if (fThread.StartSync() == 0) { 00051 return true; 00052 } else { 00053 fRunning = false; 00054 return false; 00055 } 00056 } 00057 00058 bool JackMessageBuffer::Stop() 00059 { 00060 if (fOverruns > 0) { 00061 jack_error("WARNING: %d message buffer overruns!", fOverruns); 00062 } else { 00063 jack_log("no message buffer overruns"); 00064 } 00065 00066 if (fGuard.Lock()) { 00067 fRunning = false; 00068 fGuard.Signal(); 00069 fGuard.Unlock(); 00070 fThread.Stop(); 00071 } else { 00072 fThread.Kill(); 00073 } 00074 00075 Flush(); 00076 return true; 00077 } 00078 00079 void JackMessageBuffer::Flush() 00080 { 00081 while (fOutBuffer != fInBuffer) { 00082 jack_log_function(fBuffers[fOutBuffer].level, fBuffers[fOutBuffer].message); 00083 fOutBuffer = MB_NEXT(fOutBuffer); 00084 } 00085 } 00086 00087 void JackMessageBuffer::AddMessage(int level, const char *message) 00088 { 00089 if (fGuard.Trylock()) { 00090 fBuffers[fInBuffer].level = level; 00091 strncpy(fBuffers[fInBuffer].message, message, MB_BUFFERSIZE); 00092 fInBuffer = MB_NEXT(fInBuffer); 00093 fGuard.Signal(); 00094 fGuard.Unlock(); 00095 } else { /* lock collision */ 00096 INC_ATOMIC(&fOverruns); 00097 } 00098 } 00099 00100 bool JackMessageBuffer::Execute() 00101 { 00102 if (fGuard.Lock()) { 00103 while (fRunning) { 00104 fGuard.Wait(); 00105 /* the client asked for all threads to run a thread 00106 initialization callback, which includes us. 00107 */ 00108 if (fInit) { 00109 fInit(fInitArg); 00110 fInit = NULL; 00111 /* and we're done */ 00112 fGuard.Signal(); 00113 } 00114 00115 /* releasing the mutex reduces contention */ 00116 fGuard.Unlock(); 00117 Flush(); 00118 fGuard.Lock(); 00119 } 00120 fGuard.Unlock(); 00121 } else { 00122 jack_error("JackMessageBuffer::Execute lock cannot be taken"); 00123 } 00124 00125 return false; 00126 } 00127 00128 bool JackMessageBuffer::Create() 00129 { 00130 if (fInstance == NULL) { 00131 fInstance = new JackMessageBuffer(); 00132 if (!fInstance->Start()) { 00133 jack_error("JackMessageBuffer::Create cannot start thread"); 00134 delete fInstance; 00135 fInstance = NULL; 00136 return false; 00137 } 00138 } 00139 00140 return true; 00141 } 00142 00143 bool JackMessageBuffer::Destroy() 00144 { 00145 if (fInstance != NULL) { 00146 fInstance->Stop(); 00147 delete fInstance; 00148 fInstance = NULL; 00149 return true; 00150 } else { 00151 return false; 00152 } 00153 } 00154 00155 void JackMessageBufferAdd(int level, const char *message) 00156 { 00157 if (Jack::JackMessageBuffer::fInstance == NULL) { 00158 /* Unable to print message with realtime safety. Complain and print it anyway. */ 00159 jack_log_function(LOG_LEVEL_ERROR, "messagebuffer not initialized, skip message"); 00160 } else { 00161 Jack::JackMessageBuffer::fInstance->AddMessage(level, message); 00162 } 00163 } 00164 00165 int JackMessageBuffer::SetInitCallback(JackThreadInitCallback callback, void *arg) 00166 { 00167 if (fInstance && callback && fRunning && fGuard.Lock()) { 00168 /* set up the callback */ 00169 fInitArg = arg; 00170 fInit = callback; 00171 00172 #ifndef WIN32 00173 // wake msg buffer thread 00174 fGuard.Signal(); 00175 // wait for it to be done 00176 fGuard.Wait(); 00177 // and we're done 00178 fGuard.Unlock(); 00179 #else 00180 /* 00181 The condition variable emulation code does not work reliably on Windows (lost signal). 00182 So use a "hackish" way to signal/wait for the result. 00183 Probaly better in the long term : use pthread-win32 (http://sourceware.org/pthreads-win32/` 00184 */ 00185 fGuard.Unlock(); 00186 int count = 0; 00187 while (fInit && ++count < 1000) { 00188 /* wake msg buffer thread */ 00189 fGuard.Signal(); 00190 JackSleep(1000); 00191 } 00192 if (count == 1000) goto error; 00193 #endif 00194 00195 return 0; 00196 } 00197 00198 error: 00199 jack_error("JackMessageBuffer::SetInitCallback : callback cannot be executed"); 00200 return -1; 00201 } 00202 00203 }; 00204