git-svn-id: svn+ssh://jackaudio.org/trunk/jack@1177 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.115.6
@@ -789,5 +789,6 @@ echo \| Default driver backend................................ : $JACK_DEFAULT_D | |||
echo \| Shared memory interface............................... : $JACK_SHM_TYPE | |||
echo \| IPC Temporary directory............................... : $DEFAULT_TMP_DIR | |||
echo \| Install prefix........................................ : $prefix | |||
echo \| Default tmp dir....................................... : $DEFAULT_TMP_DIR | |||
echo | |||
@@ -116,6 +116,7 @@ struct _jack_engine { | |||
int reordered; | |||
int watchdog_check; | |||
int feedbackcount; | |||
int removing_clients; | |||
pid_t wait_pid; | |||
pthread_t freewheel_thread; | |||
int nozombies; | |||
@@ -95,7 +95,7 @@ static inline char* jack_shm_addr (jack_shm_info_t* si) { | |||
/* here beginneth the API */ | |||
extern int jack_register_server (const char *server_name); | |||
extern int jack_register_server (const char *server_name, int new_registry); | |||
extern void jack_unregister_server (const char *server_name); | |||
extern int jack_initialize_shm (const char *server_name); | |||
@@ -25,6 +25,7 @@ | |||
#include <errno.h> | |||
#include <stdio.h> | |||
#include <unistd.h> | |||
#include <string.h> | |||
#include <jack/internal.h> | |||
@@ -37,8 +38,6 @@ | |||
#include "clientengine.h" | |||
#include "transengine.h" | |||
#define JACK_ERROR_WITH_SOCKETS 10000000 | |||
static void | |||
jack_client_disconnect_ports (jack_engine_t *engine, | |||
jack_client_internal_t *client) | |||
@@ -68,7 +67,10 @@ jack_client_do_deactivate (jack_engine_t *engine, | |||
jack_client_internal_t *client, int sort_graph) | |||
{ | |||
/* caller must hold engine->client_lock and must have checked for and/or | |||
* cleared all connections held by client. */ | |||
* cleared all connections held by client. | |||
*/ | |||
VERBOSE(engine,"+++ deactivate %s", client->control->name); | |||
client->control->active = FALSE; | |||
jack_transport_client_exit (engine, client); | |||
@@ -77,7 +79,7 @@ jack_client_do_deactivate (jack_engine_t *engine, | |||
engine->external_client_cnt > 0) { | |||
engine->external_client_cnt--; | |||
} | |||
if (sort_graph) { | |||
jack_sort_graph (engine); | |||
} | |||
@@ -166,6 +168,12 @@ jack_remove_clients (jack_engine_t* engine) | |||
JSList *tmp, *node; | |||
int need_sort = FALSE; | |||
jack_client_internal_t *client; | |||
if (engine->removing_clients) { | |||
return; | |||
} | |||
engine->removing_clients++; | |||
/* remove all dead clients */ | |||
@@ -174,6 +182,8 @@ jack_remove_clients (jack_engine_t* engine) | |||
tmp = jack_slist_next (node); | |||
client = (jack_client_internal_t *) node->data; | |||
VERBOSE(engine, "client %s error status %d", client->control->name, client->error); | |||
if (client->error) { | |||
@@ -220,6 +230,8 @@ jack_remove_clients (jack_engine_t* engine) | |||
} | |||
jack_engine_reset_rolling_usecs (engine); | |||
engine->removing_clients--; | |||
} | |||
static int | |||
@@ -848,6 +860,10 @@ jack_client_disconnect (jack_engine_t *engine, int fd) | |||
if (((jack_client_internal_t *) node->data)->request_fd == fd) { | |||
client = (jack_client_internal_t *) node->data; | |||
VERBOSE (engine, "marking socket error on client %s state = " | |||
"%s errors = %d", client->control->name, | |||
jack_client_state_name (client), | |||
client->error); | |||
if (client->error < JACK_ERROR_WITH_SOCKETS) { | |||
client->error += JACK_ERROR_WITH_SOCKETS; | |||
} | |||
@@ -961,3 +977,4 @@ jack_intclient_unload_request (jack_engine_t *engine, jack_request_t *req) | |||
req->status = JackFailure; | |||
} | |||
} | |||
@@ -40,6 +40,8 @@ jack_client_state_name (jack_client_internal_t *client) | |||
return client_state_names[client->control->state]; | |||
} | |||
#define JACK_ERROR_WITH_SOCKETS 10000000 | |||
int jack_client_activate (jack_engine_t *engine, jack_client_id_t id); | |||
int jack_client_deactivate (jack_engine_t *engine, jack_client_id_t id); | |||
int jack_client_create (jack_engine_t *engine, int client_fd); | |||
@@ -1018,8 +1018,9 @@ jack_load_driver (jack_engine_t *engine, jack_driver_desc_t * driver_desc) | |||
void | |||
jack_driver_unload (jack_driver_t *driver) | |||
{ | |||
void* handle = driver->handle; | |||
driver->finish (driver); | |||
dlclose (driver->handle); | |||
dlclose (handle); | |||
} | |||
int | |||
@@ -1471,6 +1472,7 @@ jack_server_thread (void *arg) | |||
} | |||
if (pfd[i].revents & ~POLLIN) { | |||
VERBOSE (engine, "client poll reports non-input condition, fd was %d", pfd[i].fd); | |||
jack_client_disconnect (engine, pfd[i].fd); | |||
} else if (pfd[i].revents & POLLIN) { | |||
if (handle_external_client_request | |||
@@ -1630,6 +1632,7 @@ jack_engine_new (int realtime, int rtpriority, int do_mlock, int do_unlock, | |||
engine->feedbackcount = 0; | |||
engine->wait_pid = wait_pid; | |||
engine->nozombies = nozombies; | |||
engine->removing_clients = 0; | |||
engine->audio_out_cnt = 0; | |||
engine->audio_in_cnt = 0; | |||
@@ -1815,7 +1818,6 @@ jack_engine_new (int realtime, int rtpriority, int do_mlock, int do_unlock, | |||
static void | |||
jack_engine_delay (jack_engine_t *engine, float delayed_usecs) | |||
{ | |||
JSList *node; | |||
jack_event_t event; | |||
engine->control->frame_timer.reset_pending = 1; | |||
@@ -1827,13 +1829,7 @@ jack_engine_delay (jack_engine_t *engine, float delayed_usecs) | |||
event.type = XRun; | |||
jack_lock_graph (engine); | |||
for (node = engine->clients; node; node = jack_slist_next (node)) { | |||
jack_deliver_event (engine, | |||
(jack_client_internal_t *) node->data, | |||
&event); | |||
} | |||
jack_unlock_graph (engine); | |||
jack_deliver_event_to_all (engine, &event); | |||
} | |||
static inline void | |||
@@ -2265,6 +2261,7 @@ jack_deliver_event_to_all (jack_engine_t *engine, jack_event_t *event) | |||
event); | |||
} | |||
jack_unlock_graph (engine); | |||
jack_remove_clients (engine); | |||
} | |||
static void | |||
@@ -2307,9 +2304,8 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, | |||
our check on a client's continued well-being | |||
*/ | |||
if (client->control->dead | |||
|| (client->control->type == ClientExternal | |||
&& kill (client->control->pid, 0))) { | |||
if (client->control->dead || client->error >= JACK_ERROR_WITH_SOCKETS | |||
|| (client->control->type == ClientExternal && kill (client->control->pid, 0))) { | |||
DEBUG ("client %s is dead - no event sent", | |||
client->control->name); | |||
return 0; | |||
@@ -2378,32 +2374,74 @@ jack_deliver_event (jack_engine_t *engine, jack_client_internal_t *client, | |||
jack_error ("cannot send event to client [%s]" | |||
" (%s)", client->control->name, | |||
strerror (errno)); | |||
client->error++; | |||
} | |||
DEBUG ("engine reading from event fd"); | |||
if (!client->error && | |||
(read (client->event_fd, &status, sizeof (status)) | |||
!= sizeof (status))) { | |||
jack_error ("cannot read event response from " | |||
"client [%s] (%s)", | |||
client->control->name, | |||
strerror (errno)); | |||
client->error++; | |||
client->error = JACK_ERROR_WITH_SOCKETS+99; | |||
} | |||
DEBUG ("engine reading from event fd DONE"); | |||
if (status != 0) { | |||
jack_error ("bad status for client event " | |||
"handling (type = %d)", | |||
event->type); | |||
client->error++; | |||
} | |||
if (client->error) { | |||
status = 1; | |||
} else { | |||
// then we check whether there really is an error.... :) | |||
struct pollfd pfd[1]; | |||
pfd[0].fd = client->event_fd; | |||
//pfd[0].events = POLLERR|POLLIN|POLLHUP|POLLNVAL; | |||
pfd[0].events = POLLIN; | |||
int poll_timeout = (engine->client_timeout_msecs > 0 ? | |||
engine->client_timeout_msecs : | |||
1 + engine->driver->period_usecs/1000); | |||
//poll_timeout = 200; | |||
//poll_timeout = 30000; // 30 seconds | |||
int poll_ret; | |||
// printf("################ poll_timeout = %d (%d or 1 + %d/1000)\n", poll_timeout, engine->client_timeout_msecs, engine->driver->period_usecs); | |||
if ( (poll_ret = poll (pfd, 1, poll_timeout)) < 0) { | |||
DEBUG ("client event poll not ok! (-1) poll returned an error"); | |||
jack_error ("poll on subgraph processing failed (%s)", strerror (errno)); | |||
status = -1; | |||
} else { | |||
DEBUG ("\n\n\n\n\n back from client event poll, revents = 0x%x\n\n\n", pfd[0].revents); | |||
if (pfd[0].revents & ~POLLIN) { | |||
DEBUG ("client event poll not ok! (-2), revents = %d\n", pfd[0].revents); | |||
jack_error ("subgraph starting at %s lost client", client->control->name); | |||
status = -2; | |||
} | |||
if (pfd[0].revents & POLLIN) { | |||
DEBUG ("client event poll ok!"); | |||
status = 0; | |||
} else { | |||
DEBUG ("client event poll not ok! (1 = poll timed out, revents = 0x%04x, poll_ret = %d)", pfd[0].revents, poll_ret); | |||
jack_error ("subgraph starting at %s timed out " | |||
"(subgraph_wait_fd=%d, status = %d, state = %s, revents = 0x%04x)", | |||
client->control->name, | |||
client->subgraph_wait_fd, status, | |||
jack_client_state_name (client), pfd[0].revents); | |||
status = 1; | |||
} | |||
} | |||
} | |||
if (status == 0) { | |||
if (read (client->event_fd, &status, sizeof (status)) != sizeof (status)) { | |||
jack_error ("cannot read event response from " | |||
"client [%s] (%s)", | |||
client->control->name, | |||
strerror (errno)); | |||
client->error = JACK_ERROR_WITH_SOCKETS+99; | |||
} | |||
} else { | |||
jack_error ("bad status (%d) for client event " | |||
"handling (type = %d)", | |||
status,event->type); | |||
client->error = JACK_ERROR_WITH_SOCKETS+99; | |||
} | |||
} | |||
} | |||
DEBUG ("event delivered"); | |||
return 0; | |||
@@ -2431,6 +2469,10 @@ jack_rechain_graph (jack_engine_t *engine) | |||
next = jack_slist_next (node); | |||
VERBOSE(engine, "+++ client is now %s active ? %d", | |||
((jack_client_internal_t *) node->data)->control->name, | |||
((jack_client_internal_t *) node->data)->control->active); | |||
if (((jack_client_internal_t *) node->data)->control->active) { | |||
client = (jack_client_internal_t *) node->data; | |||
@@ -2560,6 +2602,8 @@ jack_rechain_graph (jack_engine_t *engine) | |||
subgraph_client->subgraph_wait_fd, n); | |||
} | |||
jack_remove_clients (engine); | |||
VERBOSE (engine, "-- jack_rechain_graph()"); | |||
return err; | |||
@@ -3161,6 +3205,8 @@ jack_port_do_connect (jack_engine_t *engine, | |||
} | |||
jack_unlock_graph (engine); | |||
jack_remove_clients (engine); | |||
return 0; | |||
} | |||
@@ -3262,6 +3308,8 @@ jack_port_disconnect_internal (jack_engine_t *engine, | |||
} | |||
} | |||
jack_remove_clients (engine); | |||
if (check_acyclic) { | |||
jack_check_acyclic (engine); | |||
} | |||
@@ -3785,6 +3833,8 @@ jack_port_registration_notify (jack_engine_t *engine, | |||
} | |||
} | |||
} | |||
jack_remove_clients (engine); | |||
} | |||
void | |||
@@ -3820,6 +3870,8 @@ jack_client_registration_notify (jack_engine_t *engine, | |||
} | |||
} | |||
} | |||
jack_remove_clients (engine); | |||
} | |||
int | |||
@@ -58,6 +58,13 @@ variable. It will be "default" if that is not defined. | |||
Set the maximum number of ports the JACK server can manage. | |||
The default value is 256. | |||
.TP | |||
\fB\-r, \-\-replace-registry\fR | |||
.br | |||
Remove the shared memory registry used by all JACK server instances | |||
before startup. This should rarely be used, and is intended only | |||
for occasions when the structure of this registry changes in ways | |||
that are incompatible across JACK versions (which is rare). | |||
.TP | |||
\fB\-R, \-\-realtime\fR | |||
.br | |||
Use realtime scheduling. This is needed for reliable low\-latency | |||
@@ -371,6 +371,7 @@ static void usage (FILE *file) | |||
" [ --debug-timer OR -D ]\n" | |||
" [ --verbose OR -v ]\n" | |||
" [ --clocksource OR -c [ c(ycle) | h(pet) | s(ystem) ]\n" | |||
" [ --replace-registry OR -r ]\n" | |||
" [ --silent OR -s ]\n" | |||
" [ --version OR -V ]\n" | |||
" [ --nozombies OR -Z ]\n" | |||
@@ -520,6 +521,7 @@ main (int argc, char *argv[]) | |||
{ "name", 1, 0, 'n' }, | |||
{ "unlock", 0, 0, 'u' }, | |||
{ "realtime", 0, 0, 'R' }, | |||
{ "replace-registry", 0, 0, 'r' }, | |||
{ "realtime-priority", 1, 0, 'P' }, | |||
{ "timeout", 1, 0, 't' }, | |||
{ "temporary", 0, 0, 'T' }, | |||
@@ -537,6 +539,7 @@ main (int argc, char *argv[]) | |||
JSList * driver_params; | |||
int driver_nargs = 1; | |||
int show_version = 0; | |||
int replace_registry = 0; | |||
int i; | |||
int rc; | |||
@@ -593,6 +596,10 @@ main (int argc, char *argv[]) | |||
realtime_priority = atoi (optarg); | |||
break; | |||
case 'r': | |||
replace_registry = 1; | |||
break; | |||
case 'R': | |||
realtime = 1; | |||
break; | |||
@@ -695,7 +702,7 @@ main (int argc, char *argv[]) | |||
copyright (stdout); | |||
rc = jack_register_server (server_name); | |||
rc = jack_register_server (server_name, replace_registry); | |||
switch (rc) { | |||
case EEXIST: | |||
fprintf (stderr, "`%s' server already active\n", server_name); | |||
@@ -1301,6 +1301,8 @@ jack_client_process_events (jack_client_t* client) | |||
JSList *node; | |||
jack_port_t* port; | |||
DEBUG ("process events"); | |||
if (client->pollfd[EVENT_POLL_INDEX].revents & POLLIN) { | |||
DEBUG ("client receives an event, " | |||
@@ -1683,14 +1685,26 @@ jack_client_thread_aux (void *arg) | |||
/* wait for first wakeup from server */ | |||
if (jack_thread_first_wait (client) == control->nframes) { | |||
/* now run till we're done */ | |||
if (control->process) { | |||
/* run process callback, then wait... ad-infinitum */ | |||
while (jack_thread_wait (client, | |||
control->process (control->nframes, | |||
control->process_arg)) == | |||
control->nframes) | |||
; | |||
while (1) { | |||
DEBUG("client calls process()"); | |||
int status = (control->process (control->nframes, | |||
control->process_arg) == | |||
control->nframes); | |||
control->state = Finished; | |||
DEBUG("client leaves process(), re-enters wait"); | |||
if (!jack_thread_wait (client, status)) { | |||
break; | |||
} | |||
DEBUG("client done with wait"); | |||
} | |||
} else { | |||
/* no process handling but still need to process events */ | |||
while (jack_thread_wait (client, 0) == control->nframes) | |||
@@ -243,7 +243,7 @@ jack_set_server_prefix (const char *server_name) | |||
* returns: 0 if successful | |||
*/ | |||
static int | |||
jack_server_initialize_shm (void) | |||
jack_server_initialize_shm (int new_registry) | |||
{ | |||
int rc; | |||
@@ -254,6 +254,11 @@ jack_server_initialize_shm (void) | |||
rc = jack_access_registry (®istry_info); | |||
if (new_registry) { | |||
jack_remove_shm (®istry_id); | |||
rc = ENOENT; | |||
} | |||
switch (rc) { | |||
case ENOENT: /* registry does not exist */ | |||
rc = jack_create_registry (®istry_info); | |||
@@ -302,6 +307,7 @@ jack_initialize_shm (const char *server_name) | |||
jack_set_server_prefix (server_name); | |||
jack_shm_lock_registry (); | |||
if ((rc = jack_access_registry (®istry_info)) == 0) { | |||
if ((rc = jack_shm_validate_registry ()) != 0) { | |||
jack_error ("Incompatible shm registry, " | |||
@@ -373,7 +379,7 @@ jack_release_shm_info (jack_shm_registry_index_t index) | |||
* ENOMEM if unable to access shared memory registry | |||
*/ | |||
int | |||
jack_register_server (const char *server_name) | |||
jack_register_server (const char *server_name, int new_registry) | |||
{ | |||
int i; | |||
pid_t my_pid = getpid (); | |||
@@ -382,7 +388,7 @@ jack_register_server (const char *server_name) | |||
jack_info ("JACK compiled with %s SHM support.", JACK_SHM_TYPE); | |||
if (jack_server_initialize_shm ()) | |||
if (jack_server_initialize_shm (new_registry)) | |||
return ENOMEM; | |||
jack_shm_lock_registry (); | |||