From a74f1a586e14abb37076438a86ac4260cd4e7229 Mon Sep 17 00:00:00 2001 From: sletz Date: Wed, 21 May 2008 12:50:24 +0000 Subject: [PATCH] Better handling of graph state read functions : never wait when used in the real-time thread, current state is used. git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2302 0c269be4-1314-0410-8aa9-9f06e86f4224 --- ChangeLog | 1 + common/JackAPI.cpp | 20 ++++++++++++----- common/JackClient.cpp | 5 ++++- common/JackGlobals.cpp | 41 +++++++++++++++++++++++++++++++-- common/JackGlobals.h | 15 +++++++++++++ common/JackLibGlobals.h | 2 +- common/JackPosixThread.cpp | 46 ++++++++++++++++++++++++++++++++++++++ common/JackThread.h | 12 ++++++++++ windows/JackWinThread.cpp | 41 +++++++++++++++++++++++++++++++++ 9 files changed, 173 insertions(+), 10 deletions(-) diff --git a/ChangeLog b/ChangeLog index d5b8a836..8317bb5f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,6 +24,7 @@ Fernando Lopez-Lezcano * Correct JackEngine::PortUnRegister, JackEngine::ClientCloseAux and JackEngine::ClientDeactivate to correctly send notifications. * New jack_get_client_pid API, implemented on server side. + * Better handling of graph state read functions : never wait when used in the real-time thread, current state is used. 2008-05-20 Stephane Letz diff --git a/common/JackAPI.cpp b/common/JackAPI.cpp index c0c9e820..f8e396f4 100644 --- a/common/JackAPI.cpp +++ b/common/JackAPI.cpp @@ -248,12 +248,20 @@ static inline bool CheckBufferSize(jack_nframes_t buffer_size) static inline void WaitGraphChange() { - JackGraphManager* manager = GetGraphManager(); - JackEngineControl* control = GetEngineControl(); - - if (manager && control && manager->IsPendingChange()) { - jack_log("WaitGraphChange..."); - JackSleep(int(control->fPeriodUsecs * 1.1f)); + /* + TLS key that is set only in RT thread, so never waits for pending + graph change in RT context (just read the current graph state). + */ + + if (jack_tls_get(gRealTime) == NULL) { + JackGraphManager* manager = GetGraphManager(); + JackEngineControl* control = GetEngineControl(); + assert(manager); + assert(control); + if (manager->IsPendingChange()) { + jack_log("WaitGraphChange..."); + JackSleep(int(control->fPeriodUsecs * 1.1f)); + } } } diff --git a/common/JackClient.cpp b/common/JackClient.cpp index fa537465..5dbe8a2c 100644 --- a/common/JackClient.cpp +++ b/common/JackClient.cpp @@ -36,7 +36,7 @@ namespace Jack { #define IsRealTime() ((fProcess != NULL) | (fThreadFun != NULL) | (fSync != NULL) | (fTimebase != NULL)) - + JackClient::JackClient() {} @@ -335,6 +335,9 @@ int JackClient::StartThread() */ bool JackClient::Execute() { + if (!jack_tls_set(gRealTime, this)) + jack_error("failed to set thread realtime key"); + if (fThreadFun) { // Execute a dummy cycle to be sure thread has the correct properties (ensure thread creation is finished) WaitSync(); diff --git a/common/JackGlobals.cpp b/common/JackGlobals.cpp index 0005e054..3afacc53 100644 --- a/common/JackGlobals.cpp +++ b/common/JackGlobals.cpp @@ -22,6 +22,43 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. namespace Jack { -JackFactoryImpl* JackGlobals::fInstance; - + JackFactoryImpl* JackGlobals::fInstance; + } // end of namespace + +static bool gKeyRealtimeInitialized = false; +jack_tls_key gRealTime; + +void jack_realtime_init() +{ + if (!gKeyRealtimeInitialized) { + gKeyRealtimeInitialized = jack_tls_allocate_key(&gRealTime); + } +} + +void jack_realtime_uninit() +{ + if (gKeyRealtimeInitialized) { + jack_tls_free_key(gRealTime); + gKeyRealtimeInitialized = false; + } +} + +// Initialisation at library load time + +#ifdef WIN32 + +BOOL WINAPI DllEntryPoint(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + jack_realtime_init(); + break; + case DLL_PROCESS_DETACH: + jack_realtime_uninit(); + break; + } + return TRUE; +} + +#endif diff --git a/common/JackGlobals.h b/common/JackGlobals.h index 160deac8..10b435a0 100644 --- a/common/JackGlobals.h +++ b/common/JackGlobals.h @@ -21,6 +21,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #define __JackGlobals__ #include "JackError.h" +#include "JackThread.h" namespace Jack { @@ -279,4 +280,18 @@ class JackGlobals } // end of namespace +#ifdef __cplusplus +extern "C" +{ +#endif + +extern jack_tls_key gRealTime; + +void __attribute__ ((constructor)) jack_realtime_init(); +void __attribute__ ((destructor)) jack_realtime_uninit(); + +#ifdef __cplusplus +} +#endif + #endif diff --git a/common/JackLibGlobals.h b/common/JackLibGlobals.h index 2f24c07a..8daa3117 100644 --- a/common/JackLibGlobals.h +++ b/common/JackLibGlobals.h @@ -48,7 +48,7 @@ struct JackLibGlobals #ifdef __APPLE__ std::map fClientTable; /*! Client table */ #endif - + static int fClientCount; static JackLibGlobals* fGlobals; diff --git a/common/JackPosixThread.cpp b/common/JackPosixThread.cpp index 1b0909ef..6e62de58 100644 --- a/common/JackPosixThread.cpp +++ b/common/JackPosixThread.cpp @@ -219,3 +219,49 @@ void JackPosixThread::Terminate() } // end of namespace +bool jack_tls_allocate_key(jack_tls_key *key_ptr) +{ + int ret; + + ret = pthread_key_create(key_ptr, NULL); + if (ret != 0) + { + jack_error("pthread_key_create() failed with error %d errno %s", ret, strerror(errno)); + return false; + } + + return true; +} + +bool jack_tls_free_key(jack_tls_key key) +{ + int ret; + + ret = pthread_key_delete(key); + if (ret != 0) + { + jack_error("pthread_key_delete() failed with error %d errno %s", ret, strerror(errno)); + return false; + } + + return true; +} + +bool jack_tls_set(jack_tls_key key, void *data_ptr) +{ + int ret; + + ret = pthread_setspecific(key, (const void *)data_ptr); + if (ret != 0) + { + jack_error("pthread_setspecific() failed with error %d errno %s", ret, strerror(errno)); + return false; + } + + return true; +} + +void *jack_tls_get(jack_tls_key key) +{ + return pthread_getspecific(key); +} diff --git a/common/JackThread.h b/common/JackThread.h index 29bbce4e..96a73c51 100644 --- a/common/JackThread.h +++ b/common/JackThread.h @@ -108,4 +108,16 @@ class JackThread } // end of namespace +#if defined(WIN32) +typedef DWORD jack_tls_key; +#else +typedef pthread_key_t jack_tls_key; +#endif + +bool jack_tls_allocate_key(jack_tls_key *key_ptr); +bool jack_tls_free_key(jack_tls_key key); + +bool jack_tls_set(jack_tls_key key, void *data_ptr); +void *jack_tls_get(jack_tls_key key); + #endif diff --git a/windows/JackWinThread.cpp b/windows/JackWinThread.cpp index 29cdbd19..30dfacd7 100644 --- a/windows/JackWinThread.cpp +++ b/windows/JackWinThread.cpp @@ -257,3 +257,44 @@ void JackWinThread::Terminate() } // end of namespace +bool jack_tls_allocate_key(jack_tls_key *key_ptr) +{ + DWORD key; + + key = TlsAlloc(); + if (key == TLS_OUT_OF_INDEXES) + { + jack_error("TlsAlloc() failed. Error is %d", (unsigned int)GetLastError()); + return false; + } + + *key_ptr = key; + return true; +} + +bool jack_tls_free_key(jack_tls_key key) +{ + if (!TlsFree(key)) + { + jack_error("TlsFree() failed. Error is %d", (unsigned int)GetLastError()); + return false; + } + + return true; +} + +bool jack_tls_set(jack_tls_key key, void *data_ptr) +{ + if (!TlsSetValue(key, data_ptr)) + { + jack_error("TlsSetValue() failed. Error is %d", (unsigned int)GetLastError()); + return false; + } + + return true; +} + +void *jack_tls_get(jack_tls_key key) +{ + return TlsGetValue(key); +}