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.

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