Browse Source

substantive rearrangement of OSX code so that async API (jack_cycle_wait/jack_cycle_signal) works on that platform. tested (provisionally) with the help of lincoln spiteri

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@4312 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.120.2
paul 14 years ago
parent
commit
345f9dbed7
1 changed files with 280 additions and 176 deletions
  1. +280
    -176
      libjack/client.c

+ 280
- 176
libjack/client.c View File

@@ -1826,11 +1826,105 @@ jack_client_process_events (jack_client_t* client)
return 0;
}


static int
jack_wake_next_client (jack_client_t* client)
{
#ifndef JACK_USE_MACH_THREADS
struct pollfd pfds[1];
int pret = 0;
char c = 0;

if (write (client->graph_next_fd, &c, sizeof (c))
!= sizeof (c)) {
DEBUG("cannot write byte to fd %d", client->graph_next_fd);
jack_error ("cannot continue execution of the "
"processing graph (%s)",
strerror(errno));
return -1;
}
DEBUG ("client sent message to next stage by %" PRIu64 "",
jack_get_microseconds());
DEBUG("reading cleanup byte from pipe %d\n", client->graph_wait_fd);

/* "upstream client went away? readability is checked in
* jack_client_core_wait(), but that's almost a whole cycle
* before we get here.
*/

if (client->graph_wait_fd >= 0) {
pfds[0].fd = client->graph_wait_fd;
pfds[0].events = POLLIN;

/* 0 timeout, don't actually wait */
pret = poll(pfds, 1, 0);
}

if (pret > 0 && (pfds[0].revents & POLLIN)) {
if (read (client->graph_wait_fd, &c, sizeof (c))
!= sizeof (c)) {
jack_error ("cannot complete execution of the "
"processing graph (%s)", strerror(errno));
return -1;
}
} else {
DEBUG("cleanup byte from pipe %d not available?\n",
client->graph_wait_fd);
}
#endif
return 0;
}

#ifdef JACK_USE_MACH_THREADS

static int
jack_client_core_wait (jack_client_t* client)
{
jack_client_control_t *control = client->control;

/* this is OS X - we're only waiting on events */

DEBUG ("client polling on %s", client->pollmax == 2 ?
"event_fd and graph_wait_fd..." :
"event_fd only");
while (1) {
if (poll (client->pollfd, client->pollmax, 1000) < 0) {
if (errno == EINTR) {
continue;
}
jack_error ("poll failed in client (%s)",
strerror (errno));
return -1;
}

pthread_testcancel();

if (jack_client_process_events (client)) {
DEBUG ("event processing failed\n");
return 0;
}
}

if (control->dead || client->pollfd[EVENT_POLL_INDEX].revents & ~POLLIN) {
DEBUG ("client appears dead or event pollfd has error status\n");
return -1;
}

return 0;
}

#else /* !JACK_USE_MACH_THREADS */

static int
jack_client_core_wait (jack_client_t* client)
{
jack_client_control_t *control = client->control;

/* this is not OS X - we're waiting on events & process wakeups */

DEBUG ("client polling on %s", client->pollmax == 2 ?
"event_fd and graph_wait_fd..." :
"event_fd only");
@@ -1847,8 +1941,6 @@ jack_client_core_wait (jack_client_t* client)

pthread_testcancel();

#ifndef JACK_USE_MACH_THREADS
/* get an accurate timestamp on waking from poll for a
* process() cycle.
*/
@@ -1894,20 +1986,17 @@ jack_client_core_wait (jack_client_t* client)
client->pollmax = 1;
}
}
#endif
if (jack_client_process_events (client)) {
DEBUG ("event processing failed\n");
return 0;
}

#ifndef JACK_USE_MACH_THREADS
if (client->graph_wait_fd >= 0 &&
(client->pollfd[WAIT_POLL_INDEX].revents & POLLIN)) {
DEBUG ("time to run process()\n");
break;
}
#endif
}

