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.

935 lines
23KB

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