~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
JACK/jackd/jackd.c


** Warning: Cannot open xref database.

1 /* -*- mode: c; c-file-style: "bsd"; -*- */ 2 /* 3 Copyright (C) 2001-2003 Paul Davis 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, write to the Free Software 17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 19 $Id: jackd.c,v 1.29 2003/12/01 19:45:17 pbd Exp $ 20 */ 21 22 #include <stdio.h> 23 #include <signal.h> 24 #include <getopt.h> 25 #include <sys/types.h> 26 #include <sys/shm.h> 27 #include <sys/wait.h> 28 #include <string.h> 29 #include <errno.h> 30 #include <stdlib.h> 31 #include <dirent.h> 32 #include <dlfcn.h> 33 34 #include <config.h> 35 36 #include <jack/engine.h> 37 #include <jack/internal.h> 38 #include <jack/driver.h> 39 #include <jack/shm.h> 40 #include <jack/driver_parse.h> 41 42 #ifdef USE_CAPABILITIES 43 44 #include <sys/stat.h> 45 /* capgetp and capsetp are linux only extensions, not posix */ 46 #undef _POSIX_SOURCE 47 #include <sys/capability.h> 48 #include <jack/start.h> 49 50 static struct stat pipe_stat; 51 52 #endif 53 54 static JSList * drivers = NULL; 55 static sigset_t signals; 56 static jack_engine_t *engine = 0; 57 static int realtime = 0; 58 static int realtime_priority = 10; 59 static int verbose = 0; 60 static int client_timeout = 500; /* msecs */ 61 62 static void 63 do_nothing_handler (int sig) 64 { 65 /* this is used by the child (active) process, but it never 66 gets called unless we are already shutting down after 67 another signal. 68 */ 69 char buf[64]; 70 snprintf (buf, sizeof(buf), 71 "received signal %d during shutdown (ignored)\n", sig); 72 write (1, buf, strlen (buf)); 73 } 74 75 static int 76 jack_main (jack_driver_desc_t * driver_desc, JSList * driver_params) 77 { 78 int sig; 79 int i; 80 sigset_t allsignals; 81 struct sigaction action; 82 int waiting; 83 84 /* ensure that we are in our own process group so that 85 kill (SIG, -pgrp) does the right thing. 86 */ 87 88 setsid (); 89 90 pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 91 92 /* what's this for? 93 94 POSIX says that signals are delivered like this: 95 96 * if a thread has blocked that signal, it is not 97 a candidate to receive the signal. 98 * of all threads not blocking the signal, pick 99 one at random, and deliver the signal. 100 101 this means that a simple-minded multi-threaded program can 102 expect to get POSIX signals delivered randomly to any one 103 of its threads, 104 105 here, we block all signals that we think we might receive 106 and want to catch. all "child" threads will inherit this 107 setting. if we create a thread that calls sigwait() on the 108 same set of signals, implicitly unblocking all those 109 signals. any of those signals that are delivered to the 110 process will be delivered to that thread, and that thread 111 alone. this makes cleanup for a signal-driven exit much 112 easier, since we know which thread is doing it and more 113 importantly, we are free to call async-unsafe functions, 114 because the code is executing in normal thread context 115 after a return from sigwait(). 116 */ 117 118 sigemptyset (&signals); 119 sigaddset(&signals, SIGHUP); 120 sigaddset(&signals, SIGINT); 121 sigaddset(&signals, SIGQUIT); 122 sigaddset(&signals, SIGPIPE); 123 sigaddset(&signals, SIGTERM); 124 sigaddset(&signals, SIGUSR1); 125 sigaddset(&signals, SIGUSR2); 126 127 /* all child threads will inherit this mask unless they 128 * explicitly reset it 129 */ 130 131 pthread_sigmask (SIG_BLOCK, &signals, 0); 132 133 /* get the engine/driver started */ 134 135 if ((engine = jack_engine_new (realtime, realtime_priority, 136 verbose, client_timeout, 137 getpid(), drivers)) == 0) { 138 fprintf (stderr, "cannot create engine\n"); 139 return -1; 140 } 141 142 fprintf (stderr, "loading driver ..\n"); 143 144 if (jack_engine_load_driver (engine, driver_desc, driver_params)) { 145 fprintf (stderr, "cannot load driver module %s\n", driver_desc->name); 146 return -1; 147 } 148 149 if (engine->driver->start (engine->driver) != 0) { 150 jack_error ("cannot start driver"); 151 return -1; 152 } 153 154 /* install a do-nothing handler because otherwise pthreads 155 behaviour is undefined when we enter sigwait. 156 */ 157 158 sigfillset (&allsignals); 159 action.sa_handler = do_nothing_handler; 160 action.sa_mask = allsignals; 161 action.sa_flags = SA_RESTART|SA_RESETHAND; 162 163 for (i = 1; i < NSIG; i++) { 164 if (sigismember (&signals, i)) { 165 sigaction (i, &action, 0); 166 } 167 } 168 169 if (verbose) { 170 fprintf (stderr, "%d waiting for signals\n", getpid()); 171 } 172 173 waiting = TRUE; 174 175 while (waiting) { 176 sigwait (&signals, &sig); 177 178 fprintf (stderr, "jack main caught signal %d\n", sig); 179 180 switch (sig) { 181 case SIGUSR1: 182 jack_dump_configuration(engine, 1); 183 break; 184 case SIGUSR2: 185 /* driver exit */ 186 waiting = FALSE; 187 break; 188 default: 189 waiting = FALSE; 190 break; 191 } 192 } 193 194 if (sig != SIGSEGV) { 195 196 /* unblock signals so we can see them during shutdown. 197 this will help prod developers not to lose sight of 198 bugs that cause segfaults etc. during shutdown. 199 */ 200 sigprocmask (SIG_UNBLOCK, &signals, 0); 201 } 202 203 jack_engine_delete (engine); 204 return 1; 205 } 206 207 static jack_driver_desc_t * 208 jack_drivers_get_descriptor (JSList * drivers, const char * sofile) 209 { 210 jack_driver_desc_t * descriptor, * other_descriptor; 211 JackDriverDescFunction so_get_descriptor; 212 JSList * node; 213 void * dlhandle; 214 char * filename; 215 const char * dlerr; 216 int err; 217 218 filename = malloc (strlen (ADDON_DIR) + 1 + strlen (sofile) + 1); 219 sprintf (filename, "%s/%s", ADDON_DIR, sofile); 220 221 if (verbose) 222 printf ("getting driver descriptor from %s\n", filename); 223 224 dlhandle = dlopen (filename, RTLD_NOW|RTLD_GLOBAL); 225 if (!dlhandle) { 226 jack_error ("could not open driver .so '%s': %s\n", filename, dlerror ()); 227 free (filename); 228 return NULL; 229 } 230 231 dlerror (); 232 233 so_get_descriptor = (JackDriverDescFunction) 234 dlsym (dlhandle, "driver_get_descriptor"); 235 236 dlerr = dlerror (); 237 if (dlerr) { 238 dlclose (dlhandle); 239 free (filename); 240 return NULL; 241 } 242 243 descriptor = so_get_descriptor (); 244 if (!descriptor) { 245 jack_error ("driver from '%s' returned NULL descriptor\n", filename); 246 dlclose (dlhandle); 247 free (filename); 248 return NULL; 249 } 250 251 err = dlclose (dlhandle); 252 if (err) { 253 jack_error ("error closing driver .so '%s': %s\n", filename, dlerror ()); 254 } 255 256 257 /* check it doesn't exist already */ 258 for (node = drivers; node; node = jack_slist_next (node)) { 259 other_descriptor = (jack_driver_desc_t *) node->data; 260 261 if (strcmp (descriptor->name, other_descriptor->name) == 0) { 262 jack_error ("the drivers in '%s' and '%s' both have the name '%s'; using the first\n", 263 other_descriptor->file, filename, other_descriptor->name); 264 /* FIXME: delete the descriptor */ 265 free (filename); 266 return NULL; 267 } 268 } 269 270 strncpy (descriptor->file, filename, PATH_MAX); 271 free (filename); 272 273 return descriptor; 274 275 } 276 277 static JSList * 278 jack_drivers_load () 279 { 280 struct dirent * dir_entry; 281 DIR * dir_stream; 282 const char * ptr; 283 int err; 284 JSList * driver_list = NULL; 285 jack_driver_desc_t * desc; 286 287 /* search through the ADDON_DIR and add get descriptors 288 from the .so files in it */ 289 dir_stream = opendir (ADDON_DIR); 290 if (!dir_stream) { 291 jack_error ("could not open driver directory %s: %s\n", ADDON_DIR, strerror (errno)); 292 return NULL; 293 } 294 295 while ( (dir_entry = readdir (dir_stream)) ) { 296 /* check the filename is of the right format */ 297 if (strncmp ("jack_", dir_entry->d_name, 5) != 0) { 298 continue; 299 } 300 301 ptr = strrchr (dir_entry->d_name, '.'); 302 if (!ptr) { 303 continue; 304 } 305 ptr++; 306 if (strncmp ("so", ptr, 2) != 0) { 307 continue; 308 } 309 310 desc = jack_drivers_get_descriptor (drivers, dir_entry->d_name); 311 if (desc) { 312 driver_list = jack_slist_append (driver_list, desc); 313 } 314 315 } 316 317 err = closedir (dir_stream); 318 if (err) { 319 jack_error ("error closing driver directory %s: %s\n", ADDON_DIR, strerror (errno)); 320 } 321 322 if (!driver_list) { 323 jack_error ("could not find any drivers in %s!\n", ADDON_DIR); 324 return NULL; 325 } 326 327 return driver_list; 328 } 329 330 static void copyright (FILE* file) 331 { 332 fprintf (file, "jackd " VERSION "\n" 333 "Copyright 2001-2003 Paul Davis and others.\n" 334 "jackd comes with ABSOLUTELY NO WARRANTY\n" 335 "This is free software, and you are welcome to redistribute it\n" 336 "under certain conditions; see the file COPYING for details\n\n"); 337 } 338 339 static void usage (FILE *file) 340 { 341 copyright (file); 342 fprintf (file, "\n" 343 "usage: jackd [ --realtime OR -R [ --realtime-priority OR -P priority ] ]\n" 344 " [ --timeout OR -t client-timeout-in-msecs ]\n" 345 " [ --verbose OR -v ]\n" 346 " [ --silent OR -s ]\n" 347 " [ --version OR -V ]\n" 348 " -d driver [ ... driver args ... ]\n" 349 " driver can be `alsa', `dummy' or `portaudio'\n\n" 350 " jackd -d driver --help\n" 351 " to display options for each driver\n\n"); 352 } 353 354 static jack_driver_desc_t * 355 jack_find_driver_descriptor (const char * name) 356 { 357 jack_driver_desc_t * desc = 0; 358 JSList * node; 359 360 for (node = drivers; node; node = jack_slist_next (node)) { 361 desc = (jack_driver_desc_t *) node->data; 362 363 if (strcmp (desc->name, name) != 0) { 364 desc = NULL; 365 } else { 366 break; 367 } 368 } 369 370 return desc; 371 } 372 373 int 374 main (int argc, char *argv[]) 375 376 { 377 jack_driver_desc_t * desc; 378 const char *options = "-ad:P:vshVRFl:t:"; 379 struct option long_options[] = 380 { 381 { "driver", 1, 0, 'd' }, 382 { "verbose", 0, 0, 'v' }, 383 { "help", 0, 0, 'h' }, 384 { "realtime", 0, 0, 'R' }, 385 { "realtime-priority", 1, 0, 'P' }, 386 { "timeout", 1, 0, 't' }, 387 { "version", 0, 0, 'V' }, 388 { "silent", 0, 0, 's' }, 389 { 0, 0, 0, 0 } 390 }; 391 int option_index; 392 int opt; 393 int seen_driver = 0; 394 char *driver_name = 0; 395 char **driver_args = 0; 396 JSList * driver_params; 397 int driver_nargs = 1; 398 int show_version = 0; 399 int i; 400 #ifdef USE_CAPABILITIES 401 int status; 402 #endif 403 404 setvbuf (stdout, NULL, _IOLBF, 0); 405 406 #ifdef USE_CAPABILITIES 407 408 /* check to see if there is a pipe in the right descriptor */ 409 if ((status = fstat (PIPE_WRITE_FD, &pipe_stat)) == 0 && 410 S_ISFIFO(pipe_stat.st_mode)) { 411 412 /* tell jackstart we are up and running */ 413 char c = 1; 414 415 if (write (PIPE_WRITE_FD, &c, 1) != 1) { 416 fprintf (stderr, "cannot write to jackstart sync " 417 "pipe %d (%s)\n", PIPE_WRITE_FD, 418 strerror (errno)); 419 } 420 421 if (close(PIPE_WRITE_FD) != 0) { 422 fprintf(stderr, 423 "jackd: error on startup pipe close: %s\n", 424 strerror (errno)); 425 } else { 426 /* wait for jackstart process to set our capabilities */ 427 if (wait (&status) == -1) { 428 fprintf (stderr, "jackd: wait for startup " 429 "process exit failed\n"); 430 } 431 if (!WIFEXITED (status) || WEXITSTATUS (status)) { 432 fprintf(stderr, "jackd: jackstart did not " 433 "exit cleanly\n"); 434 exit (1); 435 } 436 } 437 } 438 #endif 439 opterr = 0; 440 while (!seen_driver && (opt = getopt_long (argc, argv, options, 441 long_options, 442 &option_index)) != EOF) { 443 switch (opt) { 444 445 case 'd': 446 seen_driver = 1; 447 driver_name = optarg; 448 break; 449 450 case 'v': 451 verbose = 1; 452 break; 453 454 case 's': 455 jack_set_error_function (silent_jack_error_callback); 456 break; 457 458 case 'P': 459 realtime_priority = atoi (optarg); 460 break; 461 462 case 'R': 463 realtime = 1; 464 break; 465 466 case 't': 467 client_timeout = atoi (optarg); 468 break; 469 470 case 'V': 471 show_version = 1; 472 break; 473 474 default: 475 fprintf (stderr, "unknown option character %c\n", optopt); 476 /*fallthru*/ 477 case 'h': 478 usage (stdout); 479 return -1; 480 } 481 } 482 483 if (show_version) { 484 printf ( "jackd version " VERSION "\n"); 485 #ifdef DEFAULT_TMP_DIR 486 printf ( "default tmp directory: " DEFAULT_TMP_DIR "\n"); 487 #else 488 printf ( "default tmp directory: /tmp\n"); 489 #endif 490 return -1; 491 } 492 493 if (!seen_driver) { 494 usage (stderr); 495 exit (1); 496 } 497 498 drivers = jack_drivers_load (); 499 if (!drivers) 500 { 501 fprintf (stderr, "jackd: no drivers found; exiting\n"); 502 exit (1); 503 } 504 505 desc = jack_find_driver_descriptor (driver_name); 506 if (!desc) 507 { 508 fprintf (stderr, "jackd: unknown driver '%s'\n", driver_name); 509 exit (1); 510 } 511 512 if (optind < argc) { 513 driver_nargs = 1 + argc - optind; 514 } else { 515 driver_nargs = 1; 516 } 517 518 if (driver_nargs == 0) { 519 fprintf (stderr, "No driver specified ... hmm. JACK won't do" 520 " anything when run like this.\n"); 521 return -1; 522 } 523 524 driver_args = (char **) malloc (sizeof (char *) * driver_nargs); 525 driver_args[0] = driver_name; 526 527 for (i = 1; i < driver_nargs; i++) { 528 driver_args[i] = argv[optind++]; 529 } 530 531 i = jack_parse_driver_params (desc, driver_nargs, driver_args, &driver_params); 532 if (i) 533 exit (0); 534 535 copyright (stdout); 536 537 jack_cleanup_shm (); 538 jack_cleanup_files (); 539 540 jack_main (desc, driver_params); 541 542 jack_cleanup_shm (); 543 jack_cleanup_files (); 544 545 exit (0); 546 } 547 548

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.