From 9c0761b379954dadcbaa6588f21f23aa77fd9aea Mon Sep 17 00:00:00 2001 From: sletz Date: Wed, 12 Mar 2008 11:10:29 +0000 Subject: [PATCH] Automatic server launch in wrapper layer. git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@1955 0c269be4-1314-0410-8aa9-9f06e86f4224 --- ChangeLog | 1 + Todo | 2 +- common/JackAPIWrapper.cpp | 147 ++++++++++++++++++++++++++++++---- common/JackInternalClient.cpp | 5 ++ 4 files changed, 140 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index f351d853..5aecd447 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,7 @@ Nedko Arnaudov * Marc-Olivier Barre library related scons patch. * Nedko Arnaudov FULL_MIMIC patch. + * Automatic server launch in wrapper layer. 2008-03-11 Stephane Letz diff --git a/Todo b/Todo index dd848d7d..dd403148 100644 --- a/Todo +++ b/Todo @@ -3,7 +3,7 @@ --------------------- -2008-03-12 : Do not start the client RT thread if no callback or thread routine has been setup (no use of jack_set_process_callback or jack_set_process_thread). This require change in the server to avoid signaling the client in this case. +2008-03-12 : Do not start the client RT thread if no callback or thread routine has been setup (no use of jack_set_process_callback or jack_set_process_thread). This require change in the server to avoid signaling the client in this case. Check direct access from server internal clients (see comment in JackInternalClient::JackInternalClient() in JackInternalClient.cpp) 2008-02-07 : Pipelining idea: diff --git a/common/JackAPIWrapper.cpp b/common/JackAPIWrapper.cpp index fe7b32ba..c7cb9773 100644 --- a/common/JackAPIWrapper.cpp +++ b/common/JackAPIWrapper.cpp @@ -20,13 +20,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "types.h" #include "jack.h" #include "JackExports.h" - -// TODO -//#include "varargs.h" -//#include "JackTools.h" -//#include "JackConstants.h" -//#include "JackServerLaunch.h" - +#include "varargs.h" +#include "JackConstants.h" #include #include #include @@ -213,9 +208,6 @@ extern "C" } #endif -// TODO -//using namespace Jack; - #define JACK_LIB "libjack.so.0.0" #define JACKMP_LIB "libjackmp.so" @@ -227,6 +219,136 @@ static void close_library(); static void (*error_fun)(const char *) = 0; static void (*info_fun)(const char *) = 0; +static void RewriteName(const char* name, char* new_name) +{ + size_t i; + for (i = 0; i < strlen(name); i++) { + if ((name[i] == '/') || (name[i] == '\\')) + new_name[i] = '_'; + else + new_name[i] = name[i]; + } + new_name[i] = '\0'; +} + +/* Exec the JACK server in this process. Does not return. */ +static void start_server_aux(const char* server_name) +{ + FILE* fp = 0; + char filename[255]; + char arguments[255]; + char buffer[255]; + char* command = 0; + size_t pos = 0; + size_t result = 0; + char** argv = 0; + int i = 0; + int good = 0; + int ret; + + snprintf(filename, 255, "%s/.jackdrc", getenv("HOME")); + fp = fopen(filename, "r"); + + if (!fp) { + fp = fopen("/etc/jackdrc", "r"); + } + /* if still not found, check old config name for backwards compatability */ + if (!fp) { + fp = fopen("/etc/jackd.conf", "r"); + } + + if (fp) { + arguments[0] = '\0'; + ret = fscanf(fp, "%s", buffer); + while (ret != 0 && ret != EOF) { + strcat(arguments, buffer); + strcat(arguments, " "); + ret = fscanf(fp, "%s", buffer); + } + if (strlen(arguments) > 0) { + good = 1; + } + fclose(fp); + } + + if (!good) { + command = (char*)(JACK_LOCATION "/jackd"); + strncpy(arguments, JACK_LOCATION "/jackd -T -d "JACK_DEFAULT_DRIVER, 255); + } else { + result = strcspn(arguments, " "); + command = (char*)malloc(result + 1); + strncpy(command, arguments, result); + command[result] = '\0'; + } + + argv = (char**)malloc(255); + + while (1) { + /* insert -T and -nserver_name in front of arguments */ + if (i == 1) { + argv[i] = (char*)malloc(strlen ("-T") + 1); + strcpy (argv[i++], "-T"); + if (server_name) { + size_t optlen = strlen("-n"); + char* buf = (char*)malloc(optlen + strlen(server_name) + 1); + strcpy(buf, "-n"); + strcpy(buf + optlen, server_name); + argv[i++] = buf; + } + } + + result = strcspn(arguments + pos, " "); + if (result == 0) { + break; + } + argv[i] = (char*)malloc(result + 1); + strncpy(argv[i], arguments + pos, result); + argv[i][result] = '\0'; + pos += result + 1; + ++i; + } + argv[i] = 0; + execv(command, argv); + + /* If execv() succeeds, it does not return. There's no point + * in calling jack_error() here in the child process. */ + fprintf(stderr, "exec of JACK server (command = \"%s\") failed: %s\n", command, strerror(errno)); +} + +int start_server(const char* server_name, jack_options_t options) +{ + if ((options & JackNoStartServer) || getenv("JACK_NO_START_SERVER")) { + return 1; + } + + /* The double fork() forces the server to become a child of + * init, which will always clean up zombie process state on + * termination. This even works in cases where the server + * terminates but this client does not. + * + * Since fork() is usually implemented using copy-on-write + * virtual memory tricks, the overhead of the second fork() is + * probably relatively small. + */ + switch (fork()) { + case 0: /* child process */ + switch (fork()) { + case 0: /* grandchild process */ + start_server_aux(server_name); + _exit(99); /* exec failed */ + case - 1: + _exit(98); + default: + _exit(0); + } + case - 1: /* fork() error */ + return 1; /* failed to start server */ + } + + /* only the original parent process goes here */ + return 0; /* (probably) successful */ +} + static void jack_log(const char *fmt,...) { /* @@ -1016,7 +1138,6 @@ EXPORT jack_client_t * jack_client_open(const char *ext_client_name, jack_option return res; } else { - /* jack_varargs_t va; // variable arguments jack_status_t my_status; char client_name[JACK_CLIENT_NAME_SIZE]; @@ -1026,7 +1147,7 @@ EXPORT jack_client_t * jack_client_open(const char *ext_client_name, jack_option return NULL; } - JackTools::RewriteName(ext_client_name, client_name); + RewriteName(ext_client_name, client_name); if (status == NULL) // no status from caller? status = &my_status; // use local status word @@ -1056,8 +1177,6 @@ EXPORT jack_client_t * jack_client_open(const char *ext_client_name, jack_option } else { return NULL; } - */ - return NULL; } } diff --git a/common/JackInternalClient.cpp b/common/JackInternalClient.cpp index aebf1a5d..65604755 100644 --- a/common/JackInternalClient.cpp +++ b/common/JackInternalClient.cpp @@ -56,6 +56,11 @@ JackSynchro** GetSynchroTable() JackInternalClient::JackInternalClient(JackServer* server, JackSynchro** table): JackClient(table) { fClientControl = new JackClientControl(); + /* + TODO: here we use a "direct access" to server internal, which is not safe if library clients access the server using + the "command thread" at the same time. So using the "command thread" also for internal clients would be safer. + We may want to keep the "direct access" to server internal mode for "server embeded in client process" kind of use. + */ fChannel = new JackInternalClientChannel(server); }