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.

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