Browse Source

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
tags/1.9.1
sletz 16 years ago
parent
commit
171a3c4a0d
16 changed files with 108 additions and 61 deletions
  1. +4
    -0
      ChangeLog
  2. +5
    -5
      common/JackAPI.cpp
  3. +5
    -11
      common/JackClient.cpp
  4. +1
    -7
      common/JackClient.h
  5. +0
    -2
      common/JackClientControl.h
  6. +5
    -3
      common/JackError.cpp
  7. +12
    -5
      common/JackGlobals.cpp
  8. +17
    -4
      common/JackGlobals.h
  9. +3
    -1
      common/JackInternalClient.cpp
  10. +6
    -6
      common/JackLibAPI.cpp
  11. +3
    -2
      common/JackLibClient.cpp
  12. +22
    -1
      common/JackLibGlobals.h
  13. +6
    -6
      common/JackServerAPI.cpp
  14. +0
    -2
      common/ringbuffer.c
  15. +16
    -1
      tests/external_metro.cpp
  16. +3
    -5
      windows/portaudio/JackPortAudioDriver.cpp

+ 4
- 0
ChangeLog View File

@@ -23,6 +23,10 @@ Michael Voigt
Jackdmp changes log 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> 2008-11-27 Stephane Letz <letz@grame.fr>


* Report ringbuffer.c fixes from jack1. * Report ringbuffer.c fixes from jack1.


+ 5
- 5
common/JackAPI.cpp View File

@@ -259,7 +259,7 @@ static inline void WaitGraphChange()
graph change in RT context (just read the current graph state). 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(); JackGraphManager* manager = GetGraphManager();
JackEngineControl* control = GetEngineControl(); JackEngineControl* control = GetEngineControl();
assert(manager); 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) 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"); jack_error("jack_client_new: deprecated");
int options = JackUseExactName; int options = JackUseExactName;
if (getenv("JACK_START_SERVER") == NULL) if (getenv("JACK_START_SERVER") == NULL)
options |= JackNoStartServer; options |= JackNoStartServer;
jack_client_t* res = jack_client_open_aux(client_name, (jack_options_t)options, NULL, NULL); jack_client_t* res = jack_client_open_aux(client_name, (jack_options_t)options, NULL, NULL);
gOpenMutex->Unlock();
JackGlobals::fOpenMutex->Unlock();
return res; return res;
} }


