netjack changes from torben (packet loss handling leads to "dummy" backend-like behav...
[jack.git] / jackd / clientengine.c
blob4597c89337913be36f0c0d9177e706d47b197dd6
1 /* -*- mode: c; c-file-style: "bsd"; -*- */
2 /*
3 * Client creation and destruction interfaces for JACK engine.
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.
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.
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.
24 #include <config.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <string.h>
31 #include <jack/internal.h>
32 #include <jack/engine.h>
33 #include <jack/messagebuffer.h>
34 #include <jack/version.h>
35 #include <sysdeps/poll.h>
36 #include <sysdeps/ipc.h>
38 #include "clientengine.h"
39 #include "transengine.h"
41 #include "libjack/local.h"
43 static void
44 jack_client_disconnect_ports (jack_engine_t *engine,
45 jack_client_internal_t *client)
47 JSList *node;
48 jack_port_internal_t *port;
50 /* call tree **** MUST HOLD *** engine->client_lock */
52 for (node = client->ports; node; node = jack_slist_next (node)) {
53 port = (jack_port_internal_t *) node->data;
54 jack_port_clear_connections (engine, port);
55 jack_port_registration_notify (engine, port->shared->id, FALSE);
56 jack_port_release (engine, port);
59 jack_slist_free (client->ports);
60 jack_slist_free (client->truefeeds);
61 jack_slist_free (client->sortfeeds);
62 client->truefeeds = 0;
63 client->sortfeeds = 0;
64 client->ports = 0;
67 int
68 jack_client_do_deactivate (jack_engine_t *engine,
69 jack_client_internal_t *client, int sort_graph)
71 /* caller must hold engine->client_lock and must have checked for and/or
72 * cleared all connections held by client.
74 VERBOSE(engine,"+++ deactivate %s", client->control->name);
76 client->control->active = FALSE;
78 jack_transport_client_exit (engine, client);
80 if (!jack_client_is_internal (client) &&
81 engine->external_client_cnt > 0) {
82 engine->external_client_cnt--;
85 if (sort_graph) {
86 jack_sort_graph (engine);
88 return 0;
91 static void
92 jack_zombify_client (jack_engine_t *engine, jack_client_internal_t *client)
94 VERBOSE (engine, "removing client \"%s\" from the processing chain",
95 client->control->name);
97 /* caller must hold the client_lock */
99 /* this stops jack_deliver_event() from contacing this client */
101 client->control->dead = TRUE;
103 jack_client_disconnect_ports (engine, client);
104 jack_client_do_deactivate (engine, client, FALSE);
107 static void
108 jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)
110 JSList *node;
112 /* caller must write-hold the client lock */
114 VERBOSE (engine, "removing client \"%s\"", client->control->name);
116 /* if its not already a zombie, make it so */
118 if (!client->control->dead) {
119 jack_zombify_client (engine, client);
122 if (client->control->type == ClientExternal) {
124 /* try to force the server thread to return from poll */
126 close (client->event_fd);
127 close (client->request_fd);
130 for (node = engine->clients; node; node = jack_slist_next (node)) {
131 if (((jack_client_internal_t *) node->data)->control->id
132 == client->control->id) {
133 engine->clients =
134 jack_slist_remove_link (engine->clients, node);
135 jack_slist_free_1 (node);
136 break;
140 jack_client_delete (engine, client);
142 /* ignore the driver, which counts as a client. */
144 if (engine->temporary && (jack_slist_length(engine->clients) <= 1)) {
145 exit (0);
149 static void
150 jack_wake_server_thread (jack_engine_t* engine)
152 char c = 0;
153 /* we don't actually care if this fails */
154 VERBOSE (engine, "waking server thread");
155 write (engine->cleanup_fifo[1], &c, 1);
158 void
159 jack_check_clients (jack_engine_t* engine, int with_timeout_check)
161 /* CALLER MUST HOLD graph read lock */
163 JSList* node;
164 jack_client_internal_t* client;
165 int errs = 0;
167 for (node = engine->clients; node; node = jack_slist_next (node)) {
169 client = (jack_client_internal_t *) node->data;
171 if (client->error) {
172 errs++;
173 continue;
176 if (with_timeout_check) {
178 /* we can only consider the timeout a client error if
179 * it actually woke up. its possible that the kernel
180 * scheduler screwed us up and never woke up the
181 * client in time. sigh.
184 VERBOSE (engine, "checking client %s: awake at %" PRIu64 " finished at %" PRIu64,
185 client->control->name,
186 client->control->awake_at,
187 client->control->finished_at);
189 if (client->control->awake_at > 0) {
190 if (client->control->finished_at == 0) {
191 client->control->timed_out++;
192 client->error++;
193 VERBOSE (engine, "client %s has timed out", client->control->name);
199 if (errs) {
200 jack_lock_problems (engine);
201 engine->problems++;
202 jack_unlock_problems (engine);
203 jack_wake_server_thread (engine);
207 void
208 jack_remove_clients (jack_engine_t* engine)
210 JSList *tmp, *node;
211 int need_sort = FALSE;
212 jack_client_internal_t *client;
214 /* CALLER MUST HOLD GRAPH LOCK */
216 VERBOSE (engine, "++ Removing failed clients ...");
218 /* remove all dead clients */
220 for (node = engine->clients; node; ) {
222 tmp = jack_slist_next (node);
224 client = (jack_client_internal_t *) node->data;
226 VERBOSE(engine, "client %s error status %d", client->control->name, client->error);
228 if (client->error) {
230 /* if we have a communication problem with the
231 client, remove it. otherwise, turn it into
232 a zombie. the client will/should realize
233 this and will close its sockets. then
234 we'll end up back here again and will
235 finally remove the client.
237 if (client->error >= JACK_ERROR_WITH_SOCKETS) {
238 VERBOSE (engine, "removing failed "
239 "client %s state = %s errors"
240 " = %d",
241 client->control->name,
242 jack_client_state_name (client),
243 client->error);
244 jack_remove_client (engine,
245 (jack_client_internal_t *)
246 node->data);
247 } else {
248 VERBOSE (engine, "client failure: "
249 "client %s state = %s errors"
250 " = %d",
251 client->control->name,
252 jack_client_state_name (client),
253 client->error);
254 if (!engine->nozombies) {
255 jack_zombify_client (engine,
256 (jack_client_internal_t *)
257 node->data);
258 client->error = 0;
262 need_sort = TRUE;
265 node = tmp;
268 if (need_sort) {
269 jack_sort_graph (engine);
272 jack_engine_reset_rolling_usecs (engine);
274 VERBOSE (engine, "-- Removing failed clients ...");
277 static int
278 jack_load_client (jack_engine_t *engine, jack_client_internal_t *client,
279 const char *so_name)
281 const char *errstr;
282 char path_to_so[PATH_MAX+1];
284 snprintf (path_to_so, sizeof (path_to_so), ADDON_DIR "/%s.so", so_name);
285 client->handle = dlopen (path_to_so, RTLD_NOW|RTLD_GLOBAL);
287 if (client->handle == 0) {
288 if ((errstr = dlerror ()) != 0) {
289 jack_error ("%s", errstr);
290 } else {
291 jack_error ("bizarre error loading %s", so_name);
293 return -1;
296 client->initialize = dlsym (client->handle, "jack_initialize");
298 if ((errstr = dlerror ()) != 0) {
299 jack_error ("%s has no initialize() function\n", so_name);
300 dlclose (client->handle);
301 client->handle = 0;
302 return -1;
305 client->finish = (void (*)(void *)) dlsym (client->handle,
306 "jack_finish");
308 if ((errstr = dlerror ()) != 0) {
309 jack_error ("%s has no finish() function", so_name);
310 dlclose (client->handle);
311 client->handle = 0;
312 return -1;
315 return 0;
318 static void
319 jack_client_unload (jack_client_internal_t *client)
321 if (client->handle) {
322 if (client->finish) {
323 client->finish (client->private_client->process_arg);
325 dlclose (client->handle);
329 static jack_client_internal_t *
330 jack_client_by_name (jack_engine_t *engine, const char *name)
332 jack_client_internal_t *client = NULL;
333 JSList *node;
335 jack_rdlock_graph (engine);
337 for (node = engine->clients; node; node = jack_slist_next (node)) {
338 if (strcmp ((const char *) ((jack_client_internal_t *)
339 node->data)->control->name,
340 name) == 0) {
341 client = (jack_client_internal_t *) node->data;
342 break;
346 jack_unlock_graph (engine);
347 return client;
350 static jack_client_id_t
351 jack_client_id_by_name (jack_engine_t *engine, const char *name)
353 jack_client_id_t id = 0; /* NULL client ID */
354 JSList *node;
356 jack_rdlock_graph (engine);
358 for (node = engine->clients; node; node = jack_slist_next (node)) {
359 if (strcmp ((const char *) ((jack_client_internal_t *)
360 node->data)->control->name,
361 name) == 0) {
362 jack_client_internal_t *client =
363 (jack_client_internal_t *) node->data;
364 id = client->control->id;
365 break;
369 jack_unlock_graph (engine);
370 return id;
373 jack_client_internal_t *
374 jack_client_internal_by_id (jack_engine_t *engine, jack_client_id_t id)
376 jack_client_internal_t *client = NULL;
377 JSList *node;
379 /* call tree ***MUST HOLD*** the graph lock */
381 for (node = engine->clients; node; node = jack_slist_next (node)) {
383 if (((jack_client_internal_t *) node->data)->control->id
384 == id) {
385 client = (jack_client_internal_t *) node->data;
386 break;
390 return client;
393 /* generate a unique client name
395 * returns 0 if successful, updates name in place
397 static inline int
398 jack_generate_unique_name (jack_engine_t *engine, char *name)
400 int tens, ones;
401 int length = strlen (name);
403 if (length > JACK_CLIENT_NAME_SIZE - 4) {
404 jack_error ("%s exists and is too long to make unique", name);
405 return 1; /* failure */
408 /* generate a unique name by appending "-01".."-99" */
409 name[length++] = '-';
410 tens = length++;
411 ones = length++;
412 name[tens] = '0';
413 name[ones] = '1';
414 name[length] = '\0';
415 while (jack_client_by_name (engine, name)) {
416 if (name[ones] == '9') {
417 if (name[tens] == '9') {
418 jack_error ("client %s has 99 extra"
419 " instances already", name);
420 return 1; /* give up */
422 name[tens]++;
423 name[ones] = '0';
424 } else {
425 name[ones]++;
428 return 0;
431 static int
432 jack_client_name_invalid (jack_engine_t *engine, char *name,
433 jack_options_t options, jack_status_t *status)
435 /* Since this is always called from the server thread, no
436 * other new client will be created at the same time. So,
437 * testing a name for uniqueness is valid here. When called
438 * from jack_engine_load_driver() this is not strictly true,
439 * but that seems to be adequately serialized due to engine
440 * startup. There are no other clients at that point, anyway.
443 if (jack_client_by_name (engine, name)) {
445 *status |= JackNameNotUnique;
447 if (options & JackUseExactName) {
448 jack_error ("cannot create new client; %s already"
449 " exists", name);
450 *status |= JackFailure;
451 return TRUE;
454 if (jack_generate_unique_name(engine, name)) {
455 *status |= JackFailure;
456 return TRUE;
460 return FALSE;
463 /* Set up the engine's client internal and control structures for both
464 * internal and external clients. */
465 static jack_client_internal_t *
466 jack_setup_client_control (jack_engine_t *engine, int fd,
467 ClientType type, const char *name)
469 jack_client_internal_t *client;
471 client = (jack_client_internal_t *)
472 malloc (sizeof (jack_client_internal_t));
474 client->request_fd = fd;
475 client->event_fd = -1;
476 client->ports = 0;
477 client->truefeeds = 0;
478 client->sortfeeds = 0;
479 client->execution_order = UINT_MAX;
480 client->next_client = NULL;
481 client->handle = NULL;
482 client->finish = NULL;
483 client->error = 0;
485 if (type != ClientExternal) {
487 client->control = (jack_client_control_t *)
488 malloc (sizeof (jack_client_control_t));
490 } else {
492 if (jack_shmalloc (sizeof (jack_client_control_t),
493 &client->control_shm)) {
494 jack_error ("cannot create client control block for %s",
495 name);
496 free (client);
497 return 0;
500 if (jack_attach_shm (&client->control_shm)) {
501 jack_error ("cannot attach to client control block "
502 "for %s (%s)", name, strerror (errno));
503 jack_destroy_shm (&client->control_shm);
504 free (client);
505 return 0;
508 client->control = (jack_client_control_t *)
509 jack_shm_addr (&client->control_shm);
512 client->control->type = type;
513 client->control->active = 0;
514 client->control->dead = FALSE;
515 client->control->timed_out = 0;
516 client->control->id = engine->next_client_id++;
517 strcpy ((char *) client->control->name, name);
518 client->subgraph_start_fd = -1;
519 client->subgraph_wait_fd = -1;
521 client->control->process_cbset = FALSE;
522 client->control->bufsize_cbset = FALSE;
523 client->control->srate_cbset = FALSE;
524 client->control->xrun_cbset = FALSE;
525 client->control->port_register_cbset = FALSE;
526 client->control->port_connect_cbset = FALSE;
527 client->control->graph_order_cbset = FALSE;
528 client->control->client_register_cbset = FALSE;
529 client->control->thread_cb_cbset = FALSE;
531 #if 0
532 if (type != ClientExternal) {
533 client->process = NULL;
534 client->process_arg = NULL;
535 client->bufsize = NULL;
536 client->bufsize_arg = NULL;
537 client->srate = NULL;
538 client->srate_arg = NULL;
539 client->xrun = NULL;
540 client->xrun_arg = NULL;
541 client->port_register = NULL;
542 client->port_register_arg = NULL;
543 client->port_connect = NULL;
544 client->port_connect_arg = NULL;
545 client->graph_order = NULL;
546 client->graph_order_arg = NULL;
547 client->client_register = NULL;
548 client->client_register_arg = NULL;
549 client->thread_cb = NULL;
550 client->thread_cb_arg = NULL;
552 #endif
553 jack_transport_client_new (client);
555 #ifdef JACK_USE_MACH_THREADS
556 /* specific resources for server/client real-time thread
557 * communication */
558 allocate_mach_serverport(engine, client);
559 client->running = FALSE;
560 #endif
562 return client;
565 /* set up all types of clients */
566 static jack_client_internal_t *
567 setup_client (jack_engine_t *engine, ClientType type, char *name,
568 jack_options_t options, jack_status_t *status, int client_fd,
569 const char *object_path, const char *object_data)
571 /* called with the request_lock */
572 jack_client_internal_t *client;
574 /* validate client name, generate a unique one if appropriate */
575 if (jack_client_name_invalid (engine, name, options, status))
576 return NULL;
578 /* create a client struct for this name */
579 if ((client = jack_setup_client_control (engine, client_fd,
580 type, name)) == NULL) {
581 *status |= (JackFailure|JackInitFailure);
582 jack_error ("cannot create new client object");
583 return NULL;
586 /* only for internal clients, driver is already loaded */
587 if (type == ClientInternal) {
588 if (jack_load_client (engine, client, object_path)) {
589 jack_error ("cannot dynamically load client from"
590 " \"%s\"", object_path);
591 jack_client_delete (engine, client);
592 *status |= (JackFailure|JackLoadFailure);
593 return NULL;
597 VERBOSE (engine, "new client: %s, id = %" PRIu32
598 " type %d @ %p fd = %d",
599 client->control->name, client->control->id,
600 type, client->control, client_fd);
602 if (jack_client_is_internal(client)) {
604 // XXX: do i need to lock the graph here ?
605 // i moved this one up in the init process, lets see what happens.
607 /* Internal clients need to make regular JACK API
608 * calls, which need a jack_client_t structure.
609 * Create one here.
611 client->private_client =
612 jack_client_alloc_internal (client->control, engine);
614 /* Set up the pointers necessary for the request
615 * system to work. The client is in the same address
616 * space */
618 client->private_client->deliver_request = internal_client_request;
619 client->private_client->deliver_arg = engine;
622 /* add new client to the clients list */
623 jack_lock_graph (engine);
624 engine->clients = jack_slist_prepend (engine->clients, client);
625 jack_engine_reset_rolling_usecs (engine);
627 if (jack_client_is_internal(client)) {
630 jack_unlock_graph (engine);
632 /* Call its initialization function. This function
633 * may make requests of its own, so we temporarily
634 * release and then reacquire the request_lock. */
635 if (client->control->type == ClientInternal) {
637 pthread_mutex_unlock (&engine->request_lock);
638 if (client->initialize (client->private_client,
639 object_data)) {
641 /* failed: clean up client data */
642 VERBOSE (engine,
643 "%s jack_initialize() failed!",
644 client->control->name);
645 jack_lock_graph (engine);
646 jack_remove_client (engine, client);
647 jack_unlock_graph (engine);
648 *status |= (JackFailure|JackInitFailure);
649 client = NULL;
650 //JOQ: not clear that all allocated
651 //storage has been cleaned up properly.
653 pthread_mutex_lock (&engine->request_lock);
656 } else { /* external client */
658 jack_unlock_graph (engine);
661 return client;
664 jack_client_internal_t *
665 jack_create_driver_client (jack_engine_t *engine, char *name)
667 jack_client_connect_request_t req;
668 jack_status_t status;
669 jack_client_internal_t *client;
671 snprintf (req.name, sizeof (req.name), "%s", name);
673 pthread_mutex_lock (&engine->request_lock);
674 client = setup_client (engine, ClientDriver, name, JackUseExactName,
675 &status, -1, NULL, NULL);
676 pthread_mutex_unlock (&engine->request_lock);
678 return client;
681 static jack_status_t
682 handle_unload_client (jack_engine_t *engine, jack_client_id_t id)
684 /* called *without* the request_lock */
685 jack_client_internal_t *client;
686 jack_status_t status = (JackNoSuchClient|JackFailure);
688 jack_lock_graph (engine);
690 if ((client = jack_client_internal_by_id (engine, id))) {
691 VERBOSE (engine, "unloading client \"%s\"",
692 client->control->name);
693 jack_remove_client (engine, client);
694 status = 0;
697 jack_unlock_graph (engine);
699 return status;
703 jack_client_create (jack_engine_t *engine, int client_fd)
705 /* called *without* the request_lock */
706 jack_client_internal_t *client;
707 jack_client_connect_request_t req;
708 jack_client_connect_result_t res;
709 ssize_t nbytes;
711 res.status = 0;
713 nbytes = read (client_fd, &req, sizeof (req));
715 if (nbytes == 0) { /* EOF? */
716 jack_error ("cannot read connection request from client");
717 return -1;
720 /* First verify protocol version (first field of request), if
721 * present, then make sure request has the expected length. */
722 if ((nbytes < sizeof (req.protocol_v))
723 || (req.protocol_v != jack_protocol_version)
724 || (nbytes != sizeof (req))) {
726 /* JACK protocol incompatibility */
727 res.status |= (JackFailure|JackVersionError);
728 jack_error ("JACK protocol mismatch (%d vs %d)", req.protocol_v, jack_protocol_version);
729 if (write (client_fd, &res, sizeof (res)) != sizeof (res)) {
730 jack_error ("cannot write client connection response");
732 return -1;
735 if (!req.load) { /* internal client close? */
737 int rc = -1;
738 jack_client_id_t id;
740 if ((id = jack_client_id_by_name(engine, req.name))) {
741 rc = handle_unload_client (engine, id);
744 /* close does not send a reply */
745 return rc;
748 pthread_mutex_lock (&engine->request_lock);
749 client = setup_client (engine, req.type, req.name,
750 req.options, &res.status, client_fd,
751 req.object_path, req.object_data);
752 pthread_mutex_unlock (&engine->request_lock);
753 if (client == NULL) {
754 res.status |= JackFailure; /* just making sure */
755 return -1;
757 res.client_shm_index = client->control_shm.index;
758 res.engine_shm_index = engine->control_shm.index;
759 res.realtime = engine->control->real_time;
760 res.realtime_priority = engine->rtpriority - 1;
761 strncpy (res.name, req.name, sizeof(res.name));
763 #ifdef JACK_USE_MACH_THREADS
764 /* Mach port number for server/client communication */
765 res.portnum = client->portnum;
766 #endif
768 if (jack_client_is_internal(client)) {
769 res.client_control = client->control;
770 res.engine_control = engine->control;
771 } else {
772 strcpy (res.fifo_prefix, engine->fifo_prefix);
775 if (write (client_fd, &res, sizeof (res)) != sizeof (res)) {
776 jack_error ("cannot write connection response to client");
777 jack_client_delete (engine, client);
778 return -1;
781 if (jack_client_is_internal (client)) {
782 close (client_fd);
785 jack_client_registration_notify (engine, (const char*) client->control->name, 1);
787 return 0;
791 jack_client_activate (jack_engine_t *engine, jack_client_id_t id)
793 jack_client_internal_t *client;
794 JSList *node;
795 int ret = -1;
797 jack_lock_graph (engine);
799 for (node = engine->clients; node; node = jack_slist_next (node)) {
801 if (((jack_client_internal_t *) node->data)->control->id
802 == id) {
804 client = (jack_client_internal_t *) node->data;
805 client->control->active = TRUE;
807 jack_transport_activate(engine, client);
809 /* we call this to make sure the FIFO is
810 * built+ready by the time the client needs
811 * it. we don't care about the return value at
812 * this point.
815 jack_get_fifo_fd (engine,
816 ++engine->external_client_cnt);
817 jack_sort_graph (engine);
819 ret = 0;
820 break;
824 jack_unlock_graph (engine);
825 return ret;
829 jack_client_deactivate (jack_engine_t *engine, jack_client_id_t id)
831 JSList *node;
832 int ret = -1;
834 jack_lock_graph (engine);
836 for (node = engine->clients; node; node = jack_slist_next (node)) {
838 jack_client_internal_t *client =
839 (jack_client_internal_t *) node->data;
841 if (client->control->id == id) {
843 JSList *portnode;
844 jack_port_internal_t *port;
846 for (portnode = client->ports; portnode;
847 portnode = jack_slist_next (portnode)) {
848 port = (jack_port_internal_t *) portnode->data;
849 jack_port_clear_connections (engine, port);
852 ret = jack_client_do_deactivate (engine, client, TRUE);
853 break;
857 jack_unlock_graph (engine);
859 return ret;
863 jack_mark_client_socket_error (jack_engine_t *engine, int fd)
865 /* CALLER MUST HOLD GRAPH LOCK */
867 jack_client_internal_t *client = 0;
868 JSList *node;
870 for (node = engine->clients; node; node = jack_slist_next (node)) {
872 if (jack_client_is_internal((jack_client_internal_t *)
873 node->data)) {
874 continue;
877 if (((jack_client_internal_t *) node->data)->request_fd == fd) {
878 client = (jack_client_internal_t *) node->data;
879 break;
883 if (client) {
884 VERBOSE (engine, "marking client %s with SOCKET error state = "
885 "%s errors = %d", client->control->name,
886 jack_client_state_name (client),
887 client->error);
888 client->error += JACK_ERROR_WITH_SOCKETS;
891 return 0;
894 void
895 jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client)
897 jack_client_registration_notify (engine, (const char*) client->control->name, 0);
899 if (jack_client_is_internal (client)) {
901 jack_client_unload (client);
902 free (client->private_client);
903 free ((void *) client->control);
905 } else {
907 /* release the client segment, mark it for
908 destruction, and free up the shm registry
909 information so that it can be reused.
912 jack_release_shm (&client->control_shm);
913 jack_destroy_shm (&client->control_shm);
916 free (client);
919 void
920 jack_intclient_handle_request (jack_engine_t *engine, jack_request_t *req)
922 jack_client_internal_t *client;
924 req->status = 0;
925 if ((client = jack_client_by_name (engine, req->x.intclient.name))) {
926 req->x.intclient.id = client->control->id;
927 } else {
928 req->status |= (JackNoSuchClient|JackFailure);
932 void
933 jack_intclient_load_request (jack_engine_t *engine, jack_request_t *req)
935 /* called with the request_lock */
936 jack_client_internal_t *client;
937 jack_status_t status = 0;
939 VERBOSE (engine, "load internal client %s from %s, init `%s', "
940 "options: 0x%x", req->x.intclient.name,
941 req->x.intclient.path, req->x.intclient.init,
942 req->x.intclient.options);
944 client = setup_client (engine, ClientInternal, req->x.intclient.name,
945 req->x.intclient.options, &status, -1,
946 req->x.intclient.path, req->x.intclient.init);
948 if (client == NULL) {
949 status |= JackFailure; /* just making sure */
950 req->x.intclient.id = 0;
951 VERBOSE (engine, "load failed, status = 0x%x", status);
952 } else {
953 req->x.intclient.id = client->control->id;
956 req->status = status;
959 void
960 jack_intclient_name_request (jack_engine_t *engine, jack_request_t *req)
962 jack_client_internal_t *client;
964 jack_rdlock_graph (engine);
965 if ((client = jack_client_internal_by_id (engine,
966 req->x.intclient.id))) {
967 strncpy ((char *) req->x.intclient.name,
968 (char *) client->control->name,
969 sizeof (req->x.intclient.name));
970 req->status = 0;
971 } else {
972 req->status = (JackNoSuchClient|JackFailure);
974 jack_unlock_graph (engine);
977 void
978 jack_intclient_unload_request (jack_engine_t *engine, jack_request_t *req)
980 /* Called with the request_lock, but we need to call
981 * handle_unload_client() *without* it. */
983 if (req->x.intclient.id) {
984 pthread_mutex_unlock (&engine->request_lock);
985 req->status =
986 handle_unload_client (engine, req->x.intclient.id);
987 pthread_mutex_lock (&engine->request_lock);
988 } else {
989 VERBOSE (engine, "invalid unload request");
990 req->status = JackFailure;