git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3207 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.9.1
@@ -23,6 +23,10 @@ Michael Voigt | |||
Jackdmp changes log | |||
--------------------------- | |||
2008-11-16 Stephane Letz <letz@grame.fr> | |||
* 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 <letz@grame.fr> | |||
* Report ringbuffer.c fixes from jack1. | |||
@@ -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 { | |||
@@ -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); | |||
@@ -87,8 +87,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface | |||
detail::JackClientChannelInterface* fChannel; | |||
JackSynchro* fSynchroTable; | |||
std::list<jack_port_id_t> 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. | |||
@@ -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; | |||
} | |||
}; | |||
@@ -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) | |||
@@ -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 |
@@ -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 |
@@ -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: | |||
@@ -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; | |||
} | |||
@@ -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; | |||
@@ -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 <assert.h> | |||
#include <signal.h> | |||
@@ -44,7 +45,7 @@ struct JackLibGlobals | |||
{ | |||
JackShmReadWritePtr<JackGraphManager> fGraphManager; /*! Shared memory Port manager */ | |||
JackShmReadWritePtr<JackEngineControl> 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(); | |||
@@ -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; | |||
} | |||
@@ -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; | |||
@@ -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')) { | |||
@@ -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; | |||
} | |||