Commit 171a3c4a authored by sletz's avatar sletz
Browse files

Client and library global context cleanup in case of incorrect shutdown...

Client and library global context cleanup in case of incorrect shutdown handling (that is applications not correctly closing client after server has shutdown).

git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@3207 0c269be4-1314-0410-8aa9-9f06e86f4224
parent 14772699
......@@ -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
\ No newline at end of file
......@@ -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;
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment