Browse Source

fix a possible race/deadlock when jack is quitting and clients try to connect; mention jack_free() and not free() in port buffer docs; fix failure to execute clients using wait API; tweak session mgmt code so that the SM can pass directory names with or without a trailing '/'; unload/finish internal clients at a better time to stop crashes; add new and as-yet not used and definitely unfinished a2j internal clients for ALSA/MIDI bridge

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@3981 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.120.1
paul 16 years ago
parent
commit
ca5bb796d3
9 changed files with 150 additions and 115 deletions
  1. +2
    -1
      configure.ac
  2. +3
    -2
      drivers/Makefile.am
  3. +12
    -15
      drivers/alsa/alsa_driver.c
  4. +1
    -0
      jack/engine.h
  5. +10
    -5
      jack/internal.h
  6. +3
    -3
      jack/jack.h
  7. +8
    -13
      jack/midiport.h
  8. +70
    -58
      jackd/clientengine.c
  9. +41
    -18
      jackd/engine.c

+ 2
- 1
configure.ac View File

@@ -844,7 +844,7 @@ then
[HAVE_ALSA="true"
ALSA_LIBS=-lasound
JACK_DEFAULT_DRIVER=\"alsa\"
], AC_MSG_RESULT([no]), [-lm]
], AC_MSG_RESULT([no - cannot find ALSA 1.0.18 or later]), [-lm]
)
AC_SUBST(ALSA_LIBS)
fi
@@ -928,6 +928,7 @@ doc/reference.doxygen
drivers/Makefile
drivers/alsa/Makefile
drivers/alsa-midi/Makefile
drivers/a2j/Makefile
drivers/dummy/Makefile
drivers/oss/Makefile
drivers/sun/Makefile


+ 3
- 2
drivers/Makefile.am View File

@@ -8,6 +8,7 @@ endif

if HAVE_ALSA_MIDI
ALSA_MIDI_DIR = alsa-midi
A2J_DIR = a2j
else
ALSA_MIDI_DIR =
endif
@@ -48,5 +49,5 @@ else
FIREWIRE_DIR =
endif

SUBDIRS = $(ALSA_MIDI_DIR) $(ALSA_DIR) dummy $(OSS_DIR) $(SUN_DIR) $(PA_DIR) $(CA_DIR) $(FREEBOB_DIR) $(FIREWIRE_DIR) netjack
DIST_SUBDIRS = alsa alsa-midi dummy oss sun portaudio coreaudio freebob firewire netjack
SUBDIRS = $(ALSA_MIDI_DIR) $(A2J_DIR) $(ALSA_DIR) dummy $(OSS_DIR) $(SUN_DIR) $(PA_DIR) $(CA_DIR) $(FREEBOB_DIR) $(FIREWIRE_DIR) netjack
DIST_SUBDIRS = alsa alsa-midi a2j dummy oss sun portaudio coreaudio freebob firewire netjack

+ 12
- 15
drivers/alsa/alsa_driver.c View File

@@ -1456,21 +1456,18 @@ alsa_driver_null_cycle (alsa_driver_t* driver, jack_nframes_t nframes)
if (nframes > driver->frames_per_cycle) {
return -1;
}
if (driver->capture_handle) {
if (driver->capture_handle) {
nf = nframes;
offset = 0;
while (nf) {
contiguous = nf;
if (snd_pcm_mmap_begin (
driver->capture_handle,
&driver->capture_areas,
(snd_pcm_uframes_t *) &offset,
(snd_pcm_uframes_t *) &contiguous)) {
return -1;
}
if (alsa_driver_get_channel_addresses (driver,
&contiguous, 0, &offset, 0)) {
return -1;
}

if (snd_pcm_mmap_commit (driver->capture_handle,
offset, contiguous) < 0) {
return -1;
@@ -1486,11 +1483,11 @@ alsa_driver_null_cycle (alsa_driver_t* driver, jack_nframes_t nframes)
while (nf) {
contiguous = nf;
if (alsa_driver_get_channel_addresses (driver,
0, &contiguous, 0, &offset)) {
return -1;
}
if (alsa_driver_get_channel_addresses (driver,
0, &contiguous, 0, &offset)) {
return -1;
}
for (chn = 0; chn < driver->playback_nchannels; chn++) {
alsa_driver_silence_on_channel (driver, chn,
contiguous);


+ 1
- 0
jack/engine.h View File

@@ -136,6 +136,7 @@ struct _jack_engine {
pid_t wait_pid;
int nozombies;
volatile int problems;
volatile int new_clients_allowed;

/* these lists are protected by `client_lock' */
JSList *clients;


+ 10
- 5
jack/internal.h View File

@@ -525,12 +525,17 @@ extern char *jack_default_server_name (void);
void silent_jack_error_callback (const char *desc);

/* needed for port management */
jack_port_t *jack_port_by_id_int (const jack_client_t *client,
jack_port_id_t id, int* free);
extern jack_port_t *jack_port_by_id_int (const jack_client_t *client,
jack_port_id_t id, int* free);

jack_port_t *jack_port_by_name_int (jack_client_t *client,
const char *port_name);
int jack_port_name_equals (jack_port_shared_t* port, const char* target);
extern jack_port_t *jack_port_by_name_int (jack_client_t *client,
const char *port_name);
extern int jack_port_name_equals (jack_port_shared_t* port, const char* target);

/** Get the size (in bytes) of the data structure used to store
* MIDI events internally.
*/
extern size_t jack_midi_internal_event_size ();

#ifdef __GNUC__
# define likely(x) __builtin_expect((x),1)


+ 3
- 3
jack/jack.h View File

@@ -606,7 +606,7 @@ int jack_port_connected_to (const jack_port_t *port,
* @return a null-terminated array of full port names to which the @a
* port is connected. If none, returns NULL.
*
* The caller is responsible for calling free(3) on any non-NULL
* The caller is responsible for calling jack_free(3) on any non-NULL
* returned value.
*
* @param port locally owned jack_port_t pointer.
@@ -619,7 +619,7 @@ const char **jack_port_get_connections (const jack_port_t *port) JACK_OPTIONAL_W
* @return a null-terminated array of full port names to which the @a
* port is connected. If none, returns NULL.
*
* The caller is responsible for calling free(3) on any non-NULL
* The caller is responsible for calling jack_free(3) on any non-NULL
* returned value.
*
* This differs from jack_port_get_connections() in two important
@@ -869,7 +869,7 @@ int jack_port_type_size(void) JACK_OPTIONAL_WEAK_EXPORT;
* If zero, no selection based on flags will be carried out.
*
* @return a NULL-terminated array of ports that match the specified
* arguments. The caller is responsible for calling free(3) any
* arguments. The caller is responsible for calling jack_free(3) any
* non-NULL returned value.
*
* @see jack_port_name_size(), jack_port_type_size()


+ 8
- 13
jack/midiport.h View File

@@ -25,6 +25,7 @@
extern "C" {
#endif
#include <jack/weakmacros.h>
#include <jack/types.h>
#include <stdlib.h>

@@ -53,7 +54,7 @@ typedef struct _jack_midi_event
* @return number of events inside @a port_buffer
*/
jack_nframes_t
jack_midi_get_event_count(void* port_buffer);
jack_midi_get_event_count(void* port_buffer) JACK_OPTIONAL_WEAK_EXPORT;


/** Get a MIDI event from an event port buffer.
@@ -70,7 +71,7 @@ jack_midi_get_event_count(void* port_buffer);
int
jack_midi_event_get(jack_midi_event_t *event,
void *port_buffer,
jack_nframes_t event_index);
jack_nframes_t event_index) JACK_OPTIONAL_WEAK_EXPORT;


/** Clear an event buffer.
@@ -82,7 +83,7 @@ jack_midi_event_get(jack_midi_event_t *event,
* @param port_buffer Port buffer to clear (must be an output port buffer).
*/
void
jack_midi_clear_buffer(void *port_buffer);
jack_midi_clear_buffer(void *port_buffer) JACK_OPTIONAL_WEAK_EXPORT;


/** Get the size of the largest event that can be stored by the port.
@@ -93,7 +94,7 @@ jack_midi_clear_buffer(void *port_buffer);
* @param port_buffer Port buffer to check size of.
*/
size_t
jack_midi_max_event_size(void* port_buffer);
jack_midi_max_event_size(void* port_buffer) JACK_OPTIONAL_WEAK_EXPORT;


/** Allocate space for an event to be written to an event port buffer.
@@ -114,7 +115,7 @@ jack_midi_max_event_size(void* port_buffer);
jack_midi_data_t*
jack_midi_event_reserve(void *port_buffer,
jack_nframes_t time,
size_t data_size);
size_t data_size) JACK_OPTIONAL_WEAK_EXPORT;


/** Write an event into an event port buffer.
@@ -133,7 +134,7 @@ int
jack_midi_event_write(void *port_buffer,
jack_nframes_t time,
const jack_midi_data_t *data,
size_t data_size);
size_t data_size) JACK_OPTIONAL_WEAK_EXPORT;


/** Get the number of events that could not be written to @a port_buffer.
@@ -145,13 +146,7 @@ jack_midi_event_write(void *port_buffer,
* @returns Number of events that could not be written to @a port_buffer.
*/
jack_nframes_t
jack_midi_get_lost_event_count(void *port_buffer);

/** Get the size (in bytes) of the data structure used to store
* MIDI events internally. This is not useful for JACK applications.
*/
size_t
jack_midi_internal_event_size ();
jack_midi_get_lost_event_count(void *port_buffer) JACK_OPTIONAL_WEAK_EXPORT;

/*@}*/



+ 70
- 58
jackd/clientengine.c View File

@@ -89,6 +89,58 @@ jack_client_do_deactivate (jack_engine_t *engine,
return 0;
}

static int
jack_load_client (jack_engine_t *engine, jack_client_internal_t *client,
const char *so_name)
{
const char *errstr;
char path_to_so[PATH_MAX+1];

snprintf (path_to_so, sizeof (path_to_so), ADDON_DIR "/%s.so", so_name);
client->handle = dlopen (path_to_so, RTLD_NOW|RTLD_GLOBAL);
if (client->handle == 0) {
if ((errstr = dlerror ()) != 0) {
jack_error ("%s", errstr);
} else {
jack_error ("bizarre error loading %s", so_name);
}
return -1;
}

client->initialize = dlsym (client->handle, "jack_initialize");

if ((errstr = dlerror ()) != 0) {
jack_error ("%s has no initialize() function\n", so_name);
dlclose (client->handle);
client->handle = 0;
return -1;
}

client->finish = (void (*)(void *)) dlsym (client->handle,
"jack_finish");
if ((errstr = dlerror ()) != 0) {
jack_error ("%s has no finish() function", so_name);
dlclose (client->handle);
client->handle = 0;
return -1;
}

return 0;
}

static void
jack_client_unload (jack_client_internal_t *client)
{
if (client->handle) {
if (client->finish) {
client->finish (client->private_client->process_arg);
}
dlclose (client->handle);
}
}

static void
jack_zombify_client (jack_engine_t *engine, jack_client_internal_t *client)
{
@@ -115,6 +167,12 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)

VERBOSE (engine, "removing client \"%s\"", client->control->name);

if (client->control->type == ClientInternal) {
/* unload it while its still a regular client */

jack_client_unload (client);
}

/* if its not already a zombie, make it so */

if (!client->control->dead) {
@@ -141,7 +199,7 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)
close (client->event_fd);
close (client->request_fd);
}
}

for (node = engine->clients; node; node = jack_slist_next (node)) {
if (((jack_client_internal_t *) node->data)->control->id
@@ -159,11 +217,17 @@ jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)

if (engine->temporary && (jack_slist_length(engine->clients) <= 1)) {
if (engine->wait_pid >= 0) {
/* block new clients from being created
after we release the lock.
*/
engine->new_clients_allowed = 0;
/* tell the waiter we're done
to initiate a normal shutdown.
*/
VERBOSE (engine, "Kill wait pid to stop");
kill (engine->wait_pid, SIGUSR2);
/* unlock the graph so that the server thread can finish */
jack_unlock_graph (engine);
sleep (-1);
} else {
exit (0);
@@ -305,58 +369,6 @@ jack_remove_clients (jack_engine_t* engine, int* exit_freewheeling_when_done)
VERBOSE (engine, "-- Removing failed clients ...");
}

static int
jack_load_client (jack_engine_t *engine, jack_client_internal_t *client,
const char *so_name)
{
const char *errstr;
char path_to_so[PATH_MAX+1];

snprintf (path_to_so, sizeof (path_to_so), ADDON_DIR "/%s.so", so_name);
client->handle = dlopen (path_to_so, RTLD_NOW|RTLD_GLOBAL);
if (client->handle == 0) {
if ((errstr = dlerror ()) != 0) {
jack_error ("%s", errstr);
} else {
jack_error ("bizarre error loading %s", so_name);
}
return -1;
}

client->initialize = dlsym (client->handle, "jack_initialize");

if ((errstr = dlerror ()) != 0) {
jack_error ("%s has no initialize() function\n", so_name);
dlclose (client->handle);
client->handle = 0;
return -1;
}

client->finish = (void (*)(void *)) dlsym (client->handle,
"jack_finish");
if ((errstr = dlerror ()) != 0) {
jack_error ("%s has no finish() function", so_name);
dlclose (client->handle);
client->handle = 0;
return -1;
}

return 0;
}

static void
jack_client_unload (jack_client_internal_t *client)
{
if (client->handle) {
if (client->finish) {
client->finish (client->private_client->process_arg);
}
dlclose (client->handle);
}
}

jack_client_internal_t *
jack_client_by_name (jack_engine_t *engine, const char *name)
{
@@ -1004,12 +1016,11 @@ jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client)

if (jack_client_is_internal (client)) {

jack_client_unload (client);
free (client->private_client);
free ((void *) client->control);

} else {
} else {
/* release the client segment, mark it for
destruction, and free up the shm registry
information so that it can be reused.
@@ -1017,9 +1028,10 @@ jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client)

jack_release_shm (&client->control_shm);
jack_destroy_shm (&client->control_shm);
}
}

free (client);

free (client);
}

void


+ 41
- 18
jackd/engine.c View File

@@ -861,7 +861,9 @@ jack_engine_process (jack_engine_t *engine, jack_nframes_t nframes)
DEBUG ("considering client %s for processing",
client->control->name);

if (!client->control->active || !client->control->process_cbset || client->control->dead) {
if (!client->control->active ||
(!client->control->process_cbset && !client->control->thread_cb_cbset) ||
client->control->dead) {
node = jack_slist_next (node);
} else if (jack_client_is_internal (client)) {
node = jack_process_internal (engine, node, nframes);
@@ -1671,7 +1673,7 @@ jack_server_thread (void *arg)
&client_addrlen)) < 0) {
jack_error ("cannot accept new connection (%s)",
strerror (errno));
} else if (jack_client_create (engine, client_socket) < 0) {
} else if (!engine->new_clients_allowed || jack_client_create (engine, client_socket) < 0) {
jack_error ("cannot complete client "
"connection process");
close (client_socket);
@@ -1786,6 +1788,7 @@ jack_engine_new (int realtime, int rtpriority, int do_mlock, int do_unlock,
engine->wait_pid = wait_pid;
engine->nozombies = nozombies;
engine->removing_clients = 0;
engine->new_clients_allowed = 1;

engine->session_reply_fd = -1;
engine->session_pending_replies = 0;
@@ -2098,7 +2101,7 @@ jack_start_freewheeling (jack_engine_t* engine, jack_client_id_t client_id)

client = jack_client_internal_by_id (engine, client_id);

if (client->control->process_cbset) {
if (client->control->process_cbset || client->control->thread_cb_cbset) {
engine->fwclient = client_id;
}

@@ -2649,14 +2652,30 @@ jack_do_session_notify (jack_engine_t *engine, jack_request_t *req, int reply_fd
for (node = engine->clients; node; node = jack_slist_next (node)) {
jack_client_internal_t* client = (jack_client_internal_t*) node->data;
if (client->control->session_cbset) {
struct stat sbuf;

// in case we only want to send to a special client.
// uuid assign is still complete. not sure if thats necessary.
if( (req->x.session.target[0] != 0) && strcmp(req->x.session.target, (char *)client->control->name) )
continue;

snprintf (event.x.name, sizeof (event.x.name), "%s%s/", req->x.session.path, client->control->name );
mkdir (event.x.name, 0777 );
/* the caller of jack_session_notify() is required to have created the session dir
*/
if (stat (req->x.session.path, &sbuf) != 0 || !S_ISDIR (sbuf.st_mode)) {
jack_error ("session parent directory (%s) does not exist", req->x.session.path);
goto error_out;
}
if (req->x.session.path[strlen(req->x.session.path)-1] == '/') {
snprintf (event.x.name, sizeof (event.x.name), "%s%s/", req->x.session.path, client->control->name );
} else {
snprintf (event.x.name, sizeof (event.x.name), "%s/%s/", req->x.session.path, client->control->name );
}
if (mkdir (event.x.name, 0777) != 0) {
jack_error ("cannot create session directory (%s) for client %s: %s",
event.x.name, client->control->name, strerror (errno));
goto error_out;
}
reply = jack_deliver_event (engine, client, &event);

if (reply == 1) {
@@ -2961,26 +2980,24 @@ jack_rechain_graph (jack_engine_t *engine)

for (n = 0, node = engine->clients, next = NULL; node; node = next) {

next = jack_slist_next (node);
jack_client_internal_t* client = (jack_client_internal_t *) node->data;

if (! ((jack_client_internal_t *) node->data)->control->process_cbset) {
next = jack_slist_next (node);
if (!client->control->process_cbset && !client->control->thread_cb_cbset) {
continue;
}

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->control->name, client->control->active);

client = (jack_client_internal_t *) node->data;
if (client->control->active) {

/* find the next active client. its ok for
* this to be NULL */
while (next) {
if (((jack_client_internal_t *)
next->data)->control->active && ((jack_client_internal_t *)next->data)->control->process_cbset ) {
if (client->control->active && (client->control->process_cbset || client->control->thread_cb_cbset)) {
break;
}
next = jack_slist_next (next);
@@ -3465,12 +3482,13 @@ void jack_dump_configuration(jack_engine_t *engine, int take_lock)
client = (jack_client_internal_t *) clientnode->data;
ctl = client->control;

jack_info ("client #%d: %s (type: %d, process? %s,"
jack_info ("client #%d: %s (type: %d, process? %s, thread ? %s"
" start=%d wait=%d",
++n,
ctl->name,
ctl->type,
ctl->process_cbset ? "yes" : "no",
ctl->thread_cb_cbset ? "yes" : "no",
client->subgraph_start_fd,
client->subgraph_wait_fd);

@@ -4092,14 +4110,19 @@ jack_port_do_register (jack_engine_t *engine, jack_request_t *req, int internal)

shared = &engine->control->ports[port_id];

if (!internal || !engine->driver)
if (!internal || !engine->driver) {
goto fallback;
}

/* if the port belongs to the backend client, do some magic with names
*/

backend_client_name = (char *) engine->driver->internal_client->control->name;
len = strlen (backend_client_name);

if (strncmp (req->x.port_info.name, backend_client_name, len) != 0)
if (strncmp (req->x.port_info.name, backend_client_name, len) != 0) {
goto fallback;
}

/* use backend's original as an alias, use predefined names */



Loading…
Cancel
Save