Browse Source

changes to jack_thread_create to support proper assignment of capabilities; revert freewheeling changes; do not allow watchdog to kill stuff when freewheeling

git-svn-id: svn+ssh://jackaudio.org/trunk/jack@892 0c269be4-1314-0410-8aa9-9f06e86f4224
tags/0.109.0
pbd 21 years ago
parent
commit
5ed969eaae
8 changed files with 162 additions and 205 deletions
  1. +1
    -1
      configure.ac
  2. +2
    -2
      drivers/oss/oss_driver.c
  3. +10
    -0
      jack/internal.h
  4. +5
    -3
      jack/thread.h
  5. +20
    -35
      jackd/engine.c
  6. +30
    -44
      libjack/client.c
  7. +2
    -1
      libjack/driver.c
  8. +92
    -119
      libjack/thread.c

+ 1
- 1
configure.ac View File

@@ -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


+ 2
- 2
drivers/oss/oss_driver.c View File

@@ -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)


+ 10
- 0
jack/internal.h View File

@@ -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 *,


+ 5
- 3
jack/thread.h View File

@@ -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*),


+ 20
- 35
jackd/engine.c View File

@@ -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;
}


+ 30
- 44
libjack/client.c View File

@@ -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;


+ 2
- 1
libjack/driver.c View File

@@ -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) {


+ 92
- 119
libjack/thread.c View File

@@ -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;
}



Loading…
Cancel
Save