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.

1085 lines
28KB

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