summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--drivers/oss/oss_driver.c4
-rw-r--r--jack/internal.h10
-rw-r--r--jack/thread.h8
-rw-r--r--jackd/engine.c55
-rw-r--r--libjack/client.c74
-rw-r--r--libjack/driver.c3
-rw-r--r--libjack/thread.c211
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, &param);
- 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, &current_param);
-
- result = sched_setscheduler (0, policy, &param);
- 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, &current_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, &param);
+ 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;
}