@@ -628,7 +628,7 @@ EXPORT int jack_port_set_name(jack_port_t* port, const char* name)
JackGraphManager* manager = GetGraphManager(); JackGraphManager* manager = GetGraphManager();
int refnum; int refnum;
if (manager && ((refnum = manager->GetPort(myport)->GetRefNum()) > 0)) { if (manager && ((refnum = manager->GetPort(myport)->GetRefNum()) > 0)) {
JackClient* client = JackClient::fClientTable[refnum];
JackClient* client = JackGlobals::fClientTable[refnum];
assert(client); assert(client);
return client->PortRename(myport, name); return client->PortRename(myport, name);
} else { } else {


+ 5
- 11
common/JackClient.cpp View File

@@ -37,8 +37,6 @@ using namespace std;
namespace Jack namespace Jack
{ {


JackClient* JackClient::fClientTable[CLIENT_NUM] = {};

#define IsRealTime() ((fProcess != NULL) | (fThreadFun != NULL) | (fSync != NULL) | (fTimebase != NULL)) #define IsRealTime() ((fProcess != NULL) | (fThreadFun != NULL) | (fSync != NULL) | (fTimebase != NULL))


JackClient::JackClient():fThread(this) JackClient::JackClient():fThread(this)
@@ -88,8 +86,8 @@ int JackClient::Close()
Deactivate(); Deactivate();
fChannel->Stop(); // Channels is stopped first to avoid receiving notifications while closing 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); fChannel->ClientClose(GetClientControl()->fRefNum, &result);
} else { } else {
jack_log("JackClient::Close server is shutdown"); jack_log("JackClient::Close server is shutdown");
@@ -97,7 +95,7 @@ int JackClient::Close()
fChannel->Close(); fChannel->Close();
fSynchroTable[GetClientControl()->fRefNum].Disconnect(); fSynchroTable[GetClientControl()->fRefNum].Disconnect();
fClientTable[GetClientControl()->fRefNum] = NULL;
JackGlobals::fClientTable[GetClientControl()->fRefNum] = NULL;
return result; return result;
} }


@@ -359,7 +357,7 @@ int JackClient::StartThread()
*/ */
bool JackClient::Execute() bool JackClient::Execute()
{ {
if (!jack_tls_set(gRealTime, this))
if (!jack_tls_set(JackGlobals::fRealTime, this))
jack_error("failed to set thread realtime key"); jack_error("failed to set thread realtime key");
if (GetEngineControl()->fRealTime) if (GetEngineControl()->fRealTime)
@@ -596,11 +594,7 @@ ShutDown is called:
void JackClient::ShutDown() void JackClient::ShutDown()
{ {
jack_log("ShutDown"); jack_log("ShutDown");
// Be sure client is already started
if (GetClientControl()) {
GetClientControl()->fServer = false;
}
JackGlobals::fServerRunning = false;
if (fShutdown) { if (fShutdown) {
fShutdown(fShutdownArg); fShutdown(fShutdownArg);


+ 1
- 7
common/JackClient.h View File

@@ -87,8 +87,7 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
detail::JackClientChannelInterface* fChannel; detail::JackClientChannelInterface* fChannel;
JackSynchro* fSynchroTable; JackSynchro* fSynchroTable;
std::list<jack_port_id_t> fPortList; std::list<jack_port_id_t> fPortList;
bool fServerRunning;

int StartThread(); int StartThread();
void SetupDriverSync(bool freewheel); void SetupDriverSync(bool freewheel);
bool IsActive(); 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); virtual int ClientNotifyImp(int refnum, const char* name, int notify, int sync, int value1, int value);


// Fons Adriaensen thread model
inline bool WaitFirstSync(); inline bool WaitFirstSync();
inline void ExecuteThread(); inline void ExecuteThread();
inline bool WaitSync(); inline bool WaitSync();
@@ -140,7 +138,6 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
virtual int PortDisconnect(jack_port_id_t src); virtual int PortDisconnect(jack_port_id_t src);


virtual int PortIsMine(jack_port_id_t port_index); virtual int PortIsMine(jack_port_id_t port_index);
virtual int PortRename(jack_port_id_t port_index, const char* name); virtual int PortRename(jack_port_id_t port_index, const char* name);


// Transport // Transport
@@ -185,9 +182,6 @@ class JackClient : public JackClientInterface, public JackRunnableInterface
// JackRunnableInterface interface // JackRunnableInterface interface
bool Init(); bool Init();
bool Execute(); 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. // Each "side" server and client will implement this to get the shared graph manager, engine control and inter-process synchro table.


+ 0
- 2
common/JackClientControl.h View File

@@ -43,7 +43,6 @@ struct JackClientControl : public JackShmMemAble
int fRefNum; int fRefNum;
int fPID; int fPID;
bool fActive; bool fActive;
bool fServer;


JackClientControl(const char* name, int pid, int refnum) JackClientControl(const char* name, int pid, int refnum)
{ {
@@ -78,7 +77,6 @@ struct JackClientControl : public JackShmMemAble
fTransportSync = false; fTransportSync = false;
fTransportTimebase = false; fTransportTimebase = false;
fActive = false; fActive = false;
fServer = true;
} }


}; };


+ 5
- 3
common/JackError.cpp View File

@@ -27,9 +27,11 @@


int jack_verbose = 0; int jack_verbose = 0;


using namespace Jack;

void change_thread_log_function(jack_log_function_t log_function) 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"); 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() 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) 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); 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 is not overriden for thread, use default one */
if (log_function == NULL) if (log_function == NULL)


+ 12
- 5
common/JackGlobals.cpp View File

@@ -19,10 +19,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.


#include "JackGlobals.h" #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

+ 17
- 4
common/JackGlobals.h View File

@@ -21,11 +21,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define __JackGlobals__ #define __JackGlobals__


#include "JackPlatformPlug.h" #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 #endif

+ 3
- 1
common/JackInternalClient.cpp View File

@@ -141,7 +141,9 @@ int JackInternalClient::Open(const char* server_name, const char* name, jack_opt
} }


SetupDriverSync(false); 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; return 0;


error: error:


+ 6
- 6
common/JackLibAPI.cpp View File

@@ -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, ...) 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_list ap;
va_start(ap, status); va_start(ap, status);
jack_client_t* res = jack_client_open_aux(ext_client_name, options, status, ap); jack_client_t* res = jack_client_open_aux(ext_client_name, options, status, ap);
va_end(ap); va_end(ap);
gOpenMutex->Unlock();
JackGlobals::fOpenMutex->Unlock();
return res; return res;
} }


EXPORT int jack_client_close(jack_client_t* ext_client) EXPORT int jack_client_close(jack_client_t* ext_client)
{ {
assert(gOpenMutex);
gOpenMutex->Lock();
assert(JackGlobals::fOpenMutex);
JackGlobals::fOpenMutex->Lock();
int res = -1; int res = -1;
jack_log("jack_client_close"); jack_log("jack_client_close");
JackClient* client = (JackClient*)ext_client; JackClient* client = (JackClient*)ext_client;
@@ -138,7 +138,7 @@ EXPORT int jack_client_close(jack_client_t* ext_client)
JackLibGlobals::Destroy(); // jack library destruction JackLibGlobals::Destroy(); // jack library destruction
jack_log("jack_client_close res = %d", res); jack_log("jack_client_close res = %d", res);
} }
gOpenMutex->Unlock();
JackGlobals::fOpenMutex->Unlock();
return res; return res;
} }