if (control->dead || client->pollfd[EVENT_POLL_INDEX].revents & ~POLLIN) {
@@ -1918,70 +2007,134 @@ jack_client_core_wait (jack_client_t* client)
return 0;
}

static int
jack_wake_next_client (jack_client_t* client)
{
struct pollfd pfds[1];
int pret = 0;
char c = 0;
#endif

if (write (client->graph_next_fd, &c, sizeof (c))
!= sizeof (c)) {
DEBUG("cannot write byte to fd %d", client->graph_next_fd);
jack_error ("cannot continue execution of the "
"processing graph (%s)",
strerror(errno));
return -1;
static jack_nframes_t
jack_thread_first_wait (jack_client_t* client)
{
if (jack_client_core_wait (client)) {
return 0;
}
DEBUG ("client sent message to next stage by %" PRIu64 "",
jack_get_microseconds());
DEBUG("reading cleanup byte from pipe %d\n", client->graph_wait_fd);
return client->control->nframes;
}
static void
jack_client_thread_aux (void *arg)
{
jack_client_t *client = (jack_client_t *) arg;
jack_client_control_t *control = client->control;

/* "upstream client went away? readability is checked in
* jack_client_core_wait(), but that's almost a whole cycle
* before we get here.
*/
pthread_mutex_lock (&client_lock);
client->thread_ok = TRUE;
client->thread_id = pthread_self();
pthread_cond_signal (&client_ready);
pthread_mutex_unlock (&client_lock);

if (client->graph_wait_fd >= 0) {
pfds[0].fd = client->graph_wait_fd;
pfds[0].events = POLLIN;
control->pid = getpid();
control->pgrp = getpgrp();

/* 0 timeout, don't actually wait */
pret = poll(pfds, 1, 0);
DEBUG ("client thread is now running");

if (control->thread_init_cbset) {
DEBUG ("calling client thread init callback");
client->thread_init (client->thread_init_arg);
}

if (pret > 0 && (pfds[0].revents & POLLIN)) {
if (read (client->graph_wait_fd, &c, sizeof (c))
!= sizeof (c)) {
jack_error ("cannot complete execution of the "
"processing graph (%s)", strerror(errno));
return -1;
/* wait for first wakeup from server */

if (jack_thread_first_wait (client) == control->nframes) {

/* now run till we're done */

if (control->process_cbset) {

/* run process callback, then wait... ad-infinitum */

while (1) {
DEBUG("client calls process()");
int status = (client->process (control->nframes,
client->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)
;
}
} else {
DEBUG("cleanup byte from pipe %d not available?\n",
client->graph_wait_fd);
}
return 0;

jack_client_thread_suicide (client);
}

static jack_nframes_t
jack_thread_first_wait (jack_client_t* client)
static void
jack_run_client_provided_process_thread (jack_client_t* client)
{
if (jack_client_core_wait (client)) {
return 0;
jack_client_control_t *control = client->control;

pthread_mutex_lock (&client_lock);
client->thread_ok = TRUE;
client->thread_id = pthread_self();
pthread_cond_signal (&client_ready);
pthread_mutex_unlock (&client_lock);
control->pid = getpid();
control->pgrp = getpgrp();
client->thread_cb(client->thread_cb_arg);
jack_client_thread_suicide(client);
}

#ifdef JACK_USE_MACH_THREADS

static void*
jack_client_thread (void *arg)
{
/* On OS X, the secondary client thread that we create will
always just handle server events, whether or not the
client has called jack_set_process_thread().
*/
jack_client_thread_aux(arg);
/*NOTREACHED*/
return (void *) 0;
}

#else /* !JACK_USE_MACH_THREADS */

static void*
jack_client_thread (void *arg)
{
jack_client_t *client = (jack_client_t *) arg;

/* On non-OSX systems, the client thread should run the supplied
callback if jack_set_process_thread() was called, otherwise
it will just wait in a loop for events and/or process wakeups.
*/
if (client->control->thread_cb_cbset) {
jack_run_client_provided_process_thread (client);
} else {
jack_client_thread_aux (arg);
}
return client->control->nframes;
/*NOTREACHED*/
return (void *) 0;
}

#endif

jack_nframes_t
jack_thread_wait (jack_client_t* client, int status)
{
client->control->last_status = status;

/* SECTION ONE: HOUSEKEEPING/CLEANUP FROM LAST DATA PROCESSING */
/* SECTION ONE: HOUSEKEEPING/CLEANUP FROM LAST DATA PROCESSING */

/* housekeeping/cleanup after data processing */

@@ -2008,13 +2161,13 @@ jack_thread_wait (jack_client_t* client, int status)
return 0;
}
/* SECTION TWO: WAIT FOR NEXT DATA PROCESSING TIME */
/* SECTION TWO: WAIT FOR NEXT DATA PROCESSING TIME */
if (jack_client_core_wait (client)) {
return 0;
}
/* SECTION THREE: START NEXT DATA PROCESSING TIME */
/* SECTION THREE: START NEXT DATA PROCESSING TIME */

/* Time to do data processing */

@@ -2031,35 +2184,52 @@ jack_thread_wait (jack_client_t* client, int status)

jack_nframes_t jack_cycle_wait (jack_client_t* client)
{
/* SECTION TWO: WAIT FOR NEXT DATA PROCESSING TIME */
jack_client_control_t *control = client->control;

/* SECTION TWO: WAIT FOR NEXT DATA PROCESSING TIME */
#ifdef JACK_USE_MACH_THREADS
/* on OS X systems, this thread is running a callback provided
by the client that has called this function in order to wait
for the next process callback. This is how we do that ...
*/
jack_client_suspend (client);
#else
/* on non-OSX systems, this thread is running a callback provided
by the client that has called this function in order to wait
for the next process() callback or the next event from the
server.
*/
if (jack_client_core_wait (client)) {
return 0;
}

/* SECTION THREE: START NEXT DATA PROCESSING TIME */

#endif
/* SECTION THREE: START NEXT DATA PROCESSING TIME */
/* Time to do data processing */

control->awake_at = jack_get_microseconds();
client->control->state = Running;
/* begin preemption checking */
CHECK_PREEMPTION (client->engine, TRUE);
if (client->control->sync_cb_cbset)
if (client->control->sync_cb_cbset) {
jack_call_sync_client (client);

}
return client->control->nframes;
}

void jack_cycle_signal(jack_client_t* client, int status)
void jack_cycle_signal (jack_client_t* client, int status)
{
client->control->last_status = status;

/* SECTION ONE: HOUSEKEEPING/CLEANUP FROM LAST DATA PROCESSING */
/* SECTION ONE: HOUSEKEEPING/CLEANUP FROM LAST DATA PROCESSING */
/* housekeeping/cleanup after data processing */
if (status == 0 && client->control->timebase_cb_cbset) {
jack_call_timebase_master (client);
}
@@ -2068,6 +2238,7 @@ void jack_cycle_signal(jack_client_t* client, int status)
CHECK_PREEMPTION (client->engine, FALSE);
client->control->finished_at = jack_get_microseconds();
client->control->state = Finished;
/* wake the next client in the chain (could be the server),
and check if we were killed during the process
@@ -2079,132 +2250,40 @@ void jack_cycle_signal(jack_client_t* client, int status)
jack_client_thread_suicide (client);
/*NOTREACHED*/
}
if (status || client->control->dead || !client->engine->engine_ok) {
jack_client_thread_suicide (client);
/*NOTREACHED*/
}
}

static void
jack_client_thread_aux (void *arg)
{
jack_client_t *client = (jack_client_t *) arg;
jack_client_control_t *control = client->control;

pthread_mutex_lock (&client_lock);
client->thread_ok = TRUE;
client->thread_id = pthread_self();
pthread_cond_signal (&client_ready);
pthread_mutex_unlock (&client_lock);

control->pid = getpid();
control->pgrp = getpgrp();

DEBUG ("client thread is now running");

if (control->thread_init_cbset) {
DEBUG ("calling client thread init callback");
client->thread_init (client->thread_init_arg);
}

/* wait for first wakeup from server */

if (jack_thread_first_wait (client) == control->nframes) {

/* now run till we're done */

if (control->process_cbset) {

/* run process callback, then wait... ad-infinitum */

while (1) {
DEBUG("client calls process()");
int status = (client->process (control->nframes,
client->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)
;
}
}

jack_client_thread_suicide (client);
}

static void*
jack_client_thread (void *arg)
{
jack_client_t *client = (jack_client_t *) arg;
jack_client_control_t *control = client->control;
if (client->control->thread_cb_cbset) {
pthread_mutex_lock (&client_lock);
client->thread_ok = TRUE;
client->thread_id = pthread_self();
pthread_cond_signal (&client_ready);
pthread_mutex_unlock (&client_lock);

control->pid = getpid();
control->pgrp = getpgrp();

client->thread_cb(client->thread_cb_arg);
jack_client_thread_suicide(client);
} else {
jack_client_thread_aux(arg);
}
/*NOTREACHED*/
return (void *) 0;
}

#ifdef JACK_USE_MACH_THREADS

/* real-time thread : separated from the normal client thread, it will
* communicate with the server using fast mach RPC mechanism */

static void *
jack_client_process_thread (void *arg)
static void
jack_osx_process_thread (jack_client_t* client)
{
jack_client_t *client = (jack_client_t *) arg;
jack_client_control_t *control = client->control;
jack_client_control_t *control = client->control;
int err = 0;

if (client->control->thread_init_cbset) {
/* this means that the init callback will be called twice -taybin*/
DEBUG ("calling client thread init callback");
client->thread_init (client->thread_init_arg);
}

client->control->pid = getpid();
DEBUG ("client process thread is now running");
client->rt_thread_ok = TRUE;
while (err == 0) {
if (jack_client_suspend(client) < 0) {
jack_error ("jack_client_process_thread :resume error");
goto zombie;
jack_error ("jack_client_process_thread :resume error");
goto zombie;
}
control->awake_at = jack_get_microseconds();
DEBUG ("client resumed");
control->state = Running;

if (control->sync_cb_cbset)
if (control->sync_cb_cbset) {
jack_call_sync_client (client);
}

if (control->process_cbset) {
if (client->process (control->nframes,
@@ -2215,9 +2294,10 @@ jack_client_process_thread (void *arg)
control->state = Finished;
}

if (control->timebase_cb_cbset)
if (control->timebase_cb_cbset) {
jack_call_timebase_master (client);
}

control->finished_at = jack_get_microseconds();
DEBUG ("client finished processing at %Lu (elapsed = %f usecs)",
@@ -2228,16 +2308,15 @@ jack_client_process_thread (void *arg)
* (or whatever) */
if (client->control->dead) {
jack_error ("jack_client_process_thread: "
"client->control->dead");
goto zombie;
jack_error ("jack_client_process_thread: "
"client->control->dead");
goto zombie;
}
DEBUG("process cycle fully complete\n");

}
return (void *) ((intptr_t)err);
return;

zombie:
@@ -2257,11 +2336,36 @@ jack_client_process_thread (void *arg)
* zombified without shutdown handler */
jack_client_close_aux (client);
}
}

static void *
jack_client_process_thread (void *arg)
{
jack_client_t *client = (jack_client_t *) arg;
jack_client_control_t *control = client->control;

if (client->control->thread_init_cbset) {
/* this means that the init callback will be called twice -taybin*/
DEBUG ("calling client thread init callback");
client->thread_init (client->thread_init_arg);
}
client->control->pid = getpid();
DEBUG ("client process thread is now running");
client->rt_thread_ok = TRUE;
if (client->control->thread_cb_cbset) {
jack_run_client_provided_process_thread (client);
} else {
jack_osx_process_thread (client);
}

pthread_exit (0);
/*NOTREACHED*/
return 0;
}

#endif /* JACK_USE_MACH_THREADS */

static int


Loading…
Cancel
Save