diff --git a/ChangeLog b/ChangeLog index 54932426..09894199 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,10 @@ Michael Voigt Jackdmp changes log --------------------------- +2008-11-16 Stephane Letz + + * Client and library global context cleanup in case of incorrect shutdown handling (that is applications not correctly closing client after server has shutdown). + 2008-11-27 Stephane Letz * Report ringbuffer.c fixes from jack1. diff --git a/common/JackAPI.cpp b/common/JackAPI.cpp index d91872d9..2cd6dc49 100644 --- a/common/JackAPI.cpp +++ b/common/JackAPI.cpp @@ -259,7 +259,7 @@ static inline void WaitGraphChange() graph change in RT context (just read the current graph state). */ - if (jack_tls_get(gRealTime) == NULL) { + if (jack_tls_get(JackGlobals::fRealTime) == NULL) { JackGraphManager* manager = GetGraphManager(); JackEngineControl* control = GetEngineControl(); assert(manager); @@ -283,14 +283,14 @@ EXPORT void jack_set_info_function (print_function func) EXPORT jack_client_t* jack_client_new(const char* client_name) { - assert(gOpenMutex); - gOpenMutex->Lock(); + assert(JackGlobals::fOpenMutex); + JackGlobals::fOpenMutex->Lock(); jack_error("jack_client_new: deprecated"); int options = JackUseExactName; if (getenv("JACK_START_SERVER") == NULL) options |= JackNoStartServer; jack_client_t* res = jack_client_open_aux(client_name, (jack_options_t)options, NULL, NULL); - gOpenMutex->Unlock(); + JackGlobals::fOpenMutex->Unlock(); return res; } @@ -628,7 +628,7 @@ EXPORT int jack_port_set_name(jack_port_t* port, const char* name) JackGraphManager* manager = GetGraphManager(); int refnum; if (manager && ((refnum = manager->GetPort(myport)->GetRefNum()) > 0)) { - JackClient* client = JackClient::fClientTable[refnum]; + JackClient* client = JackGlobals::fClientTable[refnum]; assert(client); return client->PortRename(myport, name); } else { diff --git a/common/JackClient.cpp b/common/JackClient.cpp index 66999070..cf8097c0 100644 --- a/common/JackClient.cpp +++ b/common/JackClient.cpp @@ -37,8 +37,6 @@ using namespace std; namespace Jack { -JackClient* JackClient::fClientTable[CLIENT_NUM] = {}; - #define IsRealTime() ((fProcess != NULL) | (fThreadFun != NULL) | (fSync != NULL) | (fTimebase != NULL)) JackClient::JackClient():fThread(this) @@ -88,8 +86,8 @@ int JackClient::Close() Deactivate(); fChannel->Stop(); // Channels is stopped first to avoid receiving notifications while closing - // Request close only is server is still running - if (GetClientControl()->fServer) { + // Request close only if server is still running + if (JackGlobals::fServerRunning) { fChannel->ClientClose(GetClientControl()->fRefNum, &result); } else { jack_log("JackClient::Close server is shutdown"); @@ -97,7 +95,7 @@ int JackClient::Close() fChannel->Close(); fSynchroTable[GetClientControl()->fRefNum].Disconnect(); - fClientTable[GetClientControl()->fRefNum] = NULL; + JackGlobals::fClientTable[GetClientControl()->fRefNum] = NULL; return result; } @@ -359,7 +357,7 @@ int JackClient::StartThread() */ bool JackClient::Execute() { - if (!jack_tls_set(gRealTime, this)) + if (!jack_tls_set(JackGlobals::fRealTime, this)) jack_error("failed to set thread realtime key"); if (GetEngineControl()->fRealTime) @@ -596,11 +594,7 @@ ShutDown is called: void JackClient::ShutDown() { jack_log("ShutDown"); - - // Be sure client is already started - if (GetClientControl()) { - GetClientControl()->fServer = false; - } + JackGlobals::fServerRunning = false; if (fShutdown) { fShutdown(fShutdownArg); diff --git a/common/JackClient.h b/common/JackClient.h index 52a2c14b..f9addd6e 100644 --- a/common/JackClient.h +++ b/common/JackClient.h @@ -87,8 +87,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface detail::JackClientChannelInterface* fChannel; JackSynchro* fSynchroTable; std::list fPortList; - bool fServerRunning; - + int StartThread(); void SetupDriverSync(bool freewheel); bool IsActive(); @@ -98,7 +97,6 @@ class JackClient : public JackClientInterface, public JackRunnableInterface virtual int ClientNotifyImp(int refnum, const char* name, int notify, int sync, int value1, int value); - // Fons Adriaensen thread model inline bool WaitFirstSync(); inline void ExecuteThread(); inline bool WaitSync(); @@ -140,7 +138,6 @@ class JackClient : public JackClientInterface, public JackRunnableInterface virtual int PortDisconnect(jack_port_id_t src); virtual int PortIsMine(jack_port_id_t port_index); - virtual int PortRename(jack_port_id_t port_index, const char* name); // Transport @@ -185,9 +182,6 @@ class JackClient : public JackClientInterface, public JackRunnableInterface // JackRunnableInterface interface bool Init(); bool Execute(); - - static JackClient* fClientTable[CLIENT_NUM]; - }; // Each "side" server and client will implement this to get the shared graph manager, engine control and inter-process synchro table. diff --git a/common/JackClientControl.h b/common/JackClientControl.h index f8145c49..4aa31b0c 100644 --- a/common/JackClientControl.h +++ b/common/JackClientControl.h @@ -43,7 +43,6 @@ struct JackClientControl : public JackShmMemAble int fRefNum; int fPID; bool fActive; - bool fServer; JackClientControl(const char* name, int pid, int refnum) { @@ -78,7 +77,6 @@ struct JackClientControl : public JackShmMemAble fTransportSync = false; fTransportTimebase = false; fActive = false; - fServer = true; } }; diff --git a/common/JackError.cpp b/common/JackError.cpp index 38c19bd1..1ed928c0 100644 --- a/common/JackError.cpp +++ b/common/JackError.cpp @@ -27,9 +27,11 @@ int jack_verbose = 0; +using namespace Jack; + void change_thread_log_function(jack_log_function_t log_function) { - if (!jack_tls_set(g_key_log_function, (void*)log_function)) + if (!jack_tls_set(JackGlobals::fKeyLogFunction, (void*)log_function)) { jack_error("failed to set thread log function"); } @@ -37,7 +39,7 @@ void change_thread_log_function(jack_log_function_t log_function) SERVER_EXPORT void set_threaded_log_function() { - change_thread_log_function(Jack::JackMessageBufferAdd); + change_thread_log_function(JackMessageBufferAdd); } void jack_log_function(int level, const char *message) @@ -74,7 +76,7 @@ static void jack_format_and_log(int level, const char *prefix, const char *fmt, vsnprintf(buffer + len, sizeof(buffer) - len, fmt, ap); - log_function = (jack_log_function_t)jack_tls_get(g_key_log_function); + log_function = (jack_log_function_t)jack_tls_get(JackGlobals::fKeyLogFunction); /* if log function is not overriden for thread, use default one */ if (log_function == NULL) diff --git a/common/JackGlobals.cpp b/common/JackGlobals.cpp index 2888da64..84e7df6b 100644 --- a/common/JackGlobals.cpp +++ b/common/JackGlobals.cpp @@ -19,10 +19,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "JackGlobals.h" -jack_tls_key gRealTime; -static bool gKeyRealtimeInitialized = jack_tls_allocate_key(&gRealTime); +namespace Jack +{ -jack_tls_key g_key_log_function; -static bool g_key_log_function_initialized = jack_tls_allocate_key(&g_key_log_function); +jack_tls_key JackGlobals::fRealTime; +static bool gKeyRealtimeInitialized = jack_tls_allocate_key(&JackGlobals::fRealTime); -JackMutex* gOpenMutex = new JackMutex(); +jack_tls_key JackGlobals::fKeyLogFunction; +static bool fKeyLogFunctionInitialized = jack_tls_allocate_key(&JackGlobals::fKeyLogFunction); + +JackMutex* JackGlobals::fOpenMutex = new JackMutex(); +bool JackGlobals::fServerRunning = false; +JackClient* JackGlobals::fClientTable[CLIENT_NUM] = {}; + +} // end of namespace \ No newline at end of file diff --git a/common/JackGlobals.h b/common/JackGlobals.h index 7ff09326..5b109ed9 100644 --- a/common/JackGlobals.h +++ b/common/JackGlobals.h @@ -21,11 +21,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define __JackGlobals__ #include "JackPlatformPlug.h" +#include "JackConstants.h" +#include "JackClient.h" -using namespace Jack; +namespace Jack +{ -extern jack_tls_key gRealTime; -extern jack_tls_key g_key_log_function; -extern JackMutex* gOpenMutex; +// Globals used for client management on server or libray side. + +struct JackGlobals { + + static jack_tls_key fRealTime; + static jack_tls_key fKeyLogFunction; + static JackMutex* fOpenMutex; + static bool fServerRunning; + static JackClient* fClientTable[]; + +}; + +} // end of namespace #endif diff --git a/common/JackInternalClient.cpp b/common/JackInternalClient.cpp index 8e596255..a8d2a9f5 100644 --- a/common/JackInternalClient.cpp +++ b/common/JackInternalClient.cpp @@ -141,7 +141,9 @@ int JackInternalClient::Open(const char* server_name, const char* name, jack_opt } SetupDriverSync(false); - fClientTable[fClientControl.fRefNum] = this; + JackGlobals::fClientTable[fClientControl.fRefNum] = this; + JackGlobals::fServerRunning = true; + jack_log("JackInternalClient::Open name = %s refnum = %ld", name_res, fClientControl.fRefNum); return 0; error: diff --git a/common/JackLibAPI.cpp b/common/JackLibAPI.cpp index 6646454c..f905d581 100644 --- a/common/JackLibAPI.cpp +++ b/common/JackLibAPI.cpp @@ -113,20 +113,20 @@ EXPORT jack_client_t* jack_client_open_aux(const char* ext_client_name, jack_opt EXPORT jack_client_t* jack_client_open(const char* ext_client_name, jack_options_t options, jack_status_t* status, ...) { - assert(gOpenMutex); - gOpenMutex->Lock(); + assert(JackGlobals::fOpenMutex); + JackGlobals::fOpenMutex->Lock(); va_list ap; va_start(ap, status); jack_client_t* res = jack_client_open_aux(ext_client_name, options, status, ap); va_end(ap); - gOpenMutex->Unlock(); + JackGlobals::fOpenMutex->Unlock(); return res; } EXPORT int jack_client_close(jack_client_t* ext_client) { - assert(gOpenMutex); - gOpenMutex->Lock(); + assert(JackGlobals::fOpenMutex); + JackGlobals::fOpenMutex->Lock(); int res = -1; jack_log("jack_client_close"); JackClient* client = (JackClient*)ext_client; @@ -138,7 +138,7 @@ EXPORT int jack_client_close(jack_client_t* ext_client) JackLibGlobals::Destroy(); // jack library destruction jack_log("jack_client_close res = %d", res); } - gOpenMutex->Unlock(); + JackGlobals::fOpenMutex->Unlock(); return res; } diff --git a/common/JackLibClient.cpp b/common/JackLibClient.cpp index 39a854e6..55598f09 100644 --- a/common/JackLibClient.cpp +++ b/common/JackLibClient.cpp @@ -70,7 +70,7 @@ JackLibClient::~JackLibClient() int JackLibClient::Open(const char* server_name, const char* name, jack_options_t options, jack_status_t* status) { int shared_engine, shared_client, shared_graph, result; - jack_log("JackLibClient::Open %s", name); + jack_log("JackLibClient::Open name = %s", name); snprintf(fServerName, sizeof(fServerName), server_name); @@ -113,7 +113,8 @@ int JackLibClient::Open(const char* server_name, const char* name, jack_options_ goto error; } - fClientTable[GetClientControl()->fRefNum] = this; + JackGlobals::fClientTable[GetClientControl()->fRefNum] = this; + JackGlobals::fServerRunning = true; jack_log("JackLibClient::Open name = %s refnum = %ld", name_res, GetClientControl()->fRefNum); return 0; diff --git a/common/JackLibGlobals.h b/common/JackLibGlobals.h index 74732f20..f109b665 100644 --- a/common/JackLibGlobals.h +++ b/common/JackLibGlobals.h @@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "JackGraphManager.h" #include "JackMessageBuffer.h" #include "JackTime.h" +#include "JackClient.h" #include "JackError.h" #include #include @@ -44,7 +45,7 @@ struct JackLibGlobals { JackShmReadWritePtr fGraphManager; /*! Shared memory Port manager */ JackShmReadWritePtr fEngineControl; /*! Shared engine control */ // transport engine has to be writable - JackSynchro fSynchroTable[CLIENT_NUM]; /*! Shared synchro table */ + JackSynchro fSynchroTable[CLIENT_NUM]; /*! Shared synchro table */ sigset_t fProcessSignals; static int fClientCount; @@ -86,6 +87,26 @@ struct JackLibGlobals static void Init() { + if (!JackGlobals::fServerRunning && fClientCount > 0) { + + // Cleanup remaining clients + jack_error("Jack server was closed but clients are still allocated, cleanup..."); + for (int i = 0; i < CLIENT_NUM; i++) { + JackClient* client = JackGlobals::fClientTable[i]; + if (client) { + jack_error("Cleanup client ref = %d", i); + client->Close(); + delete client; + JackGlobals::fClientTable[CLIENT_NUM] = NULL; + } + } + + // Cleanup global context + fClientCount = 0; + delete fGlobals; + fGlobals = NULL; + } + if (fClientCount++ == 0 && !fGlobals) { jack_log("JackLibGlobals Init %x", fGlobals); InitTime(); diff --git a/common/JackServerAPI.cpp b/common/JackServerAPI.cpp index f1d7e1ab..61300939 100644 --- a/common/JackServerAPI.cpp +++ b/common/JackServerAPI.cpp @@ -115,20 +115,20 @@ EXPORT jack_client_t* jack_client_open_aux(const char* ext_client_name, jack_opt EXPORT jack_client_t* jack_client_open(const char* ext_client_name, jack_options_t options, jack_status_t* status, ...) { - assert(gOpenMutex); - gOpenMutex->Lock(); + assert(JackGlobals::fOpenMutex); + JackGlobals::fOpenMutex->Lock(); va_list ap; va_start(ap, status); jack_client_t* res = jack_client_open_aux(ext_client_name, options, status, ap); va_end(ap); - gOpenMutex->Unlock(); + JackGlobals::fOpenMutex->Unlock(); return res; } EXPORT int jack_client_close(jack_client_t* ext_client) { - assert(gOpenMutex); - gOpenMutex->Lock(); + assert(JackGlobals::fOpenMutex); + JackGlobals::fOpenMutex->Lock(); int res = -1; jack_log("jack_client_close"); JackClient* client = (JackClient*)ext_client; @@ -142,7 +142,7 @@ EXPORT int jack_client_close(jack_client_t* ext_client) } jack_log("jack_client_close res = %d", res); } - gOpenMutex->Unlock(); + JackGlobals::fOpenMutex->Unlock(); return res; } diff --git a/common/ringbuffer.c b/common/ringbuffer.c index 1018241a..72559594 100644 --- a/common/ringbuffer.c +++ b/common/ringbuffer.c @@ -27,8 +27,6 @@ #endif /* USE_MLOCK */ #include "JackCompilerDeps.h" -// TODO : what to do with Paul fixes done av rev 3014 (http://trac.jackaudio.org/changeset/3014) - typedef struct { char *buf; size_t len; diff --git a/tests/external_metro.cpp b/tests/external_metro.cpp index d073299b..50dba1f0 100644 --- a/tests/external_metro.cpp +++ b/tests/external_metro.cpp @@ -75,7 +75,7 @@ ExternalMetro::ExternalMetro(int freq, double max_amp, int dur_arg, int bpm, cha } if ((client = jack_client_open (client_name, options, &status)) == 0) { fprintf (stderr, "jack server not running?\n"); - return; + throw -1; } jack_set_process_callback (client, process_audio, this); @@ -184,6 +184,21 @@ int main (int argc, char *argv[]) printf("Opening a new client....\n"); client1 = new ExternalMetro(1200, 0.4, 20, 80, "t1"); + + printf("Now quit the server, shutdown callback should be called...\n"); + printf("Type 'c' to move on...\n"); + while ((getchar() != 'c')) { + JackSleep(1); + }; + + printf("Simulating client not correctly closed...\n"); + + printf("Opening a new client....\n"); + try { + client1 = new ExternalMetro(1200, 0.4, 20, 80, "t1"); + } catch (int num) { + printf("Cannot open a new client since old one was not closed correctly... OK\n"); + } printf("Type 'q' to quit...\n"); while ((getchar() != 'q')) { diff --git a/windows/portaudio/JackPortAudioDriver.cpp b/windows/portaudio/JackPortAudioDriver.cpp index 5bcaad9c..9be7c761 100644 --- a/windows/portaudio/JackPortAudioDriver.cpp +++ b/windows/portaudio/JackPortAudioDriver.cpp @@ -174,7 +174,7 @@ namespace Jack error: JackAudioDriver::Close(); - jack_error ( "Can't open default PortAudio device : %s", Pa_GetErrorText(err) ); + jack_error("Can't open default PortAudio device : %s", Pa_GetErrorText(err)); return -1; } @@ -436,8 +436,7 @@ extern "C" case 'P': playback = TRUE; - if (strcmp(param->value.str, "none") != 0) - { + if (strcmp(param->value.str, "none") != 0) { playback_pcm_name = strdup(param->value.str); } break; @@ -469,8 +468,7 @@ extern "C" } // duplex is the default - if (!capture && !playback) - { + if (!capture && !playback) { capture = TRUE; playback = TRUE; }