diff options
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | drivers/oss/oss_driver.c | 4 | ||||
-rw-r--r-- | jack/internal.h | 10 | ||||
-rw-r--r-- | jack/thread.h | 8 | ||||
-rw-r--r-- | jackd/engine.c | 55 | ||||
-rw-r--r-- | libjack/client.c | 74 | ||||
-rw-r--r-- | libjack/driver.c | 3 | ||||
-rw-r--r-- | libjack/thread.c | 211 |
8 files changed, 162 insertions, 205 deletions
diff --git a/configure.ac b/configure.ac index 6ad99d8..9c69300 100644 --- a/configure.ac +++ b/configure.ac @@ -15,7 +15,7 @@ dnl changes are made dnl --- JACK_MAJOR_VERSION=0 JACK_MINOR_VERSION=99 -JACK_MICRO_VERSION=54 +JACK_MICRO_VERSION=60 dnl --- dnl HOWTO: updating the jack protocol version diff --git a/drivers/oss/oss_driver.c b/drivers/oss/oss_driver.c index bbe8e44..8a23a13 100644 --- a/drivers/oss/oss_driver.c +++ b/drivers/oss/oss_driver.c @@ -655,7 +655,7 @@ static int oss_driver_start (oss_driver_t *driver) driver->threads = 0; if (infd >= 0) { - if (jack_create_thread(&driver->thread_in, + if (jack_create_thread(NULL, &driver->thread_in, driver->engine->rtpriority, driver->engine->control->real_time, io_thread, driver) < 0) @@ -669,7 +669,7 @@ static int oss_driver_start (oss_driver_t *driver) # ifdef USE_BARRIER if (outfd >= 0) { - if (jack_create_thread(&driver->thread_out, + if (jack_create_thread(NULL, &driver->thread_out, driver->engine->rtpriority, driver->engine->control->real_time, io_thread, driver) < 0) diff --git a/jack/internal.h b/jack/internal.h index d0e003c..9a5514d 100644 --- a/jack/internal.h +++ b/jack/internal.h @@ -354,6 +354,7 @@ struct _jack_request { jack_client_id_t client_id; jack_nframes_t nframes; jack_time_t timeout; + pid_t cap_pid; } x; int32_t status; }; @@ -393,6 +394,15 @@ typedef struct _jack_client_internal { } jack_client_internal_t; +typedef struct _jack_thread_arg { + jack_client_t* client; + void* (*work_function)(void*); + int priority; + int realtime; + void* arg; + pid_t cap_pid; +} jack_thread_arg_t; + extern int jack_client_handle_port_connection (jack_client_t *client, jack_event_t *event); extern jack_client_t *jack_driver_client_new (jack_engine_t *, diff --git a/jack/thread.h b/jack/thread.h index 723f3bf..c4a98a3 100644 --- a/jack/thread.h +++ b/jack/thread.h @@ -51,6 +51,8 @@ int jack_acquire_real_time_scheduling (pthread_t thread, int priority); * created executing @a start_routine with @a arg as its sole * argument. * + * @param client the JACK client for whom the thread is being created. May be + * NULL if the client is being created within the JACK server. * @param thread place to return POSIX thread ID. * @param priority thread priority, if realtime. * @param realtime true for the thread to use realtime scheduling. On @@ -58,10 +60,10 @@ int jack_acquire_real_time_scheduling (pthread_t thread, int priority); * @param start_routine function the thread calls when it starts. * @param arg parameter passed to the @a start_routine. * - * @returns 0, if successful; EPERM, if the calling process lacks - * required realtime privileges; otherwise some other error number. + * @returns 0, if successful; otherwise some error number. */ -int jack_create_thread (pthread_t *thread, +int jack_create_thread (jack_client_t* client, + pthread_t *thread, int priority, int realtime, /* boolean */ void *(*start_routine)(void*), diff --git a/jackd/engine.c b/jackd/engine.c index 9f2873e..f2ea5b5 100644 --- a/jackd/engine.c +++ b/jackd/engine.c @@ -901,7 +901,7 @@ jack_watchdog_thread (void *arg) while (1) { sleep (5); - if ( engine->watchdog_check == 0) { + if (!engine->freewheeling && engine->watchdog_check == 0) { jack_error ("jackd watchdog: timeout - killing jackd"); @@ -930,7 +930,7 @@ jack_start_watchdog (jack_engine_t *engine) (max_priority < watchdog_priority)) watchdog_priority = max_priority; - if (jack_create_thread (&engine->watchdog_thread, watchdog_priority, + if (jack_create_thread (NULL, &engine->watchdog_thread, watchdog_priority, TRUE, jack_watchdog_thread, engine)) { jack_error ("cannot start watchdog thread"); return -1; @@ -1134,41 +1134,26 @@ static int give_capabilities (jack_engine_t *engine, pid_t pid) } static int -jack_set_client_capabilities (jack_engine_t *engine, jack_client_id_t id) - +jack_set_client_capabilities (jack_engine_t *engine, pid_t cap_pid) { - JSList *node; int ret = -1; - jack_lock_graph (engine); - - for (node = engine->clients; node; node = jack_slist_next (node)) { - - jack_client_internal_t *client = - (jack_client_internal_t *) node->data; - - if (client->control->id == id) { + /* before sending this request the client has + already checked that the engine has + realtime capabilities, that it is running + realtime and that the pid is defined + */ - /* before sending this request the client has - already checked that the engine has - realtime capabilities, that it is running - realtime and that the pid is defined - */ - ret = give_capabilities (engine, client->control->pid); - if (ret) { - jack_error ("could not give capabilities to " - "process %d\n", - client->control->pid); - } else { - VERBOSE (engine, "gave capabilities to" - " process %d\n", - client->control->pid); - } - } + if ((ret = give_capabilities (engine, cap_pid)) != 0) { + jack_error ("could not give capabilities to " + "process %d\n", + cap_pid); + } else { + VERBOSE (engine, "gave capabilities to" + " process %d\n", + cap_pid); } - jack_unlock_graph (engine); - return ret; } @@ -1252,7 +1237,7 @@ do_request (jack_engine_t *engine, jack_request_t *req, int *reply_fd) #ifdef USE_CAPABILITIES case SetClientCapabilities: req->status = jack_set_client_capabilities (engine, - req->x.client_id); + req->x.cap_pid); break; #endif /* USE_CAPABILITIES */ @@ -1757,7 +1742,7 @@ jack_engine_new (int realtime, int rtpriority, int do_mlock, int do_unlock, (void) jack_get_fifo_fd (engine, 0); - jack_create_thread (&engine->server_thread, 0, FALSE, + jack_create_thread (NULL, &engine->server_thread, 0, FALSE, &jack_server_thread, engine); return engine; @@ -1870,8 +1855,8 @@ jack_start_freewheeling (jack_engine_t* engine) event.type = StartFreewheel; jack_deliver_event_to_all (engine, &event); - if (jack_create_thread (&engine->freewheel_thread, 0, FALSE, - jack_engine_freewheel, engine)) { + if (jack_create_thread (NULL, &engine->freewheel_thread, 0, FALSE, + jack_engine_freewheel, engine)) { jack_error ("could not start create freewheel thread"); return -1; } diff --git a/libjack/client.c b/libjack/client.c index f5975e7..4c13f68 100644 --- a/libjack/client.c +++ b/libjack/client.c @@ -988,34 +988,9 @@ int jack_set_freewheel (jack_client_t* client, int onoff) { jack_request_t request; - int ret; - - /* Note: the thread that initiates and terminates freewheeling must - be the one that called jack_activate(), because that is the only - thread with RT-granting capabilities. - - XXX horrible design. The RT thread should acquire/drop/reacquire - scheduling all by itself. - */ request.type = onoff ? FreeWheel : StopFreeWheel; - - if ((ret = jack_client_deliver_request (client, &request)) == 0) { - if (onoff == 0 && client->engine->real_time) { - /* get the relevant thread back to RT priority */ -#if JACK_USE_MACH_THREADS - jack_acquire_real_time_scheduling ( - client->process_thread, - client->engine->client_priority); -#else - jack_acquire_real_time_scheduling ( - client->thread, - client->engine->client_priority); -#endif - } - } - - return ret; + return jack_client_deliver_request (client, &request); } void @@ -1041,6 +1016,16 @@ jack_stop_freewheel (jack_client_t* client) { jack_client_control_t *control = client->control; + if (client->engine->real_time) { +#if JACK_USE_MACH_THREADS + jack_acquire_real_time_scheduling (client->process_thread, + client->engine->client_priority); +#else + jack_acquire_real_time_scheduling (client->thread, + client->engine->client_priority); +#endif + } + if (control->freewheel_cb) { control->freewheel_cb (0, control->freewheel_arg); } @@ -1491,16 +1476,18 @@ jack_start_thread (jack_client_t *client) #ifdef JACK_USE_MACH_THREADS /* Stephane Letz : letz@grame.fr -On MacOSX, the normal thread does not need to be real-time. + On MacOSX, the normal thread does not need to be real-time. */ - if (jack_create_thread (&client->thread, + if (jack_create_thread (client, + &client->thread, client->engine->client_priority, - 0, + FALSE, jack_client_thread, client)) { return -1; } #else - if (jack_create_thread (&client->thread, + if (jack_create_thread (client, + &client->thread, client->engine->client_priority, client->engine->real_time, jack_client_thread, client)) { @@ -1508,7 +1495,7 @@ On MacOSX, the normal thread does not need to be real-time. } #endif - + #ifdef JACK_USE_MACH_THREADS /* a secondary thread that runs the process callback and uses @@ -1521,10 +1508,11 @@ On MacOSX, the normal thread does not need to be real-time. */ - if (jack_create_thread(&client->process_thread, - client->engine->client_priority, - client->engine->real_time, - jack_client_process_thread, client)) { + if (jack_create_thread(client, + &client->process_thread, + client->engine->client_priority, + client->engine->real_time, + jack_client_process_thread, client)) { return -1; } #endif /* JACK_USE_MACH_THREADS */ @@ -1569,6 +1557,7 @@ jack_activate (jack_client_t *client) req.type = SetClientCapabilities; req.x.client_id = client->control->id; + req.x.cap_pid = client->control->pid; jack_client_deliver_request (client, &req); @@ -1578,17 +1567,14 @@ jack_activate (jack_client_t *client) is using capabilities and has them (otherwise we would not get an error return) but for some reason it could not - give the client the required capabilities, - so for now downgrade the client so that it - still runs, albeit non-realtime - nando + give the client the required capabilities. + For now, leave the client so that it + still runs, albeit non-realtime. */ - + jack_error ("could not receive realtime capabilities, " "client will run non-realtime"); - /* XXX wrong, this is a property of the engine - client->engine->real_time = 0; - */ - } + } } #endif /* USE_CAPABILITIES */ @@ -1598,7 +1584,7 @@ jack_activate (jack_client_t *client) pthread_cond_init (&client_ready, NULL); pthread_mutex_lock (&client_lock); - + if (jack_start_thread (client)) { pthread_mutex_unlock (&client_lock); return -1; diff --git a/libjack/driver.c b/libjack/driver.c index 4008447..f5b509b 100644 --- a/libjack/driver.c +++ b/libjack/driver.c @@ -148,7 +148,8 @@ jack_driver_nt_start (jack_driver_nt_t * driver) pthread_mutex_lock (&driver->nt_run_lock); driver->nt_run = DRIVER_NT_RUN; - if ((err = jack_create_thread (&driver->nt_thread, + if ((err = jack_create_thread (NULL, + &driver->nt_thread, driver->engine->rtpriority, driver->engine->control->real_time, jack_driver_nt_thread, driver)) != 0) { diff --git a/libjack/thread.c b/libjack/thread.c index bc507a7..009cbcb 100644 --- a/libjack/thread.c +++ b/libjack/thread.c @@ -24,6 +24,7 @@ #include <config.h> +#include <jack/jack.h> #include <jack/thread.h> #include <jack/internal.h> @@ -33,6 +34,8 @@ #include <string.h> #include <errno.h> +#include "local.h" + #ifdef JACK_USE_MACH_THREADS #include <sysdeps/pThreadUtilities.h> #endif @@ -47,8 +50,85 @@ log_result (char *msg, int res) jack_error(outbuf); } +static void* +jack_thread_proxy (jack_thread_arg_t* arg) +{ + void* (*work)(void*); + void* warg; + jack_client_t* client = arg->client; + int try_rt = 0; + + if (arg->realtime) { + +#ifdef USE_CAPABILITIES + + if (client == 0) { + + /* we're creating a thread within jackd itself, don't + bother trying to acquire capabilities because either + jackd has them or it doesn't. + */ + + try_rt = 1; + + } else { + + jack_request_t req; + + if (client->engine->has_capabilities != 0 && + client->control->pid != 0 && + client->engine->real_time != 0) { + + /* we need to ask the engine for realtime capabilities + before trying to run the thread work function + */ + + req.type = SetClientCapabilities; + req.x.cap_pid = getpid(); + + jack_client_deliver_request (client, &req); + + if (req.status) { + + /* what to do? engine is running realtime, it + is using capabilities and has them + (otherwise we would not get an error + return) but for some reason it could not + give the client the required capabilities. + for now, allow the client to run, albeit + non-realtime. + */ + + jack_error ("could not receive realtime capabilities, " + "client will run non-realtime"); + } else { + try_rt = 1; + } + } + } + +#else /* !USE_CAPABILITIES */ + + try_rt = 1; + +#endif /* USE_CAPABILITIES */ + + if (try_rt) { + jack_acquire_real_time_scheduling (pthread_self(), arg->priority); + } + } + + warg = arg->arg; + work = arg->work_function; + + free (arg); + + return work (warg); +} + int -jack_create_thread (pthread_t* thread, +jack_create_thread (jack_client_t* client, + pthread_t* thread, int priority, int realtime, void*(*start_routine)(void*), @@ -60,6 +140,7 @@ jack_create_thread (pthread_t* thread, struct sched_param param; int actual_policy; struct sched_param actual_param; + jack_thread_arg_t* thread_args; #endif /* !JACK_USE_MACH_THREADS */ int result = 0; @@ -81,8 +162,6 @@ jack_create_thread (pthread_t* thread, #ifndef JACK_USE_MACH_THREADS pthread_attr_init(&attr); - policy = SCHED_FIFO; - param.sched_priority = priority; result = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); if (result) { log_result("requesting explicit scheduling", result); @@ -98,125 +177,18 @@ jack_create_thread (pthread_t* thread, log_result("requesting system scheduling scope", result); return result; } - result = pthread_attr_setschedpolicy(&attr, policy); - if (result) { - log_result("requesting non-standard scheduling policy", result); - return result; - } - result = pthread_attr_setschedparam(&attr, ¶m); - if (result) { - log_result("requesting thread priority", result); - return result; - } - - /* with respect to getting scheduling class+priority set up - correctly, there are three possibilities here: - - a) the call sets them and returns zero - =================================== - - this is great, obviously. - - b) the call fails to set them and returns an error code - ==================================================== - - this could happen for a number of reasons, - but the important one is that we do not have the - priviledges required to create a realtime - thread. this could be correct, or it could be - bogus: there is at least one version of glibc - that checks only for UID in - pthread_attr_setschedpolicy(), and does not - check capabilities. - - c) the call fails to set them and does not return an error code - ============================================================ - - this last case is caused by a stupid workaround in NPTL 0.60 - where scheduling parameters are simply ignored, with no indication - of an error. - */ - - result = pthread_create (thread, &attr, start_routine, arg); - - if (result) { - - /* this workaround temporarily switches the - current thread to the proper scheduler - and priority, using a call that - correctly checks for capabilities, then - starts the realtime thread so that it - can inherit them and finally switches - the current thread back to what it was - before. - */ - - int current_policy; - struct sched_param current_param; - pthread_attr_t inherit_attr; - - current_policy = sched_getscheduler (0); - sched_getparam (0, ¤t_param); - - result = sched_setscheduler (0, policy, ¶m); - if (result) { - log_result("switching current thread to rt for " - "inheritance", result); - return result; - } - - pthread_attr_init (&inherit_attr); - result = pthread_attr_setscope (&inherit_attr, - PTHREAD_SCOPE_SYSTEM); - if (result) { - log_result("requesting system scheduling scope " - "for inheritance", result); - return result; - } - result = pthread_attr_setinheritsched (&inherit_attr, - PTHREAD_INHERIT_SCHED); - if (result) { - log_result("requesting inheritance of scheduling " - "parameters", result); - return result; - } - result = pthread_create (thread, &inherit_attr, start_routine, - arg); - if (result) { - log_result("creating real-time thread by inheritance", - result); - } - - sched_setscheduler (0, current_policy, ¤t_param); - - if (result) - return result; - } - - /* Still here? Good. Let's see if this worked... */ - - result = pthread_getschedparam (*thread, &actual_policy, &actual_param); - if (result) { - log_result ("verifying scheduler parameters", result); - return result; - } - if (actual_policy == policy && - actual_param.sched_priority == param.sched_priority) { - return 0; /* everything worked OK */ - } + thread_args = (jack_thread_arg_t *) malloc (sizeof (jack_thread_arg_t)); - /* we failed to set the sched class and priority, - * even though no error was returned by - * pthread_create(). fix this by setting them - * explicitly, which as far as is known will - * work even when using thread attributes does not. - */ + thread_args->client = client; + thread_args->work_function = start_routine; + thread_args->arg = arg; + thread_args->realtime = 1; + thread_args->priority = priority; - result = pthread_setschedparam (*thread, policy, ¶m); + result = pthread_create (thread, &attr, jack_thread_proxy, thread_args); if (result) { - log_result("setting scheduler parameters after thread " - "creation", result); + log_result ("creating realtime thread", result); return result; } @@ -282,13 +254,14 @@ jack_acquire_real_time_scheduling (pthread_t thread, int priority) rtparam.sched_priority = priority; if ((x = pthread_setschedparam (thread, SCHED_FIFO, &rtparam)) != 0) { - jack_error ("cannot use real-time scheduling (FIFO/%d) " + jack_error ("cannot use real-time scheduling (FIFO at priority %d) " "[for thread %d, from thread %d] (%d: %s)", rtparam.sched_priority, thread, pthread_self(), x, strerror (x)); return -1; } + return 0; } |