git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@4526 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.9.8
| @@ -35,6 +35,10 @@ Chris Caudle | |||
| Jackdmp changes log | |||
| --------------------------- | |||
| 2011-06-26 Stephane Letz <letz@grame.fr> | |||
| * More robust code in synchronization primitives and in JackMessageBuffer. | |||
| 2011-07-29 Stephane Letz <letz@grame.fr> | |||
| * New JackTimedDriver class to be used by JackDummyDriver, JackNetDriver and JackNetOneDriver classes. | |||
| @@ -53,7 +53,7 @@ extern "C" | |||
| Jack::JackAudioAdapter* adapter; | |||
| jack_nframes_t buffer_size = jack_get_buffer_size(jack_client); | |||
| jack_nframes_t sample_rate = jack_get_sample_rate(jack_client); | |||
| try { | |||
| #ifdef __linux__ | |||
| @@ -71,17 +71,16 @@ extern "C" | |||
| #if defined(__sun__) || defined(sun) | |||
| adapter = new Jack::JackAudioAdapter(jack_client, new Jack::JackOSSAdapter(buffer_size, sample_rate, params)); | |||
| #endif | |||
| assert(adapter); | |||
| if (adapter->Open() == 0) | |||
| assert(adapter); | |||
| if (adapter->Open() == 0) { | |||
| return 0; | |||
| else | |||
| { | |||
| } else { | |||
| delete adapter; | |||
| return 1; | |||
| } | |||
| } catch (...) { | |||
| return 1; | |||
| } | |||
| @@ -94,13 +93,14 @@ extern "C" | |||
| int res = 1; | |||
| jack_driver_desc_t* desc = jack_get_descriptor(); | |||
| Jack::JackArgParser parser ( load_init ); | |||
| if ( parser.GetArgc() > 0 ) | |||
| parse_params = parser.ParseParams ( desc, ¶ms ); | |||
| Jack::JackArgParser parser(load_init); | |||
| if (parser.GetArgc() > 0) { | |||
| parse_params = parser.ParseParams(desc, ¶ms); | |||
| } | |||
| if (parse_params) { | |||
| res = jack_internal_initialize ( jack_client, params ); | |||
| parser.FreeParams ( params ); | |||
| res = jack_internal_initialize(jack_client, params); | |||
| parser.FreeParams(params); | |||
| } | |||
| return res; | |||
| } | |||
| @@ -29,6 +29,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| namespace Jack | |||
| { | |||
| #define ThrowIf(inCondition, inException) \ | |||
| if(inCondition) \ | |||
| { \ | |||
| throw(inException); \ | |||
| } | |||
| /*! | |||
| \brief Exception base class. | |||
| */ | |||
| @@ -52,8 +59,9 @@ class SERVER_EXPORT JackException : public std::runtime_error { | |||
| void PrintMessage() | |||
| { | |||
| std::string str = what(); | |||
| if (str != "") | |||
| if (str != "") { | |||
| jack_info(str.c_str()); | |||
| } | |||
| } | |||
| }; | |||
| @@ -62,9 +70,9 @@ class SERVER_EXPORT JackException : public std::runtime_error { | |||
| */ | |||
| class SERVER_EXPORT JackTemporaryException : public JackException { | |||
| public: | |||
| JackTemporaryException(const std::string& msg) : JackException(msg) | |||
| {} | |||
| JackTemporaryException(char* msg) : JackException(msg) | |||
| @@ -74,15 +82,15 @@ class SERVER_EXPORT JackTemporaryException : public JackException { | |||
| JackTemporaryException() : JackException("") | |||
| {} | |||
| }; | |||
| /*! | |||
| \brief | |||
| \brief | |||
| */ | |||
| class SERVER_EXPORT JackQuitException : public JackException { | |||
| public: | |||
| JackQuitException(const std::string& msg) : JackException(msg) | |||
| {} | |||
| JackQuitException(char* msg) : JackException(msg) | |||
| @@ -92,7 +100,7 @@ class SERVER_EXPORT JackQuitException : public JackException { | |||
| JackQuitException() : JackException("") | |||
| {} | |||
| }; | |||
| /*! | |||
| \brief Exception possibly thrown by Net slaves. | |||
| */ | |||
| @@ -48,11 +48,16 @@ void JackMessageBuffer::Stop() | |||
| } else { | |||
| jack_log("no message buffer overruns"); | |||
| } | |||
| fGuard.Lock(); | |||
| fRunning = false; | |||
| fGuard.Signal(); | |||
| fGuard.Unlock(); | |||
| fThread.Stop(); | |||
| if (fGuard.Lock()) { | |||
| fRunning = false; | |||
| fGuard.Signal(); | |||
| fGuard.Unlock(); | |||
| fThread.Stop(); | |||
| } else { | |||
| fThread.Kill(); | |||
| } | |||
| Flush(); | |||
| } | |||
| @@ -80,19 +85,22 @@ void JackMessageBuffer::AddMessage(int level, const char *message) | |||
| bool JackMessageBuffer::Execute() | |||
| { | |||
| while (fRunning) { | |||
| fGuard.Lock(); | |||
| fGuard.Wait(); | |||
| /* the client asked for all threads to run a thread | |||
| initialization callback, which includes us. | |||
| */ | |||
| if (fInit) { | |||
| fInit(fInitArg); | |||
| fInit = NULL; | |||
| /* and we're done */ | |||
| fGuard.Signal(); | |||
| if (fGuard.Lock()) { | |||
| fGuard.Wait(); | |||
| /* the client asked for all threads to run a thread | |||
| initialization callback, which includes us. | |||
| */ | |||
| if (fInit) { | |||
| fInit(fInitArg); | |||
| fInit = NULL; | |||
| /* and we're done */ | |||
| fGuard.Signal(); | |||
| } | |||
| Flush(); | |||
| fGuard.Unlock(); | |||
| } else { | |||
| jack_error("JackMessageBuffer::Execute lock cannot be taken"); | |||
| } | |||
| Flush(); | |||
| fGuard.Unlock(); | |||
| } | |||
| return false; | |||
| } | |||
| @@ -126,16 +134,19 @@ void JackMessageBufferAdd(int level, const char *message) | |||
| void JackMessageBuffer::SetInitCallback(JackThreadInitCallback callback, void *arg) | |||
| { | |||
| fGuard.Lock(); | |||
| /* set up the callback */ | |||
| fInitArg = arg; | |||
| fInit = callback; | |||
| /* wake msg buffer thread */ | |||
| fGuard.Signal(); | |||
| /* wait for it to be done */ | |||
| fGuard.Wait(); | |||
| /* and we're done */ | |||
| fGuard.Unlock(); | |||
| if (fGuard.Lock()) { | |||
| /* set up the callback */ | |||
| fInitArg = arg; | |||
| fInit = callback; | |||
| /* wake msg buffer thread */ | |||
| fGuard.Signal(); | |||
| /* wait for it to be done */ | |||
| fGuard.Wait(); | |||
| /* and we're done */ | |||
| fGuard.Unlock(); | |||
| } else { | |||
| jack_error("JackMessageBuffer::SetInitCallback lock cannot be taken"); | |||
| } | |||
| } | |||
| }; | |||
| @@ -10,19 +10,19 @@ | |||
| * Copyright (C) 2004 Rui Nuno Capela, Steve Harris | |||
| * Copyright (C) 2008 Nedko Arnaudov | |||
| * Copyright (C) 2008 Grame | |||
| * | |||
| * | |||
| * This program is free software; you can redistribute it and/or modify | |||
| * it under the terms of the GNU Lesser General Public License as published by | |||
| * the Free Software Foundation; either version 2.1 of the License, or | |||
| * (at your option) any later version. | |||
| * | |||
| * | |||
| * This program is distributed in the hope that it will be useful, | |||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| * GNU Lesser General Public License for more details. | |||
| * | |||
| * | |||
| * You should have received a copy of the GNU Lesser General Public License | |||
| * along with this program; if not, write to the Free Software | |||
| * along with this program; if not, write to the Free Software | |||
| * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| * | |||
| */ | |||
| @@ -56,7 +56,7 @@ class JackMessageBuffer : public JackRunnableInterface | |||
| { | |||
| private: | |||
| JackThreadInitCallback fInit; | |||
| void* fInitArg; | |||
| JackMessage fBuffers[MB_BUFFERS]; | |||
| @@ -68,15 +68,15 @@ class JackMessageBuffer : public JackRunnableInterface | |||
| bool fRunning; | |||
| void Flush(); | |||
| void Start(); | |||
| void Stop(); | |||
| public: | |||
| JackMessageBuffer(); | |||
| JackMessageBuffer(); | |||
| ~JackMessageBuffer(); | |||
| // JackRunnableInterface interface | |||
| bool Execute(); | |||
| @@ -90,16 +90,16 @@ class JackMessageBuffer : public JackRunnableInterface | |||
| }; | |||
| #ifdef __cplusplus | |||
| extern "C" | |||
| extern "C" | |||
| { | |||
| #endif | |||
| void JackMessageBufferAdd(int level, const char *message); | |||
| #ifdef __cplusplus | |||
| } | |||
| } | |||
| #endif | |||
| }; | |||
| #endif | |||
| #endif | |||
| @@ -22,10 +22,11 @@ | |||
| #ifndef __JackPosixMutex__ | |||
| #define __JackPosixMutex__ | |||
| #include "JackError.h" | |||
| #include "JackException.h" | |||
| #include <pthread.h> | |||
| #include <stdio.h> | |||
| #include <assert.h> | |||
| #include "JackError.h" | |||
| namespace Jack | |||
| { | |||
| @@ -33,19 +34,20 @@ namespace Jack | |||
| \brief Mutex abstraction. | |||
| */ | |||
| class JackBasePosixMutex | |||
| { | |||
| protected: | |||
| pthread_mutex_t fMutex; | |||
| pthread_t fOwner; | |||
| public: | |||
| JackBasePosixMutex() | |||
| JackBasePosixMutex():fOwner(0) | |||
| { | |||
| pthread_mutex_init(&fMutex, NULL); | |||
| int res = pthread_mutex_init(&fMutex, NULL); | |||
| ThrowIf(res != 0, JackException("JackBasePosixMutex: could not init the mutex")); | |||
| } | |||
| virtual ~JackBasePosixMutex() | |||
| @@ -53,30 +55,65 @@ class JackBasePosixMutex | |||
| pthread_mutex_destroy(&fMutex); | |||
| } | |||
| void Lock() | |||
| bool Lock() | |||
| { | |||
| int res = pthread_mutex_lock(&fMutex); | |||
| if (res != 0) | |||
| jack_log("JackBasePosixMutex::Lock res = %d", res); | |||
| pthread_t current_thread = pthread_self(); | |||
| if (!pthread_equal(current_thread, fOwner)) { | |||
| int res = pthread_mutex_lock(&fMutex); | |||
| if (res == 0) { | |||
| fOwner = current_thread; | |||
| return true; | |||
| } else { | |||
| jack_error("JackBasePosixMutex::Lock res = %d", res); | |||
| return false; | |||
| } | |||
| } else { | |||
| jack_error("JackBasePosixMutex::Lock mutex already locked by thread = %d", current_thread); | |||
| return false; | |||
| } | |||
| } | |||
| bool Trylock() | |||
| { | |||
| return (pthread_mutex_trylock(&fMutex) == 0); | |||
| pthread_t current_thread = pthread_self(); | |||
| if (!pthread_equal(current_thread, fOwner)) { | |||
| int res = pthread_mutex_trylock(&fMutex); | |||
| if (res == 0) { | |||
| fOwner = current_thread; | |||
| return true; | |||
| } else { | |||
| jack_error("JackBasePosixMutex::Trylock res = %d", res); | |||
| return false; | |||
| } | |||
| } else { | |||
| jack_error("JackBasePosixMutex::Trylock mutex already locked by thread = %d", current_thread); | |||
| return false; | |||
| } | |||
| } | |||
| void Unlock() | |||
| bool Unlock() | |||
| { | |||
| int res = pthread_mutex_unlock(&fMutex); | |||
| if (res != 0) | |||
| jack_log("JackBasePosixMutex::Unlock res = %d", res); | |||
| if (pthread_equal(pthread_self(), fOwner)) { | |||
| fOwner = 0; | |||
| int res = pthread_mutex_unlock(&fMutex); | |||
| if (res == 0) { | |||
| return true; | |||
| } else { | |||
| jack_error("JackBasePosixMutex::Unlock res = %d", res); | |||
| return false; | |||
| } | |||
| } else { | |||
| jack_error("JackBasePosixMutex::Unlock mutex not locked by thread = %d owner %d", pthread_self(), fOwner); | |||
| return false; | |||
| } | |||
| } | |||
| }; | |||
| class JackPosixMutex | |||
| { | |||
| protected: | |||
| pthread_mutex_t fMutex; | |||
| @@ -89,13 +126,12 @@ class JackPosixMutex | |||
| pthread_mutexattr_t mutex_attr; | |||
| int res; | |||
| res = pthread_mutexattr_init(&mutex_attr); | |||
| assert(res == 0); | |||
| ThrowIf(res != 0, JackException("JackBasePosixMutex: could not init the mutex attribute")); | |||
| res = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE); | |||
| assert(res == 0); | |||
| ThrowIf(res != 0, JackException("JackBasePosixMutex: could not settype the mutex")); | |||
| res = pthread_mutex_init(&fMutex, &mutex_attr); | |||
| assert(res == 0); | |||
| res = pthread_mutexattr_destroy(&mutex_attr); | |||
| assert(res == 0); | |||
| ThrowIf(res != 0, JackException("JackBasePosixMutex: could not init the mutex")); | |||
| pthread_mutexattr_destroy(&mutex_attr); | |||
| } | |||
| virtual ~JackPosixMutex() | |||
| @@ -106,8 +142,9 @@ class JackPosixMutex | |||
| bool Lock() | |||
| { | |||
| int res = pthread_mutex_lock(&fMutex); | |||
| if (res != 0) | |||
| if (res != 0) { | |||
| jack_log("JackPosixMutex::Lock res = %d", res); | |||
| } | |||
| return (res == 0); | |||
| } | |||
| @@ -119,8 +156,9 @@ class JackPosixMutex | |||
| bool Unlock() | |||
| { | |||
| int res = pthread_mutex_unlock(&fMutex); | |||
| if (res != 0) | |||
| if (res != 0) { | |||
| jack_log("JackPosixMutex::Unlock res = %d", res); | |||
| } | |||
| return (res == 0); | |||
| } | |||
| @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -30,6 +30,7 @@ void JackProcessSync::Signal() | |||
| jack_error("JackProcessSync::Signal error err = %s", strerror(res)); | |||
| } | |||
| // TO DO : check thread consistency? | |||
| void JackProcessSync::LockedSignal() | |||
| { | |||
| int res = pthread_mutex_lock(&fMutex); | |||
| @@ -50,6 +51,7 @@ void JackProcessSync::SignalAll() | |||
| jack_error("JackProcessSync::SignalAll error err = %s", strerror(res)); | |||
| } | |||
| // TO DO : check thread consistency? | |||
| void JackProcessSync::LockedSignalAll() | |||
| { | |||
| int res = pthread_mutex_lock(&fMutex); | |||
| @@ -65,11 +67,18 @@ void JackProcessSync::LockedSignalAll() | |||
| void JackProcessSync::Wait() | |||
| { | |||
| int res; | |||
| if ((res = pthread_cond_wait(&fCond, &fMutex)) != 0) | |||
| ThrowIf(!pthread_equal(pthread_self(), fOwner), JackException("JackProcessSync::Wait: a thread has to have locked a mutex before it can wait")); | |||
| fOwner = 0; | |||
| int res = pthread_cond_wait(&fCond, &fMutex); | |||
| if (res != 0) { | |||
| jack_error("JackProcessSync::Wait error err = %s", strerror(res)); | |||
| } | |||
| } else { | |||
| fOwner = pthread_self(); | |||
| } | |||
| } | |||
| // TO DO : check thread consistency? | |||
| void JackProcessSync::LockedWait() | |||
| { | |||
| int res; | |||
| @@ -85,6 +94,9 @@ void JackProcessSync::LockedWait() | |||
| bool JackProcessSync::TimedWait(long usec) | |||
| { | |||
| ThrowIf(!pthread_equal(pthread_self(), fOwner), JackException("JackProcessSync::TimedWait: a thread has to have locked a mutex before it can wait")); | |||
| fOwner = 0; | |||
| struct timeval T0, T1; | |||
| timespec time; | |||
| struct timeval now; | |||
| @@ -97,17 +109,22 @@ bool JackProcessSync::TimedWait(long usec) | |||
| unsigned int next_date_usec = now.tv_usec + usec; | |||
| time.tv_sec = now.tv_sec + (next_date_usec / 1000000); | |||
| time.tv_nsec = (next_date_usec % 1000000) * 1000; | |||
| res = pthread_cond_timedwait(&fCond, &fMutex, &time); | |||
| if (res != 0) | |||
| if (res != 0) { | |||
| jack_error("JackProcessSync::TimedWait error usec = %ld err = %s", usec, strerror(res)); | |||
| } else { | |||
| fOwner = pthread_self(); | |||
| } | |||
| gettimeofday(&T1, 0); | |||
| jack_log("JackProcessSync::TimedWait finished delta = %5.1lf", | |||
| (1e6 * T1.tv_sec - 1e6 * T0.tv_sec + T1.tv_usec - T0.tv_usec)); | |||
| return (res == 0); | |||
| } | |||
| // TO DO : check thread consistency? | |||
| bool JackProcessSync::LockedTimedWait(long usec) | |||
| { | |||
| struct timeval T0, T1; | |||
| @@ -118,7 +135,7 @@ bool JackProcessSync::LockedTimedWait(long usec) | |||
| res1 = pthread_mutex_lock(&fMutex); | |||
| if (res1 != 0) | |||
| jack_error("JackProcessSync::LockedTimedWait error err = %s", usec, strerror(res1)); | |||
| jack_log("JackProcessSync::TimedWait time out = %ld", usec); | |||
| gettimeofday(&T0, 0); | |||
| @@ -134,10 +151,10 @@ bool JackProcessSync::LockedTimedWait(long usec) | |||
| res1 = pthread_mutex_unlock(&fMutex); | |||
| if (res1 != 0) | |||
| jack_error("JackProcessSync::LockedTimedWait error err = %s", usec, strerror(res1)); | |||
| jack_log("JackProcessSync::TimedWait finished delta = %5.1lf", | |||
| (1e6 * T1.tv_sec - 1e6 * T0.tv_sec + T1.tv_usec - T0.tv_usec)); | |||
| return (res2 == 0); | |||
| } | |||
| @@ -12,7 +12,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| #include "JackPlatformPlug.h" | |||
| #include "JackPosixMutex.h" | |||
| #include "JackException.h" | |||
| #include <sys/time.h> | |||
| #include <unistd.h> | |||
| @@ -43,7 +44,8 @@ class JackProcessSync : public JackBasePosixMutex | |||
| JackProcessSync():JackBasePosixMutex() | |||
| { | |||
| pthread_cond_init(&fCond, NULL); | |||
| int res = pthread_cond_init(&fCond, NULL); | |||
| ThrowIf(res != 0, JackException("JackBasePosixMutex: could not init the cond variable")); | |||
| } | |||
| virtual ~JackProcessSync() | |||
| @@ -53,16 +55,16 @@ class JackProcessSync : public JackBasePosixMutex | |||
| bool TimedWait(long usec); | |||
| bool LockedTimedWait(long usec); | |||
| void Wait(); | |||
| void LockedWait(); | |||
| void Signal(); | |||
| void LockedSignal(); | |||
| void SignalAll(); | |||
| void LockedSignalAll(); | |||
| }; | |||
| } // end of namespace | |||
| @@ -1,20 +1,20 @@ | |||
| /* | |||
| Copyright (C) 2004-2008 Grame | |||
| This program is free software; you can redistribute it and/or modify | |||
| it under the terms of the GNU Lesser General Public License as published by | |||
| the Free Software Foundation; either version 2.1 of the License, or | |||
| (at your option) any later version. | |||
| This program is distributed in the hope that it will be useful, | |||
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| GNU Lesser General Public License for more details. | |||
| You should have received a copy of the GNU Lesser General Public License | |||
| along with this program; if not, write to the Free Software | |||
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |||
| */ | |||
| @@ -28,6 +28,81 @@ namespace Jack | |||
| /*! | |||
| \brief Mutex abstraction. | |||
| */ | |||
| class JackBaseWinMutex | |||
| { | |||
| protected: | |||
| HANDLE fMutex; | |||
| DWORD fOwner; | |||
| public: | |||
| JackBaseWinMutex():fOwner(0) | |||
| { | |||
| // In recursive mode by default | |||
| fMutex = (HANDLE)CreateMutex(0, FALSE, 0); | |||
| ThrowIf(fMutex == 0, JackException("JackWinMutex: could not init the mutex")); | |||
| } | |||
| virtual ~JackBaseWinMutex() | |||
| { | |||
| CloseHandle(fMutex); | |||
| } | |||
| bool Lock() | |||
| { | |||
| if (fOwner != GetCurrentThreadId()) { | |||
| DWORD res = WaitForSingleObject(fMutex, INFINITE); | |||
| if (res == WAIT_OBJECT_0) { | |||
| fOwner = GetCurrentThreadId(); | |||
| return true; | |||
| } else { | |||
| jack_log("JackWinMutex::Lock res = %d", res); | |||
| return false; | |||
| } | |||
| } else { | |||
| jack_error("JackWinMutex::Lock mutex already locked by thread = %d", GetCurrentThreadId()); | |||
| return false; | |||
| } | |||
| } | |||
| bool Trylock() | |||
| { | |||
| if (fOwner != GetCurrentThreadId()) { | |||
| DWORD res = WaitForSingleObject(fMutex, 0); | |||
| if (res == WAIT_OBJECT_0) { | |||
| fOwner = GetCurrentThreadId(); | |||
| return true; | |||
| } else { | |||
| jack_log("JackWinMutex::Trylock res = %d", res); | |||
| return false; | |||
| } | |||
| } else { | |||
| jack_error("JackWinMutex::Trylock mutex already locked by thread = %d", GetCurrentThreadId()); | |||
| return false; | |||
| } | |||
| } | |||
| bool Unlock() | |||
| { | |||
| if (fOwner == GetCurrentThreadId()) { | |||
| fOwner = 0; | |||
| int res = ReleaseMutex(fMutex); | |||
| if (res != 0) { | |||
| return true; | |||
| } else { | |||
| jack_log("JackWinMutex::Unlock res = %d", res); | |||
| return false; | |||
| } | |||
| } else { | |||
| jack_error("JackWinMutex::Unlock mutex not locked by thread = %d", GetCurrentThreadId()); | |||
| return false; | |||
| } | |||
| } | |||
| }; | |||
| class JackWinMutex | |||
| { | |||
| @@ -65,6 +140,7 @@ class JackWinMutex | |||
| }; | |||
| } // namespace | |||
| #endif | |||