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.

934 lines
23KB

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