git-svn-id: svn+ssh://jackaudio.org/trunk/jack@79 0c269be4-1314-0410-8aa9-9f06e86f4224tags/0.109.0
| @@ -716,7 +716,7 @@ alsa_driver_wait (alsa_driver_t *driver) | |||||
| while (need_playback || need_capture) { | while (need_playback || need_capture) { | ||||
| int p_timed_out, c_timed_out; | int p_timed_out, c_timed_out; | ||||
| int ci; | |||||
| int ci = 0; | |||||
| int nfds; | int nfds; | ||||
| nfds = 0; | nfds = 0; | ||||
| @@ -37,6 +37,14 @@ | |||||
| #include <jack/pool.h> | #include <jack/pool.h> | ||||
| #include <jack/error.h> | #include <jack/error.h> | ||||
| char *jack_temp_dir = "/tmp"; | |||||
| void | |||||
| jack_set_temp_dir (const char *path) | |||||
| { | |||||
| jack_temp_dir = strdup (path); | |||||
| } | |||||
| static jack_port_t *jack_port_new (jack_client_t *client, jack_port_id_t port_id, jack_control_t *control); | static jack_port_t *jack_port_new (jack_client_t *client, jack_port_id_t port_id, jack_control_t *control); | ||||
| static pthread_mutex_t client_lock; | static pthread_mutex_t client_lock; | ||||
| @@ -250,7 +258,7 @@ server_connect (int which) | |||||
| } | } | ||||
| addr.sun_family = AF_UNIX; | addr.sun_family = AF_UNIX; | ||||
| g_snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "/tmp/jack_%d", which); | |||||
| g_snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "%s/jack_%d", jack_temp_dir, which); | |||||
| if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { | if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { | ||||
| jack_error ("cannot connect to jack server", strerror (errno)); | jack_error ("cannot connect to jack server", strerror (errno)); | ||||
| @@ -276,7 +284,7 @@ server_event_connect (jack_client_t *client) | |||||
| } | } | ||||
| addr.sun_family = AF_UNIX; | addr.sun_family = AF_UNIX; | ||||
| g_snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "/tmp/jack_ack_0"); | |||||
| g_snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "%s/jack_ack_0", jack_temp_dir); | |||||
| if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { | if (connect (fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) { | ||||
| jack_error ("cannot connect to jack server for events", strerror (errno)); | jack_error ("cannot connect to jack server for events", strerror (errno)); | ||||
| @@ -4,8 +4,8 @@ AC_INIT(client.c) | |||||
| AC_CONFIG_AUX_DIR(.) | AC_CONFIG_AUX_DIR(.) | ||||
| JACK_MAJOR_VERSION=0 | JACK_MAJOR_VERSION=0 | ||||
| JACK_MINOR_VERSION=4 | |||||
| JACK_MICRO_VERSION=7 | |||||
| JACK_MINOR_VERSION=5 | |||||
| JACK_MICRO_VERSION=0 | |||||
| BETA= | BETA= | ||||
| @@ -28,6 +28,7 @@ | |||||
| #include <sys/shm.h> | #include <sys/shm.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <stdarg.h> | #include <stdarg.h> | ||||
| #include <dirent.h> | |||||
| #include <sys/ipc.h> | #include <sys/ipc.h> | ||||
| #include <signal.h> | #include <signal.h> | ||||
| #include <sys/types.h> | #include <sys/types.h> | ||||
| @@ -41,6 +42,8 @@ | |||||
| #include <jack/engine.h> | #include <jack/engine.h> | ||||
| #include <jack/driver.h> | #include <jack/driver.h> | ||||
| #define MAX_SHM_ID 256 /* likely use is more like 16 */ | |||||
| typedef struct { | typedef struct { | ||||
| jack_port_internal_t *source; | jack_port_internal_t *source; | ||||
| @@ -94,6 +97,8 @@ static int jack_deliver_event (jack_engine_t *, jack_client_internal_t *, jack_ | |||||
| static void jack_audio_port_mixdown (jack_port_t *port, nframes_t nframes); | static void jack_audio_port_mixdown (jack_port_t *port, nframes_t nframes); | ||||
| static int *jack_shm_registry; | |||||
| static int jack_shm_id_cnt; | |||||
| jack_port_type_info_t builtin_port_types[] = { | jack_port_type_info_t builtin_port_types[] = { | ||||
| { JACK_DEFAULT_AUDIO_TYPE, jack_audio_port_mixdown, 1 }, | { JACK_DEFAULT_AUDIO_TYPE, jack_audio_port_mixdown, 1 }, | ||||
| @@ -106,14 +111,6 @@ jack_client_is_inprocess (jack_client_internal_t *client) | |||||
| return (client->control->type == ClientDynamic) || (client->control->type == ClientDriver); | return (client->control->type == ClientDynamic) || (client->control->type == ClientDriver); | ||||
| } | } | ||||
| static | |||||
| void shm_destroy (int status, void *arg) | |||||
| { | |||||
| int shm_id = (int) arg; | |||||
| shmctl (shm_id, IPC_RMID, 0); | |||||
| } | |||||
| static int | static int | ||||
| make_sockets (int fd[2]) | make_sockets (int fd[2]) | ||||
| { | { | ||||
| @@ -129,7 +126,7 @@ make_sockets (int fd[2]) | |||||
| addr.sun_family = AF_UNIX; | addr.sun_family = AF_UNIX; | ||||
| for (i = 0; i < 999; i++) { | for (i = 0; i < 999; i++) { | ||||
| snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "/tmp/jack_%d", i); | |||||
| snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "%s/jack_%d", jack_temp_dir, i); | |||||
| if (access (addr.sun_path, F_OK) != 0) { | if (access (addr.sun_path, F_OK) != 0) { | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -163,7 +160,7 @@ make_sockets (int fd[2]) | |||||
| addr.sun_family = AF_UNIX; | addr.sun_family = AF_UNIX; | ||||
| for (i = 0; i < 999; i++) { | for (i = 0; i < 999; i++) { | ||||
| snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "/tmp/jack_ack_%d", i); | |||||
| snprintf (addr.sun_path, sizeof (addr.sun_path) - 1, "%s/jack_ack_%d", jack_temp_dir, i); | |||||
| if (access (addr.sun_path, F_OK) != 0) { | if (access (addr.sun_path, F_OK) != 0) { | ||||
| break; | break; | ||||
| } | } | ||||
| @@ -229,6 +226,88 @@ jack_cleanup_clients (jack_engine_t *engine) | |||||
| } | } | ||||
| } | } | ||||
| static int | |||||
| jack_initialize_shm () | |||||
| { | |||||
| int shmid_id; | |||||
| void *addr; | |||||
| if (jack_shm_registry != NULL) { | |||||
| return 0; | |||||
| } | |||||
| /* grab a chunk of memory to store shm ids in. this is | |||||
| to allow our parent to clean up all such ids when | |||||
| if we exit. otherwise, they can get lost in crash | |||||
| or debugger driven exits. | |||||
| */ | |||||
| if ((shmid_id = shmget (random(), sizeof(int) * MAX_SHM_ID, IPC_CREAT|0600)) < 0) { | |||||
| jack_error ("cannot create engine shm ID registry (%s)", strerror (errno)); | |||||
| return -1; | |||||
| } | |||||
| if ((addr = shmat (shmid_id, 0, 0)) == (void *) -1) { | |||||
| jack_error ("cannot attach shm ID registry (%s)", strerror (errno)); | |||||
| shmctl (shmid_id, IPC_RMID, 0); | |||||
| return -1; | |||||
| } | |||||
| if (shmctl (shmid_id, IPC_RMID, NULL)) { | |||||
| jack_error ("cannot mark shm ID registry as destroyed (%s)", strerror (errno)); | |||||
| return -1; | |||||
| } | |||||
| jack_shm_registry = (int *) addr; | |||||
| jack_shm_id_cnt = 0; | |||||
| return 0; | |||||
| } | |||||
| static void | |||||
| jack_register_shm (int shmid) | |||||
| { | |||||
| if (jack_shm_id_cnt < MAX_SHM_ID) { | |||||
| jack_shm_registry[jack_shm_id_cnt++] = shmid; | |||||
| } | |||||
| } | |||||
| void | |||||
| jack_cleanup_shm () | |||||
| { | |||||
| int i; | |||||
| for (i = 0; i < jack_shm_id_cnt; i++) { | |||||
| fprintf (stderr, "removing shm ID[%d] = %d\n", i, jack_shm_registry[i]); | |||||
| shmctl (jack_shm_registry[i], IPC_RMID, NULL); | |||||
| } | |||||
| } | |||||
| void | |||||
| jack_cleanup_files () | |||||
| { | |||||
| DIR *dir; | |||||
| struct dirent *dirent; | |||||
| /* its important that we remove all files that jackd creates | |||||
| because otherwise subsequent attempts to start jackd will | |||||
| believe that an instance is already running. | |||||
| */ | |||||
| if ((dir = opendir (jack_temp_dir)) == NULL) { | |||||
| fprintf (stderr, "jack(%d): cannot open jack FIFO directory (%s)\n", getpid(), strerror (errno)); | |||||
| return; | |||||
| } | |||||
| while ((dirent = readdir (dir)) != NULL) { | |||||
| if (strncmp (dirent->d_name, "jack-", 5) == 0 || strncmp (dirent->d_name, "jack_", 5) == 0) { | |||||
| char fullpath[PATH_MAX+1]; | |||||
| sprintf (fullpath, "%s/%s", jack_temp_dir, dirent->d_name); | |||||
| unlink (fullpath); | |||||
| } | |||||
| } | |||||
| closedir (dir); | |||||
| } | |||||
| static int | static int | ||||
| jack_add_port_segment (jack_engine_t *engine, unsigned long nports) | jack_add_port_segment (jack_engine_t *engine, unsigned long nports) | ||||
| @@ -249,14 +328,14 @@ jack_add_port_segment (jack_engine_t *engine, unsigned long nports) | |||||
| return -1; | return -1; | ||||
| } | } | ||||
| jack_register_shm (id); | |||||
| if ((addr = shmat (id, 0, 0)) == (char *) -1) { | if ((addr = shmat (id, 0, 0)) == (char *) -1) { | ||||
| jack_error ("cannot attach new port segment (%s)", strerror (errno)); | jack_error ("cannot attach new port segment (%s)", strerror (errno)); | ||||
| shmctl (id, IPC_RMID, 0); | shmctl (id, IPC_RMID, 0); | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| on_exit (shm_destroy, (void *) id); | |||||
| si = (jack_port_segment_info_t *) malloc (sizeof (jack_port_segment_info_t)); | si = (jack_port_segment_info_t *) malloc (sizeof (jack_port_segment_info_t)); | ||||
| si->shm_key = key; | si->shm_key = key; | ||||
| si->address = addr; | si->address = addr; | ||||
| @@ -1026,7 +1105,6 @@ jack_engine_new (int realtime, int rtpriority) | |||||
| engine->port_max = 128; | engine->port_max = 128; | ||||
| engine->rtpriority = rtpriority; | engine->rtpriority = rtpriority; | ||||
| engine->silent_buffer = 0; | engine->silent_buffer = 0; | ||||
| engine->getthehelloutathere = FALSE; | |||||
| pthread_mutex_init (&engine->graph_lock, 0); | pthread_mutex_init (&engine->graph_lock, 0); | ||||
| pthread_mutex_init (&engine->buffer_lock, 0); | pthread_mutex_init (&engine->buffer_lock, 0); | ||||
| @@ -1064,10 +1142,16 @@ jack_engine_new (int realtime, int rtpriority) | |||||
| engine->control_key = random(); | engine->control_key = random(); | ||||
| control_size = sizeof (jack_control_t) + (sizeof (jack_port_shared_t) * engine->port_max); | control_size = sizeof (jack_control_t) + (sizeof (jack_port_shared_t) * engine->port_max); | ||||
| if (jack_initialize_shm (engine)) { | |||||
| return 0; | |||||
| } | |||||
| if ((engine->control_shm_id = shmget (engine->control_key, control_size, IPC_CREAT|0644)) < 0) { | if ((engine->control_shm_id = shmget (engine->control_key, control_size, IPC_CREAT|0644)) < 0) { | ||||
| jack_error ("cannot create engine control shared memory segment (%s)", strerror (errno)); | jack_error ("cannot create engine control shared memory segment (%s)", strerror (errno)); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| jack_register_shm (engine->control_shm_id); | |||||
| if ((addr = shmat (engine->control_shm_id, 0, 0)) == (void *) -1) { | if ((addr = shmat (engine->control_shm_id, 0, 0)) == (void *) -1) { | ||||
| jack_error ("cannot attach control shared memory segment (%s)", strerror (errno)); | jack_error ("cannot attach control shared memory segment (%s)", strerror (errno)); | ||||
| @@ -1075,8 +1159,6 @@ jack_engine_new (int realtime, int rtpriority) | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| on_exit (shm_destroy, (void *) engine->control_shm_id); | |||||
| engine->control = (jack_control_t *) addr; | engine->control = (jack_control_t *) addr; | ||||
| /* Mark all ports as available */ | /* Mark all ports as available */ | ||||
| @@ -1109,7 +1191,7 @@ jack_engine_new (int realtime, int rtpriority) | |||||
| engine->control->buffer_size = 0; | engine->control->buffer_size = 0; | ||||
| engine->control->frame_time = 0; | engine->control->frame_time = 0; | ||||
| sprintf (engine->fifo_prefix, "/tmp/jack_fifo_%d", getpid()); | |||||
| sprintf (engine->fifo_prefix, "%s/ack_fifo_%d", jack_temp_dir, getpid()); | |||||
| (void) jack_get_fifo_fd (engine, 0); | (void) jack_get_fifo_fd (engine, 0); | ||||
| jack_start_server (engine); | jack_start_server (engine); | ||||
| @@ -1227,7 +1309,9 @@ int | |||||
| jack_engine_delete (jack_engine_t *engine) | jack_engine_delete (jack_engine_t *engine) | ||||
| { | { | ||||
| pthread_cancel (engine->main_thread); | |||||
| if (engine) { | |||||
| return pthread_cancel (engine->main_thread); | |||||
| } | |||||
| return 0; | return 0; | ||||
| } | } | ||||
| @@ -1253,6 +1337,8 @@ jack_client_internal_new (jack_engine_t *engine, int fd, jack_client_connect_req | |||||
| jack_error ("cannot create client control block"); | jack_error ("cannot create client control block"); | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| jack_register_shm (shm_id); | |||||
| if ((addr = shmat (shm_id, 0, 0)) == (void *) -1) { | if ((addr = shmat (shm_id, 0, 0)) == (void *) -1) { | ||||
| jack_error ("cannot attach new client control block"); | jack_error ("cannot attach new client control block"); | ||||
| @@ -73,15 +73,15 @@ struct _jack_engine { | |||||
| unsigned long fifo_size; | unsigned long fifo_size; | ||||
| unsigned long external_client_cnt; | unsigned long external_client_cnt; | ||||
| int rtpriority; | int rtpriority; | ||||
| int getthehelloutathere; | |||||
| }; | }; | ||||
| /* public functions */ | /* public functions */ | ||||
| jack_engine_t *jack_engine_new (int real_time, int real_time_priority); | |||||
| jack_engine_t *jack_engine_new (int real_time, int real_time_priority); | |||||
| int jack_engine_delete (jack_engine_t *); | int jack_engine_delete (jack_engine_t *); | ||||
| int jack_run (jack_engine_t *engine); | int jack_run (jack_engine_t *engine); | ||||
| int jack_wait (jack_engine_t *engine); | int jack_wait (jack_engine_t *engine); | ||||
| int jack_use_driver (jack_engine_t *, struct _jack_driver *); | int jack_use_driver (jack_engine_t *, struct _jack_driver *); | ||||
| void jack_set_temp_dir (const char *); | |||||
| #endif /* __jack_engine_h__ */ | #endif /* __jack_engine_h__ */ | ||||
| @@ -203,10 +203,15 @@ typedef struct { | |||||
| int status; | int status; | ||||
| } jack_request_t; | } jack_request_t; | ||||
| extern void jack_cleanup_shm (); | |||||
| extern void jack_cleanup_files (); | |||||
| extern int jack_client_handle_port_connection (jack_client_t *client, jack_event_t *event); | extern int jack_client_handle_port_connection (jack_client_t *client, jack_event_t *event); | ||||
| jack_client_t *jack_driver_become_client (const char *client_name); | jack_client_t *jack_driver_become_client (const char *client_name); | ||||
| extern char *jack_temp_dir; | |||||
| #endif /* __jack_internal_h__ */ | #endif /* __jack_internal_h__ */ | ||||
| @@ -22,7 +22,7 @@ | |||||
| #include <signal.h> | #include <signal.h> | ||||
| #include <getopt.h> | #include <getopt.h> | ||||
| #include <sys/types.h> | #include <sys/types.h> | ||||
| #include <dirent.h> | |||||
| #include <sys/shm.h> | |||||
| #include <string.h> | #include <string.h> | ||||
| #include <errno.h> | #include <errno.h> | ||||
| #include <wait.h> | #include <wait.h> | ||||
| @@ -32,7 +32,7 @@ | |||||
| #include <jack/driver.h> | #include <jack/driver.h> | ||||
| static sigset_t signals; | static sigset_t signals; | ||||
| static jack_engine_t *engine; | |||||
| static jack_engine_t *engine = 0; | |||||
| static int jackd_pid; | static int jackd_pid; | ||||
| static char *alsa_pcm_name = "default"; | static char *alsa_pcm_name = "default"; | ||||
| static nframes_t frames_per_interrupt = 64; | static nframes_t frames_per_interrupt = 64; | ||||
| @@ -40,111 +40,18 @@ static nframes_t srate = 48000; | |||||
| static int realtime = 0; | static int realtime = 0; | ||||
| static int realtime_priority = 10; | static int realtime_priority = 10; | ||||
| static int with_fork = 1; | static int with_fork = 1; | ||||
| static int need_cleanup = 1; | |||||
| #define JACK_TEMP_DIR "/tmp" | |||||
| static void | |||||
| cleanup () | |||||
| { | |||||
| DIR *dir; | |||||
| struct dirent *dirent; | |||||
| /* this doesn't have to truly atomic. in fact, its not even strictly | |||||
| necessary. it just potentially saves us from thrashing through | |||||
| the temp dir several times over. | |||||
| */ | |||||
| if (!need_cleanup) { | |||||
| return; | |||||
| } | |||||
| need_cleanup = 0; | |||||
| /* its important that we remove all files that jackd creates | |||||
| because otherwise subsequent attempts to start jackd will | |||||
| believe that an instance is already running. | |||||
| */ | |||||
| if ((dir = opendir (JACK_TEMP_DIR)) == NULL) { | |||||
| fprintf (stderr, "jackd(%d): cleanup - cannot open scratch directory (%s)\n", getpid(), strerror (errno)); | |||||
| return; | |||||
| } | |||||
| while ((dirent = readdir (dir)) != NULL) { | |||||
| if (strncmp (dirent->d_name, "jack-", 5) == 0 || strncmp (dirent->d_name, "jack_", 5) == 0) { | |||||
| char fullpath[PATH_MAX+1]; | |||||
| sprintf (fullpath, JACK_TEMP_DIR "/%s", dirent->d_name); | |||||
| unlink (fullpath); | |||||
| } | |||||
| } | |||||
| closedir (dir); | |||||
| } | |||||
| static void | static void | ||||
| signal_handler (int sig) | signal_handler (int sig) | ||||
| { | { | ||||
| fprintf (stderr, "parent (%d): killing jackd at %d\n", getpid(), jackd_pid); | |||||
| fprintf (stderr, "jackd: signal %d received\n", sig); | |||||
| kill (jackd_pid, SIGTERM); | kill (jackd_pid, SIGTERM); | ||||
| cleanup (); | |||||
| exit (1); | |||||
| } | } | ||||
| static void | static void | ||||
| catch_signals (void) | |||||
| { | |||||
| /* what's this for? | |||||
| this just makes sure that if we are using the fork | |||||
| approach to cleanup (see main()), the waiting | |||||
| process will catch common "interrupt" signals | |||||
| and terminate the real server appropriately. | |||||
| */ | |||||
| signal (SIGHUP, signal_handler); | |||||
| signal (SIGINT, signal_handler); | |||||
| signal (SIGQUIT, signal_handler); | |||||
| signal (SIGTERM, signal_handler); | |||||
| } | |||||
| static void * | |||||
| signal_thread (void *arg) | |||||
| { | |||||
| int sig; | |||||
| int err; | |||||
| pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | |||||
| /* Note: normal operation has with_form == 1 */ | |||||
| if (with_fork) { | |||||
| /* let the parent handle SIGINT */ | |||||
| sigdelset (&signals, SIGINT); | |||||
| } | |||||
| err = sigwait (&signals, &sig); | |||||
| fprintf (stderr, "child (%d): exiting due to signal %d\n", getpid(), sig); | |||||
| jack_engine_delete (engine); | |||||
| if (!with_fork) { | |||||
| /* no parent - take care of this ourselves */ | |||||
| cleanup (); | |||||
| } | |||||
| exit (err); | |||||
| /*NOTREACHED*/ | |||||
| return 0; | |||||
| } | |||||
| static int | |||||
| posix_me_harder (void) | posix_me_harder (void) | ||||
| { | { | ||||
| pthread_t thread_id; | |||||
| /* what's this for? | /* what's this for? | ||||
| POSIX says that signals are delivered like this: | POSIX says that signals are delivered like this: | ||||
| @@ -156,11 +63,11 @@ posix_me_harder (void) | |||||
| this means that a simple-minded multi-threaded | this means that a simple-minded multi-threaded | ||||
| program can expect to get POSIX signals delivered | program can expect to get POSIX signals delivered | ||||
| to any of its threads. | |||||
| randomly to any one of its threads, | |||||
| here, we block all signals that we think we | here, we block all signals that we think we | ||||
| might receive and want to catch. all later | |||||
| threads will inherit this setting. then we | |||||
| might receive and want to catch. all "child" | |||||
| threads will inherit this setting. if we | |||||
| create a thread that calls sigwait() on the | create a thread that calls sigwait() on the | ||||
| same set of signals, implicitly unblocking | same set of signals, implicitly unblocking | ||||
| all those signals. any of those signals that | all those signals. any of those signals that | ||||
| @@ -187,7 +94,7 @@ posix_me_harder (void) | |||||
| sigaddset(&signals, SIGTERM); | sigaddset(&signals, SIGTERM); | ||||
| /* this can make debugging a pain, but it also makes | /* this can make debugging a pain, but it also makes | ||||
| segv-exits cleanup after themselves rather than | |||||
| segv-exits cleanup_files after themselves rather than | |||||
| leaving the audio thread active. i still | leaving the audio thread active. i still | ||||
| find it truly wierd that _exit() or whatever is done | find it truly wierd that _exit() or whatever is done | ||||
| by the default SIGSEGV handler does not | by the default SIGSEGV handler does not | ||||
| @@ -200,44 +107,92 @@ posix_me_harder (void) | |||||
| /* all child threads will inherit this mask */ | /* all child threads will inherit this mask */ | ||||
| pthread_sigmask (SIG_BLOCK, &signals, 0); | pthread_sigmask (SIG_BLOCK, &signals, 0); | ||||
| /* start a thread to wait for signals */ | |||||
| if (pthread_create (&thread_id, 0, signal_thread, 0)) { | |||||
| fprintf (stderr, "cannot create signal catching thread"); | |||||
| return -1; | |||||
| } | |||||
| pthread_detach (thread_id); | |||||
| return 0; | |||||
| } | } | ||||
| static void | |||||
| jack_main () | |||||
| static void * | |||||
| jack_engine_waiter_thread (void *arg) | |||||
| { | { | ||||
| pid_t signal_pid = (pid_t) arg; | |||||
| jack_driver_t *driver; | jack_driver_t *driver; | ||||
| posix_me_harder (); | |||||
| pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | |||||
| if ((engine = jack_engine_new (realtime, realtime_priority)) == 0) { | if ((engine = jack_engine_new (realtime, realtime_priority)) == 0) { | ||||
| fprintf (stderr, "cannot create engine\n"); | fprintf (stderr, "cannot create engine\n"); | ||||
| return; | |||||
| kill (signal_pid, SIGTERM); | |||||
| return 0; | |||||
| } | } | ||||
| if ((driver = jack_driver_load (ADDON_DIR "/jack_alsa.so", alsa_pcm_name, frames_per_interrupt, srate)) == 0) { | if ((driver = jack_driver_load (ADDON_DIR "/jack_alsa.so", alsa_pcm_name, frames_per_interrupt, srate)) == 0) { | ||||
| fprintf (stderr, "cannot load ALSA driver module\n"); | fprintf (stderr, "cannot load ALSA driver module\n"); | ||||
| return; | |||||
| kill (signal_pid, SIGTERM); | |||||
| return 0; | |||||
| } | } | ||||
| jack_use_driver (engine, driver); | jack_use_driver (engine, driver); | ||||
| if (jack_run (engine)) { | if (jack_run (engine)) { | ||||
| fprintf (stderr, "cannot start main JACK thread\n"); | fprintf (stderr, "cannot start main JACK thread\n"); | ||||
| return; | |||||
| kill (signal_pid, SIGTERM); | |||||
| return 0; | |||||
| } | } | ||||
| jack_wait (engine); | jack_wait (engine); | ||||
| fprintf (stderr, "telling signal thread that the engine is done\n"); | |||||
| kill (signal_pid, SIGHUP); | |||||
| return 0; /* nobody cares what this returns */ | |||||
| } | |||||
| static void | |||||
| jack_main () | |||||
| { | |||||
| int sig; | |||||
| int err; | |||||
| pthread_t waiter_thread; | |||||
| pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | |||||
| posix_me_harder (); | |||||
| /* what we'd really like to do here is to be able to | |||||
| wait for either the engine to stop or a POSIX signal, | |||||
| whichever arrives sooner. but there is no mechanism | |||||
| to do that, so instead we create a thread to wait | |||||
| for the engine to finish, and here we stop and wait | |||||
| for any (reasonably likely) POSIX signal. | |||||
| if the engine finishes first, the waiter thread will | |||||
| tell us about it via a signal. | |||||
| if a signal arrives, we'll stop the engine and then | |||||
| exit. | |||||
| in normal operation, our parent process will be waiting | |||||
| for us and will cleanup. | |||||
| */ | |||||
| if (pthread_create (&waiter_thread, 0, jack_engine_waiter_thread, (void *) getpid())) { | |||||
| fprintf (stderr, "jackd: cannot create engine waiting thread\n"); | |||||
| return; | |||||
| } | |||||
| /* Note: normal operation has with_fork == 1 */ | |||||
| if (with_fork) { | |||||
| /* let the parent handle SIGINT */ | |||||
| sigdelset (&signals, SIGINT); | |||||
| } | |||||
| err = sigwait (&signals, &sig); | |||||
| fprintf (stderr, "signal waiter: exiting due to signal %d\n", sig); | |||||
| pthread_cancel (waiter_thread); | |||||
| jack_engine_delete (engine); | |||||
| return; | |||||
| } | } | ||||
| static void usage () | static void usage () | ||||
| @@ -256,9 +211,10 @@ int | |||||
| main (int argc, char *argv[]) | main (int argc, char *argv[]) | ||||
| { | { | ||||
| const char *options = "hd:r:p:RP:F"; | |||||
| const char *options = "hd:r:p:RP:FD:"; | |||||
| struct option long_options[] = | struct option long_options[] = | ||||
| { | { | ||||
| { "tmpdir", 1, 0, 'D' }, | |||||
| { "device", 1, 0, 'd' }, | { "device", 1, 0, 'd' }, | ||||
| { "srate", 1, 0, 'r' }, | { "srate", 1, 0, 'r' }, | ||||
| { "frames-per-interrupt", 1, 0, 'p' }, | { "frames-per-interrupt", 1, 0, 'p' }, | ||||
| @@ -274,6 +230,10 @@ main (int argc, char *argv[]) | |||||
| opterr = 0; | opterr = 0; | ||||
| while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) { | while ((opt = getopt_long (argc, argv, options, long_options, &option_index)) != EOF) { | ||||
| switch (opt) { | switch (opt) { | ||||
| case 'D': | |||||
| jack_set_temp_dir (optarg); | |||||
| break; | |||||
| case 'd': | case 'd': | ||||
| alsa_pcm_name = optarg; | alsa_pcm_name = optarg; | ||||
| break; | break; | ||||
| @@ -307,26 +267,39 @@ main (int argc, char *argv[]) | |||||
| } | } | ||||
| if (!with_fork) { | if (!with_fork) { | ||||
| /* This is really here so that we can run gdb easily */ | |||||
| jack_main (); | jack_main (); | ||||
| cleanup (); | |||||
| } else { | } else { | ||||
| int pid = fork (); | int pid = fork (); | ||||
| if (pid < 0) { | if (pid < 0) { | ||||
| fprintf (stderr, "could not fork jack server (%s)", strerror (errno)); | fprintf (stderr, "could not fork jack server (%s)", strerror (errno)); | ||||
| exit (1); | exit (1); | ||||
| } else if (pid == 0) { | } else if (pid == 0) { | ||||
| jack_main (); | jack_main (); | ||||
| } else { | } else { | ||||
| jackd_pid = pid; | jackd_pid = pid; | ||||
| catch_signals (); | |||||
| signal (SIGHUP, signal_handler); | |||||
| signal (SIGINT, signal_handler); | |||||
| signal (SIGQUIT, signal_handler); | |||||
| signal (SIGTERM, signal_handler); | |||||
| waitpid (pid, NULL, 0); | waitpid (pid, NULL, 0); | ||||
| cleanup (); | |||||
| } | } | ||||
| } | } | ||||
| jack_cleanup_shm (); | |||||
| jack_cleanup_files (); | |||||
| return 0; | return 0; | ||||
| } | } | ||||