jack1 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

953 lines
24KB

  1. /* -*- mode: c; c-file-style: "bsd"; -*- */
  2. /*
  3. * Client creation and destruction interfaces for JACK engine.
  4. *
  5. * Copyright (C) 2001-2003 Paul Davis
  6. * Copyright (C) 2004 Jack O'Quin
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21. *
  22. * $Id$
  23. */
  24. #include <config.h>
  25. #include <errno.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <jack/internal.h>
  29. #include <jack/engine.h>
  30. #include <jack/messagebuffer.h>
  31. #include <jack/version.h>
  32. #include <sysdeps/poll.h>
  33. #include <sysdeps/ipc.h>
  34. #include "clientengine.h"
  35. #include "transengine.h"
  36. #define JACK_ERROR_WITH_SOCKETS 10000000
  37. static void
  38. jack_client_disconnect_ports (jack_engine_t *engine,
  39. jack_client_internal_t *client)
  40. {
  41. JSList *node;
  42. jack_port_internal_t *port;
  43. /* call tree **** MUST HOLD *** engine->client_lock */
  44. for (node = client->ports; node; node = jack_slist_next (node)) {
  45. port = (jack_port_internal_t *) node->data;
  46. jack_port_clear_connections (engine, port);
  47. jack_port_registration_notify (engine, port->shared->id, FALSE);
  48. jack_port_release (engine, port);
  49. }
  50. jack_slist_free (client->ports);
  51. jack_slist_free (client->truefeeds);
  52. jack_slist_free (client->sortfeeds);
  53. client->truefeeds = 0;
  54. client->sortfeeds = 0;
  55. client->ports = 0;
  56. }
  57. int
  58. jack_client_do_deactivate (jack_engine_t *engine,
  59. jack_client_internal_t *client, int sort_graph)
  60. {
  61. /* caller must hold engine->client_lock and must have checked for and/or
  62. * cleared all connections held by client. */
  63. client->control->active = FALSE;
  64. jack_transport_client_exit (engine, client);
  65. if (!jack_client_is_internal (client) &&
  66. engine->external_client_cnt > 0) {
  67. engine->external_client_cnt--;
  68. }
  69. if (sort_graph) {
  70. jack_sort_graph (engine);
  71. }
  72. return 0;
  73. }
  74. static void
  75. jack_zombify_client (jack_engine_t *engine, jack_client_internal_t *client)
  76. {
  77. VERBOSE (engine, "removing client \"%s\" from the processing chain\n",
  78. client->control->name);
  79. /* caller must hold the client_lock */
  80. /* this stops jack_deliver_event() from doing anything */
  81. client->control->dead = TRUE;
  82. jack_client_disconnect_ports (engine, client);
  83. jack_client_do_deactivate (engine, client, FALSE);
  84. }
  85. static void
  86. jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)
  87. {
  88. /* called *without* the request_lock */
  89. unsigned int i;
  90. JSList *node;
  91. /* caller must hold the client_lock */
  92. VERBOSE (engine, "removing client \"%s\"\n", client->control->name);
  93. /* if its not already a zombie, make it so */
  94. if (!client->control->dead) {
  95. jack_zombify_client (engine, client);
  96. }
  97. if (client->control->type == ClientExternal) {
  98. /* try to force the server thread to return from poll */
  99. close (client->event_fd);
  100. close (client->request_fd);
  101. /* rearrange the pollfd array so that things work right the
  102. next time we go into poll(2).
  103. */
  104. for (i = 0; i < engine->pfd_max; i++) {
  105. if (engine->pfd[i].fd == client->request_fd) {
  106. if (i+1 < engine->pfd_max) {
  107. memmove (&engine->pfd[i],
  108. &engine->pfd[i+1],
  109. sizeof (struct pollfd)
  110. * (engine->pfd_max - i));
  111. }
  112. engine->pfd_max--;
  113. }
  114. }
  115. }
  116. for (node = engine->clients; node; node = jack_slist_next (node)) {
  117. if (((jack_client_internal_t *) node->data)->control->id
  118. == client->control->id) {
  119. engine->clients =
  120. jack_slist_remove_link (engine->clients, node);
  121. jack_slist_free_1 (node);
  122. break;
  123. }
  124. }
  125. jack_client_delete (engine, client);
  126. /* ignore the driver, which counts as a client. */
  127. if (engine->temporary && (jack_slist_length(engine->clients) <= 1)) {
  128. exit(0);
  129. }
  130. }
  131. void
  132. jack_remove_clients (jack_engine_t* engine)
  133. {
  134. JSList *tmp, *node;
  135. int need_sort = FALSE;
  136. jack_client_internal_t *client;
  137. /* remove all dead clients */
  138. for (node = engine->clients; node; ) {
  139. tmp = jack_slist_next (node);
  140. client = (jack_client_internal_t *) node->data;
  141. if (client->error) {
  142. /* if we have a communication problem with the
  143. client, remove it. otherwise, turn it into
  144. a zombie. the client will/should realize
  145. this and will close its sockets. then
  146. we'll end up back here again and will
  147. finally remove the client.
  148. */
  149. if (client->error >= JACK_ERROR_WITH_SOCKETS) {
  150. VERBOSE (engine, "removing failed "
  151. "client %s state = %s errors"
  152. " = %d\n",
  153. client->control->name,
  154. jack_client_state_name (client),
  155. client->error);
  156. jack_remove_client (engine,
  157. (jack_client_internal_t *)
  158. node->data);
  159. } else {
  160. VERBOSE (engine, "client failure: "
  161. "client %s state = %s errors"
  162. " = %d\n",
  163. client->control->name,
  164. jack_client_state_name (client),
  165. client->error);
  166. jack_zombify_client (engine,
  167. (jack_client_internal_t *)
  168. node->data);
  169. client->error = 0;
  170. }
  171. need_sort = TRUE;
  172. }
  173. node = tmp;
  174. }
  175. if (need_sort) {
  176. jack_sort_graph (engine);
  177. }
  178. jack_engine_reset_rolling_usecs (engine);
  179. }
  180. static int
  181. jack_load_client (jack_engine_t *engine, jack_client_internal_t *client,
  182. const char *so_name)
  183. {
  184. const char *errstr;
  185. char path_to_so[PATH_MAX+1];
  186. snprintf (path_to_so, sizeof (path_to_so), ADDON_DIR "/%s.so", so_name);
  187. client->handle = dlopen (path_to_so, RTLD_NOW|RTLD_GLOBAL);
  188. if (client->handle == 0) {
  189. if ((errstr = dlerror ()) != 0) {
  190. jack_error ("%s", errstr);
  191. } else {
  192. jack_error ("bizarre error loading %s", so_name);
  193. }
  194. return -1;
  195. }
  196. client->initialize = dlsym (client->handle, "jack_initialize");
  197. if ((errstr = dlerror ()) != 0) {
  198. jack_error ("%s has no initialize() function\n", so_name);
  199. dlclose (client->handle);
  200. client->handle = 0;
  201. return -1;
  202. }
  203. client->finish = (void (*)(void *)) dlsym (client->handle,
  204. "jack_finish");
  205. if ((errstr = dlerror ()) != 0) {
  206. jack_error ("%s has no finish() function", so_name);
  207. dlclose (client->handle);
  208. client->handle = 0;
  209. return -1;
  210. }
  211. return 0;
  212. }
  213. static void
  214. jack_client_unload (jack_client_internal_t *client)
  215. {
  216. if (client->handle) {
  217. if (client->finish) {
  218. client->finish (client->control->process_arg);
  219. }
  220. dlclose (client->handle);
  221. }
  222. }
  223. static jack_client_internal_t *
  224. jack_client_by_name (jack_engine_t *engine, const char *name)
  225. {
  226. jack_client_internal_t *client = NULL;
  227. JSList *node;
  228. jack_lock_graph (engine);
  229. for (node = engine->clients; node; node = jack_slist_next (node)) {
  230. if (strcmp ((const char *) ((jack_client_internal_t *)
  231. node->data)->control->name,
  232. name) == 0) {
  233. client = (jack_client_internal_t *) node->data;
  234. break;
  235. }
  236. }
  237. jack_unlock_graph (engine);
  238. return client;
  239. }
  240. static jack_client_id_t
  241. jack_client_id_by_name (jack_engine_t *engine, const char *name)
  242. {
  243. jack_client_id_t id = 0; /* NULL client ID */
  244. JSList *node;
  245. jack_lock_graph (engine);
  246. for (node = engine->clients; node; node = jack_slist_next (node)) {
  247. if (strcmp ((const char *) ((jack_client_internal_t *)
  248. node->data)->control->name,
  249. name) == 0) {
  250. jack_client_internal_t *client =
  251. (jack_client_internal_t *) node->data;
  252. id = client->control->id;
  253. break;
  254. }
  255. }
  256. jack_unlock_graph (engine);
  257. return id;
  258. }
  259. jack_client_internal_t *
  260. jack_client_internal_by_id (jack_engine_t *engine, jack_client_id_t id)
  261. {
  262. jack_client_internal_t *client = NULL;
  263. JSList *node;
  264. /* call tree ***MUST HOLD*** the graph lock */
  265. for (node = engine->clients; node; node = jack_slist_next (node)) {
  266. if (((jack_client_internal_t *) node->data)->control->id
  267. == id) {
  268. client = (jack_client_internal_t *) node->data;
  269. break;
  270. }
  271. }
  272. return client;
  273. }
  274. /* generate a unique client name
  275. *
  276. * returns 0 if successful, updates name in place
  277. */
  278. static inline int
  279. jack_generate_unique_name (jack_engine_t *engine, char *name)
  280. {
  281. int tens, ones;
  282. int length = strlen (name);
  283. if (length > JACK_CLIENT_NAME_SIZE - 4) {
  284. jack_error ("%s exists and is too long to make unique", name);
  285. return 1; /* failure */
  286. }
  287. /* generate a unique name by appending "-01".."-99" */
  288. name[length++] = '-';
  289. tens = length++;
  290. ones = length++;
  291. name[tens] = '0';
  292. name[ones] = '1';
  293. name[length] = '\0';
  294. while (jack_client_by_name (engine, name)) {
  295. if (name[ones] == '9') {
  296. if (name[tens] == '9') {
  297. jack_error ("client %s has 99 extra"
  298. " instances already", name);
  299. return 1; /* give up */
  300. }
  301. name[tens]++;
  302. name[ones] = '0';
  303. } else {
  304. name[ones]++;
  305. }
  306. }
  307. return 0;
  308. }
  309. static int
  310. jack_client_name_invalid (jack_engine_t *engine, char *name,
  311. jack_options_t options, jack_status_t *status)
  312. {
  313. /* Since this is always called from the server thread, no
  314. * other new client will be created at the same time. So,
  315. * testing a name for uniqueness is valid here. When called
  316. * from jack_engine_load_driver() this is not strictly true,
  317. * but that seems to be adequately serialized due to engine
  318. * startup. There are no other clients at that point, anyway.
  319. */
  320. if (jack_client_by_name (engine, name)) {
  321. *status |= JackNameNotUnique;
  322. if (options & JackUseExactName) {
  323. jack_error ("cannot create new client; %s already"
  324. " exists", name);
  325. *status |= JackFailure;
  326. return TRUE;
  327. }
  328. if (jack_generate_unique_name(engine, name)) {
  329. *status |= JackFailure;
  330. return TRUE;
  331. }
  332. }
  333. return FALSE;
  334. }
  335. /* Set up the engine's client internal and control structures for both
  336. * internal and external clients. */
  337. static jack_client_internal_t *
  338. jack_setup_client_control (jack_engine_t *engine, int fd,
  339. ClientType type, const char *name)
  340. {
  341. jack_client_internal_t *client;
  342. client = (jack_client_internal_t *)
  343. malloc (sizeof (jack_client_internal_t));
  344. client->request_fd = fd;
  345. client->event_fd = -1;
  346. client->ports = 0;
  347. client->truefeeds = 0;
  348. client->sortfeeds = 0;
  349. client->execution_order = UINT_MAX;
  350. client->next_client = NULL;
  351. client->handle = NULL;
  352. client->finish = NULL;
  353. client->error = 0;
  354. if (type != ClientExternal) {
  355. client->control = (jack_client_control_t *)
  356. malloc (sizeof (jack_client_control_t));
  357. } else {
  358. if (jack_shmalloc (sizeof (jack_client_control_t),
  359. &client->control_shm)) {
  360. jack_error ("cannot create client control block for %s",
  361. name);
  362. free (client);
  363. return 0;
  364. }
  365. if (jack_attach_shm (&client->control_shm)) {
  366. jack_error ("cannot attach to client control block "
  367. "for %s (%s)", name, strerror (errno));
  368. jack_destroy_shm (&client->control_shm);
  369. free (client);
  370. return 0;
  371. }
  372. client->control = (jack_client_control_t *)
  373. jack_shm_addr (&client->control_shm);
  374. }
  375. client->control->type = type;
  376. client->control->active = 0;
  377. client->control->dead = FALSE;
  378. client->control->timed_out = 0;
  379. client->control->id = engine->next_client_id++;
  380. strcpy ((char *) client->control->name, name);
  381. client->subgraph_start_fd = -1;
  382. client->subgraph_wait_fd = -1;
  383. client->control->process = NULL;
  384. client->control->process_arg = NULL;
  385. client->control->bufsize = NULL;
  386. client->control->bufsize_arg = NULL;
  387. client->control->srate = NULL;
  388. client->control->srate_arg = NULL;
  389. client->control->xrun = NULL;
  390. client->control->xrun_arg = NULL;
  391. client->control->port_register = NULL;
  392. client->control->port_register_arg = NULL;
  393. client->control->graph_order = NULL;
  394. client->control->graph_order_arg = NULL;
  395. jack_transport_client_new (client);
  396. #ifdef JACK_USE_MACH_THREADS
  397. /* specific resources for server/client real-time thread
  398. * communication */
  399. allocate_mach_serverport(engine, client);
  400. client->running = FALSE;
  401. #endif
  402. return client;
  403. }
  404. /* set up all types of clients */
  405. static jack_client_internal_t *
  406. setup_client (jack_engine_t *engine, ClientType type, char *name,
  407. jack_options_t options, jack_status_t *status, int client_fd,
  408. const char *object_path, const char *object_data)
  409. {
  410. /* called with the request_lock */
  411. jack_client_internal_t *client;
  412. /* validate client name, generate a unique one if appropriate */
  413. if (jack_client_name_invalid (engine, name, options, status))
  414. return NULL;
  415. /* create a client struct for this name */
  416. if ((client = jack_setup_client_control (engine, client_fd,
  417. type, name)) == NULL) {
  418. *status |= (JackFailure|JackInitFailure);
  419. jack_error ("cannot create new client object");
  420. return NULL;
  421. }
  422. /* only for internal clients, driver is already loaded */
  423. if (type == ClientInternal) {
  424. if (jack_load_client (engine, client, object_path)) {
  425. jack_error ("cannot dynamically load client from"
  426. " \"%s\"", object_path);
  427. jack_client_delete (engine, client);
  428. *status |= (JackFailure|JackLoadFailure);
  429. return NULL;
  430. }
  431. }
  432. VERBOSE (engine, "new client: %s, id = %" PRIu32
  433. " type %d @ %p fd = %d\n",
  434. client->control->name, client->control->id,
  435. type, client->control, client_fd);
  436. if (jack_client_is_internal(client)) {
  437. /* Set up the pointers necessary for the request
  438. * system to work. The client is in the same address
  439. * space */
  440. client->control->deliver_request = internal_client_request;
  441. client->control->deliver_arg = engine;
  442. }
  443. /* add new client to the clients list */
  444. jack_lock_graph (engine);
  445. engine->clients = jack_slist_prepend (engine->clients, client);
  446. jack_engine_reset_rolling_usecs (engine);
  447. if (jack_client_is_internal(client)) {
  448. /* Internal clients need to make regular JACK API
  449. * calls, which need a jack_client_t structure.
  450. * Create one here.
  451. */
  452. client->control->private_client =
  453. jack_client_alloc_internal (client->control, engine);
  454. jack_unlock_graph (engine);
  455. /* Call its initialization function. This function
  456. * may make requests of its own, so we temporarily
  457. * release and then reacquire the request_lock. */
  458. if (client->control->type == ClientInternal) {
  459. pthread_mutex_unlock (&engine->request_lock);
  460. if (client->initialize (client->control->private_client,
  461. object_data)) {
  462. /* failed: clean up client data */
  463. VERBOSE (engine,
  464. "%s jack_initialize() failed!\n",
  465. client->control->name);
  466. jack_lock_graph (engine);
  467. jack_remove_client (engine, client);
  468. jack_unlock_graph (engine);
  469. *status |= (JackFailure|JackInitFailure);
  470. client = NULL;
  471. //JOQ: not clear that all allocated
  472. //storage has been cleaned up properly.
  473. }
  474. pthread_mutex_lock (&engine->request_lock);
  475. }
  476. } else { /* external client */
  477. if (engine->pfd_max >= engine->pfd_size) {
  478. engine->pfd = (struct pollfd *)
  479. realloc (engine->pfd, sizeof (struct pollfd)
  480. * (engine->pfd_size + 16));
  481. engine->pfd_size += 16;
  482. }
  483. engine->pfd[engine->pfd_max].fd = client->request_fd;
  484. engine->pfd[engine->pfd_max].events =
  485. POLLIN|POLLPRI|POLLERR|POLLHUP|POLLNVAL;
  486. engine->pfd_max++;
  487. jack_unlock_graph (engine);
  488. }
  489. return client;
  490. }
  491. jack_client_internal_t *
  492. jack_create_driver_client (jack_engine_t *engine, char *name)
  493. {
  494. jack_client_connect_request_t req;
  495. jack_status_t status;
  496. jack_client_internal_t *client;
  497. snprintf (req.name, sizeof (req.name), "%s", name);
  498. pthread_mutex_lock (&engine->request_lock);
  499. client = setup_client (engine, ClientDriver, name, JackUseExactName,
  500. &status, -1, NULL, NULL);
  501. pthread_mutex_unlock (&engine->request_lock);
  502. return client;
  503. }
  504. static jack_status_t
  505. handle_unload_client (jack_engine_t *engine, jack_client_id_t id)
  506. {
  507. /* called *without* the request_lock */
  508. jack_client_internal_t *client;
  509. jack_status_t status = (JackNoSuchClient|JackFailure);
  510. jack_lock_graph (engine);
  511. if ((client = jack_client_internal_by_id (engine, id))) {
  512. VERBOSE (engine, "unloading client \"%s\"\n",
  513. client->control->name);
  514. jack_remove_client (engine, client);
  515. status = 0;
  516. }
  517. jack_unlock_graph (engine);
  518. return status;
  519. }
  520. int
  521. jack_client_create (jack_engine_t *engine, int client_fd)
  522. {
  523. /* called *without* the request_lock */
  524. jack_client_internal_t *client;
  525. jack_client_connect_request_t req;
  526. jack_client_connect_result_t res;
  527. ssize_t nbytes;
  528. res.status = 0;
  529. nbytes = read (client_fd, &req, sizeof (req));
  530. if (nbytes == 0) { /* EOF? */
  531. jack_error ("cannot read connection request from client");
  532. return -1;
  533. }
  534. /* First verify protocol version (first field of request), if
  535. * present, then make sure request has the expected length. */
  536. if ((nbytes < sizeof (req.protocol_v))
  537. || (req.protocol_v != jack_protocol_version)
  538. || (nbytes != sizeof (req))) {
  539. /* JACK protocol incompatibility */
  540. res.status |= (JackFailure|JackVersionError);
  541. jack_error ("JACK protocol mismatch (%d vs %d)", req.protocol_v, jack_protocol_version);
  542. if (write (client_fd, &res, sizeof (res)) != sizeof (res)) {
  543. jack_error ("cannot write client connection response");
  544. }
  545. return -1;
  546. }
  547. if (!req.load) { /* internal client close? */
  548. int rc = -1;
  549. jack_client_id_t id;
  550. if ((id = jack_client_id_by_name(engine, req.name))) {
  551. rc = handle_unload_client (engine, id);
  552. }
  553. /* close does not send a reply */
  554. return rc;
  555. }
  556. pthread_mutex_lock (&engine->request_lock);
  557. client = setup_client (engine, req.type, req.name,
  558. req.options, &res.status, client_fd,
  559. req.object_path, req.object_data);
  560. pthread_mutex_unlock (&engine->request_lock);
  561. if (client == NULL) {
  562. res.status |= JackFailure; /* just making sure */
  563. return -1;
  564. }
  565. res.client_shm = client->control_shm;
  566. res.engine_shm = engine->control_shm;
  567. res.realtime = engine->control->real_time;
  568. res.realtime_priority = engine->rtpriority - 1;
  569. strncpy (res.name, req.name, sizeof(res.name));
  570. #ifdef JACK_USE_MACH_THREADS
  571. /* Mach port number for server/client communication */
  572. res.portnum = client->portnum;
  573. #endif
  574. if (jack_client_is_internal(client)) {
  575. res.client_control = client->control;
  576. res.engine_control = engine->control;
  577. } else {
  578. strcpy (res.fifo_prefix, engine->fifo_prefix);
  579. }
  580. if (write (client_fd, &res, sizeof (res)) != sizeof (res)) {
  581. jack_error ("cannot write connection response to client");
  582. jack_client_delete (engine, client);
  583. return -1;
  584. }
  585. if (jack_client_is_internal (client)) {
  586. close (client_fd);
  587. }
  588. return 0;
  589. }
  590. int
  591. jack_client_activate (jack_engine_t *engine, jack_client_id_t id)
  592. {
  593. jack_client_internal_t *client;
  594. JSList *node;
  595. int ret = -1;
  596. jack_lock_graph (engine);
  597. for (node = engine->clients; node; node = jack_slist_next (node)) {
  598. if (((jack_client_internal_t *) node->data)->control->id
  599. == id) {
  600. client = (jack_client_internal_t *) node->data;
  601. client->control->active = TRUE;
  602. jack_transport_activate(engine, client);
  603. /* we call this to make sure the FIFO is
  604. * built+ready by the time the client needs
  605. * it. we don't care about the return value at
  606. * this point.
  607. */
  608. jack_get_fifo_fd (engine,
  609. ++engine->external_client_cnt);
  610. jack_sort_graph (engine);
  611. ret = 0;
  612. break;
  613. }
  614. }
  615. jack_unlock_graph (engine);
  616. return ret;
  617. }
  618. int
  619. jack_client_deactivate (jack_engine_t *engine, jack_client_id_t id)
  620. {
  621. JSList *node;
  622. int ret = -1;
  623. jack_lock_graph (engine);
  624. for (node = engine->clients; node; node = jack_slist_next (node)) {
  625. jack_client_internal_t *client =
  626. (jack_client_internal_t *) node->data;
  627. if (client->control->id == id) {
  628. JSList *portnode;
  629. jack_port_internal_t *port;
  630. for (portnode = client->ports; portnode;
  631. portnode = jack_slist_next (portnode)) {
  632. port = (jack_port_internal_t *) portnode->data;
  633. jack_port_clear_connections (engine, port);
  634. }
  635. ret = jack_client_do_deactivate (engine, client, TRUE);
  636. break;
  637. }
  638. }
  639. jack_unlock_graph (engine);
  640. return ret;
  641. }
  642. int
  643. jack_client_disconnect (jack_engine_t *engine, int fd)
  644. {
  645. jack_client_internal_t *client = 0;
  646. JSList *node;
  647. #ifndef DEFER_CLIENT_REMOVE_TO_AUDIO_THREAD
  648. jack_lock_graph (engine);
  649. for (node = engine->clients; node; node = jack_slist_next (node)) {
  650. if (jack_client_is_internal((jack_client_internal_t *)
  651. node->data)) {
  652. continue;
  653. }
  654. if (((jack_client_internal_t *) node->data)->request_fd == fd) {
  655. client = (jack_client_internal_t *) node->data;
  656. break;
  657. }
  658. }
  659. if (client) {
  660. VERBOSE (engine, "removing disconnected client %s state = "
  661. "%s errors = %d\n", client->control->name,
  662. jack_client_state_name (client),
  663. client->error);
  664. jack_remove_client(engine, client);
  665. jack_sort_graph (engine);
  666. }
  667. jack_unlock_graph (engine);
  668. #else /* DEFER_CLIENT_REMOVE_TO_AUDIO_THREAD */
  669. jack_lock_graph (engine);
  670. for (node = engine->clients; node; node = jack_slist_next (node)) {
  671. if (jack_client_is_internal((jack_client_internal_t *)
  672. node->data)) {
  673. continue;
  674. }
  675. if (((jack_client_internal_t *) node->data)->request_fd == fd) {
  676. client = (jack_client_internal_t *) node->data;
  677. if (client->error < JACK_ERROR_WITH_SOCKETS) {
  678. client->error += JACK_ERROR_WITH_SOCKETS;
  679. }
  680. break;
  681. }
  682. }
  683. jack_unlock_graph (engine);
  684. #endif /* DEFER_CLIENT_REMOVE_TO_AUDIO_THREAD */
  685. return 0;
  686. }
  687. void
  688. jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client)
  689. {
  690. if (jack_client_is_internal (client)) {
  691. jack_client_unload (client);
  692. free (client->control->private_client);
  693. free ((void *) client->control);
  694. } else {
  695. /* release the client segment, mark it for
  696. destruction, and free up the shm registry
  697. information so that it can be reused.
  698. */
  699. jack_release_shm (&client->control_shm);
  700. jack_destroy_shm (&client->control_shm);
  701. }
  702. free (client);
  703. }
  704. void
  705. jack_intclient_handle_request (jack_engine_t *engine, jack_request_t *req)
  706. {
  707. jack_client_internal_t *client;
  708. req->status = 0;
  709. if ((client = jack_client_by_name (engine, req->x.intclient.name))) {
  710. req->x.intclient.id = client->control->id;
  711. } else {
  712. req->status |= (JackNoSuchClient|JackFailure);
  713. }
  714. }
  715. void
  716. jack_intclient_load_request (jack_engine_t *engine, jack_request_t *req)
  717. {
  718. /* called with the request_lock */
  719. jack_client_internal_t *client;
  720. jack_status_t status = 0;
  721. VERBOSE (engine, "load internal client %s from %s, init `%s', "
  722. "options: 0x%x\n", req->x.intclient.name,
  723. req->x.intclient.path, req->x.intclient.init,
  724. req->x.intclient.options);
  725. client = setup_client (engine, ClientInternal, req->x.intclient.name,
  726. req->x.intclient.options, &status, -1,
  727. req->x.intclient.path, req->x.intclient.init);
  728. if (client == NULL) {
  729. status |= JackFailure; /* just making sure */
  730. req->x.intclient.id = 0;
  731. VERBOSE (engine, "load failed, status = 0x%x\n", status);
  732. } else {
  733. req->x.intclient.id = client->control->id;
  734. }
  735. req->status = status;
  736. }
  737. void
  738. jack_intclient_name_request (jack_engine_t *engine, jack_request_t *req)
  739. {
  740. jack_client_internal_t *client;
  741. jack_lock_graph (engine);
  742. if ((client = jack_client_internal_by_id (engine,
  743. req->x.intclient.id))) {
  744. strncpy ((char *) req->x.intclient.name,
  745. (char *) client->control->name,
  746. sizeof (req->x.intclient.name));
  747. req->status = 0;
  748. } else {
  749. req->status = (JackNoSuchClient|JackFailure);
  750. }
  751. jack_unlock_graph (engine);
  752. }
  753. void
  754. jack_intclient_unload_request (jack_engine_t *engine, jack_request_t *req)
  755. {
  756. /* Called with the request_lock, but we need to call
  757. * handle_unload_client() *without* it. */
  758. if (req->x.intclient.id) {
  759. pthread_mutex_unlock (&engine->request_lock);
  760. req->status =
  761. handle_unload_client (engine, req->x.intclient.id);
  762. pthread_mutex_lock (&engine->request_lock);
  763. } else {
  764. VERBOSE (engine, "invalid unload request\n");
  765. req->status = JackFailure;
  766. }
  767. }