1 /* -*- mode: c; c-file-style: "bsd"; -*- */
3 * Client creation and destruction interfaces for JACK engine.
5 * Copyright (C) 2001-2003 Paul Davis
6 * Copyright (C) 2004 Jack O'Quin
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.
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"
44 jack_client_disconnect_ports (jack_engine_t
*engine
,
45 jack_client_internal_t
*client
)
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;
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
--;
86 jack_sort_graph (engine
);
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
);
108 jack_remove_client (jack_engine_t
*engine
, jack_client_internal_t
*client
)
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
) {
134 jack_slist_remove_link (engine
->clients
, node
);
135 jack_slist_free_1 (node
);
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)) {
150 jack_wake_server_thread (jack_engine_t
* engine
)
153 /* we don't actually care if this fails */
154 VERBOSE (engine
, "waking server thread");
155 write (engine
->cleanup_fifo
[1], &c
, 1);
159 jack_check_clients (jack_engine_t
* engine
, int with_timeout_check
)
161 /* CALLER MUST HOLD graph read lock */
164 jack_client_internal_t
* client
;
167 for (node
= engine
->clients
; node
; node
= jack_slist_next (node
)) {
169 client
= (jack_client_internal_t
*) node
->data
;
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
++;
193 VERBOSE (engine
, "client %s has timed out", client
->control
->name
);
200 jack_lock_problems (engine
);
202 jack_unlock_problems (engine
);
203 jack_wake_server_thread (engine
);
208 jack_remove_clients (jack_engine_t
* engine
)
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
);
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"
241 client
->control
->name
,
242 jack_client_state_name (client
),
244 jack_remove_client (engine
,
245 (jack_client_internal_t
*)
248 VERBOSE (engine
, "client failure: "
249 "client %s state = %s errors"
251 client
->control
->name
,
252 jack_client_state_name (client
),
254 if (!engine
->nozombies
) {
255 jack_zombify_client (engine
,
256 (jack_client_internal_t
*)
269 jack_sort_graph (engine
);
272 jack_engine_reset_rolling_usecs (engine
);
274 VERBOSE (engine
, "-- Removing failed clients ...");
278 jack_load_client (jack_engine_t
*engine
, jack_client_internal_t
*client
,
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
);
291 jack_error ("bizarre error loading %s", so_name
);
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
);
305 client
->finish
= (void (*)(void *)) dlsym (client
->handle
,
308 if ((errstr
= dlerror ()) != 0) {
309 jack_error ("%s has no finish() function", so_name
);
310 dlclose (client
->handle
);
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
;
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
,
341 client
= (jack_client_internal_t
*) node
->data
;
346 jack_unlock_graph (engine
);
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 */
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
,
362 jack_client_internal_t
*client
=
363 (jack_client_internal_t
*) node
->data
;
364 id
= client
->control
->id
;
369 jack_unlock_graph (engine
);
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
;
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
385 client
= (jack_client_internal_t
*) node
->data
;
393 /* generate a unique client name
395 * returns 0 if successful, updates name in place
398 jack_generate_unique_name (jack_engine_t
*engine
, char *name
)
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
++] = '-';
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 */
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"
450 *status
|= JackFailure
;
454 if (jack_generate_unique_name(engine
, name
)) {
455 *status
|= JackFailure
;
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;
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
;
485 if (type
!= ClientExternal
) {
487 client
->control
= (jack_client_control_t
*)
488 malloc (sizeof (jack_client_control_t
));
492 if (jack_shmalloc (sizeof (jack_client_control_t
),
493 &client
->control_shm
)) {
494 jack_error ("cannot create client control block for %s",
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
);
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
;
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
;
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
;
553 jack_transport_client_new (client
);
555 #ifdef JACK_USE_MACH_THREADS
556 /* specific resources for server/client real-time thread
558 allocate_mach_serverport(engine
, client
);
559 client
->running
= FALSE
;
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
))
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");
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
);
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.
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
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
,
641 /* failed: clean up client data */
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
);
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
);
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
);
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
);
697 jack_unlock_graph (engine
);
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
;
713 nbytes
= read (client_fd
, &req
, sizeof (req
));
715 if (nbytes
== 0) { /* EOF? */
716 jack_error ("cannot read connection request from client");
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");
735 if (!req
.load
) { /* internal client close? */
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 */
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 */
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
;
768 if (jack_client_is_internal(client
)) {
769 res
.client_control
= client
->control
;
770 res
.engine_control
= engine
->control
;
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
);
781 if (jack_client_is_internal (client
)) {
785 jack_client_registration_notify (engine
, (const char*) client
->control
->name
, 1);
791 jack_client_activate (jack_engine_t
*engine
, jack_client_id_t id
)
793 jack_client_internal_t
*client
;
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
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
815 jack_get_fifo_fd (engine
,
816 ++engine
->external_client_cnt
);
817 jack_sort_graph (engine
);
824 jack_unlock_graph (engine
);
829 jack_client_deactivate (jack_engine_t
*engine
, jack_client_id_t id
)
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
) {
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
);
857 jack_unlock_graph (engine
);
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;
870 for (node
= engine
->clients
; node
; node
= jack_slist_next (node
)) {
872 if (jack_client_is_internal((jack_client_internal_t
*)
877 if (((jack_client_internal_t
*) node
->data
)->request_fd
== fd
) {
878 client
= (jack_client_internal_t
*) node
->data
;
884 VERBOSE (engine
, "marking client %s with SOCKET error state = "
885 "%s errors = %d", client
->control
->name
,
886 jack_client_state_name (client
),
888 client
->error
+= JACK_ERROR_WITH_SOCKETS
;
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
);
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
);
920 jack_intclient_handle_request (jack_engine_t
*engine
, jack_request_t
*req
)
922 jack_client_internal_t
*client
;
925 if ((client
= jack_client_by_name (engine
, req
->x
.intclient
.name
))) {
926 req
->x
.intclient
.id
= client
->control
->id
;
928 req
->status
|= (JackNoSuchClient
|JackFailure
);
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
);
953 req
->x
.intclient
.id
= client
->control
->id
;
956 req
->status
= status
;
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
));
972 req
->status
= (JackNoSuchClient
|JackFailure
);
974 jack_unlock_graph (engine
);
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
);
986 handle_unload_client (engine
, req
->x
.intclient
.id
);
987 pthread_mutex_lock (&engine
->request_lock
);
989 VERBOSE (engine
, "invalid unload request");
990 req
->status
= JackFailure
;