+ 3
- 2
common/JackLibClient.cpp View File

@@ -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 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; 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); snprintf(fServerName, sizeof(fServerName), server_name);


@@ -113,7 +113,8 @@ int JackLibClient::Open(const char* server_name, const char* name, jack_options_
goto error; 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); jack_log("JackLibClient::Open name = %s refnum = %ld", name_res, GetClientControl()->fRefNum);
return 0; return 0;




+ 22
- 1
common/JackLibGlobals.h View File

@@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "JackGraphManager.h" #include "JackGraphManager.h"
#include "JackMessageBuffer.h" #include "JackMessageBuffer.h"
#include "JackTime.h" #include "JackTime.h"
#include "JackClient.h"
#include "JackError.h" #include "JackError.h"
#include <assert.h> #include <assert.h>
#include <signal.h> #include <signal.h>
@@ -44,7 +45,7 @@ struct JackLibGlobals
{ {
JackShmReadWritePtr<JackGraphManager> fGraphManager; /*! Shared memory Port manager */ JackShmReadWritePtr<JackGraphManager> fGraphManager; /*! Shared memory Port manager */
JackShmReadWritePtr<JackEngineControl> fEngineControl; /*! Shared engine control */ // transport engine has to be writable 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; sigset_t fProcessSignals;
static int fClientCount; static int fClientCount;
@@ -86,6 +87,26 @@ struct JackLibGlobals


static void Init() 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) { if (fClientCount++ == 0 && !fGlobals) {
jack_log("JackLibGlobals Init %x", fGlobals); jack_log("JackLibGlobals Init %x", fGlobals);
InitTime(); InitTime();


+ 6
- 6
common/JackServerAPI.cpp View File

@@ -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, ...) 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_list ap;
va_start(ap, status); va_start(ap, status);
jack_client_t* res = jack_client_open_aux(ext_client_name, options, status, ap); jack_client_t* res = jack_client_open_aux(ext_client_name, options, status, ap);
va_end(ap); va_end(ap);
gOpenMutex->Unlock();
JackGlobals::fOpenMutex->Unlock();
return res; return res;
} }


EXPORT int jack_client_close(jack_client_t* ext_client) EXPORT int jack_client_close(jack_client_t* ext_client)
{ {
assert(gOpenMutex);
gOpenMutex->Lock();
assert(JackGlobals::fOpenMutex);
JackGlobals::fOpenMutex->Lock();
int res = -1; int res = -1;
jack_log("jack_client_close"); jack_log("jack_client_close");
JackClient* client = (JackClient*)ext_client; 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); jack_log("jack_client_close res = %d", res);
} }
gOpenMutex->Unlock();
JackGlobals::fOpenMutex->Unlock();
return res; return res;
} }




+ 0
- 2
common/ringbuffer.c View File

@@ -27,8 +27,6 @@
#endif /* USE_MLOCK */ #endif /* USE_MLOCK */
#include "JackCompilerDeps.h" #include "JackCompilerDeps.h"


// TODO : what to do with Paul fixes done av rev 3014 (http://trac.jackaudio.org/changeset/3014)

typedef struct { typedef struct {
char *buf; char *buf;
size_t len; size_t len;


+ 16
- 1
tests/external_metro.cpp View File

@@ -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) { if ((client = jack_client_open (client_name, options, &status)) == 0) {
fprintf (stderr, "jack server not running?\n"); fprintf (stderr, "jack server not running?\n");
return;
throw -1;
} }


jack_set_process_callback (client, process_audio, this); jack_set_process_callback (client, process_audio, this);
@@ -184,6 +184,21 @@ int main (int argc, char *argv[])


printf("Opening a new client....\n"); printf("Opening a new client....\n");
client1 = new ExternalMetro(1200, 0.4, 20, 80, "t1"); 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"); printf("Type 'q' to quit...\n");
while ((getchar() != 'q')) { while ((getchar() != 'q')) {


+ 3
- 5
windows/portaudio/JackPortAudioDriver.cpp View File

@@ -174,7 +174,7 @@ namespace Jack


error: error:
JackAudioDriver::Close(); 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; return -1;
} }


@@ -436,8 +436,7 @@ extern "C"


case 'P': case 'P':
playback = TRUE; playback = TRUE;
if (strcmp(param->value.str, "none") != 0)
{
if (strcmp(param->value.str, "none") != 0) {
playback_pcm_name = strdup(param->value.str); playback_pcm_name = strdup(param->value.str);
} }
break; break;
@@ -469,8 +468,7 @@ extern "C"
} }


// duplex is the default // duplex is the default
if (!capture && !playback)
{
if (!capture && !playback) {
capture = TRUE; capture = TRUE;
playback = TRUE; playback = TRUE;
} }


Loading…
Cancel
Save