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.

975 lines
24KB

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