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.

981 lines
25KB

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