proper cleanup of "temporary" JACK server, by killing the wait thread with SIGUSR2
[jack.git] / jackd / clientengine.c
blob5de971f918069131556a24c81b5fa7a7393ad76c
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>
30 #include <signal.h>
32 #include <jack/internal.h>
33 #include <jack/engine.h>
34 #include <jack/messagebuffer.h>
35 #include <jack/version.h>
36 #include <sysdeps/poll.h>
37 #include <sysdeps/ipc.h>
39 #include "clientengine.h"
40 #include "transengine.h"
42 #include "libjack/local.h"
44 static void
45 jack_client_disconnect_ports (jack_engine_t *engine,
46 jack_client_internal_t *client)
48 JSList *node;
49 jack_port_internal_t *port;
51 /* call tree **** MUST HOLD *** engine->client_lock */
53 for (node = client->ports; node; node = jack_slist_next (node)) {
54 port = (jack_port_internal_t *) node->data;
55 jack_port_clear_connections (engine, port);
56 jack_port_registration_notify (engine, port->shared->id, FALSE);
57 jack_port_release (engine, port);
60 jack_slist_free (client->ports);
61 jack_slist_free (client->truefeeds);
62 jack_slist_free (client->sortfeeds);
63 client->truefeeds = 0;
64 client->sortfeeds = 0;
65 client->ports = 0;
68 int
69 jack_client_do_deactivate (jack_engine_t *engine,
70 jack_client_internal_t *client, int sort_graph)
72 /* caller must hold engine->client_lock and must have checked for and/or
73 * cleared all connections held by client.
75 VERBOSE(engine,"+++ deactivate %s", client->control->name);
77 client->control->active = FALSE;
79 jack_transport_client_exit (engine, client);
81 if (!jack_client_is_internal (client) &&
82 engine->external_client_cnt > 0) {
83 engine->external_client_cnt--;
86 if (sort_graph) {
87 jack_sort_graph (engine);
89 return 0;
92 static void
93 jack_zombify_client (jack_engine_t *engine, jack_client_internal_t *client)
95 VERBOSE (engine, "removing client \"%s\" from the processing chain",
96 client->control->name);
98 /* caller must hold the client_lock */
100 /* this stops jack_deliver_event() from contacing this client */
102 client->control->dead = TRUE;
104 jack_client_disconnect_ports (engine, client);
105 jack_client_do_deactivate (engine, client, FALSE);
108 static void
109 jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)
111 JSList *node;
113 /* caller must write-hold the client lock */
115 VERBOSE (engine, "removing client \"%s\"", client->control->name);
117 /* if its not already a zombie, make it so */
119 if (!client->control->dead) {
120 jack_zombify_client (engine, client);
123 if (client->control->type == ClientExternal) {
125 /* try to force the server thread to return from poll */
127 close (client->event_fd);
128 close (client->request_fd);
131 for (node = engine->clients; node; node = jack_slist_next (node)) {
132 if (((jack_client_internal_t *) node->data)->control->id
133 == client->control->id) {
134 engine->clients =
135 jack_slist_remove_link (engine->clients, node);
136 jack_slist_free_1 (node);
137 break;
141 jack_client_delete (engine, client);
143 /* ignore the driver, which counts as a client. */
145 if (engine->temporary && (jack_slist_length(engine->clients) <= 1)) {
146 if (engine->wait_pid >= 0) {
147 /* tell the waiter we're done
148 to initiate a normal shutdown.
150 VERBOSE (engine, "Kill wait pid to stop");
151 kill (engine->wait_pid, SIGUSR2);
152 sleep (-1);
153 } else {
154 exit (0);
160 static void
161 jack_wake_server_thread (jack_engine_t* engine)
163 char c = 0;
164 /* we don't actually care if this fails */
165 VERBOSE (engine, "waking server thread");
166 write (engine->cleanup_fifo[1], &c, 1);
169 void
170 jack_check_clients (jack_engine_t* engine, int with_timeout_check)
172 /* CALLER MUST HOLD graph read lock */
174 JSList* node;
175 jack_client_internal_t* client;
176 int errs = 0;
178 for (node = engine->clients; node; node = jack_slist_next (node)) {
180 client = (jack_client_internal_t *) node->data;
182 if (client->error) {
183 errs++;
184 continue;
187 if (with_timeout_check) {
189 /* we can only consider the timeout a client error if
190 * it actually woke up. its possible that the kernel
191 * scheduler screwed us up and never woke up the
192 * client in time. sigh.
195 VERBOSE (engine, "checking client %s: awake at %" PRIu64 " finished at %" PRIu64,
196 client->control->name,
197 client->control->awake_at,
198 client->control->finished_at);
200 if (client->control->awake_at > 0) {
201 if (client->control->finished_at == 0) {
202 client->control->timed_out++;
203 client->error++;
204 VERBOSE (engine, "client %s has timed out", client->control->name);
210 if (errs) {
211 jack_lock_problems (engine);
212 engine->problems++;
213 jack_unlock_problems (engine);
214 jack_wake_server_thread (engine);
218 void
219 jack_remove_clients (jack_engine_t* engine)
221 JSList *tmp, *node;
222 int need_sort = FALSE;
223 jack_client_internal_t *client;
225 /* CALLER MUST HOLD GRAPH LOCK */
227 VERBOSE (engine, "++ Removing failed clients ...");
229 /* remove all dead clients */
231 for (node = engine->clients; node; ) {
233 tmp = jack_slist_next (node);
235 client = (jack_client_internal_t *) node->data;
237 VERBOSE(engine, "client %s error status %d", client->control->name, client->error);
239 if (client->error) {
241 /* if we have a communication problem with the
242 client, remove it. otherwise, turn it into
243 a zombie. the client will/should realize
244 this and will close its sockets. then
245 we'll end up back here again and will
246 finally remove the client.
248 if (client->error >= JACK_ERROR_WITH_SOCKETS) {
249 VERBOSE (engine, "removing failed "
250 "client %s state = %s errors"
251 " = %d",
252 client->control->name,
253 jack_client_state_name (client),
254 client->error);
255 jack_remove_client (engine,
256 (jack_client_internal_t *)
257 node->data);
258 } else {
259 VERBOSE (engine, "client failure: "
260 "client %s state = %s errors"
261 " = %d",
262 client->control->name,
263 jack_client_state_name (client),
264 client->error);
265 if (!engine->nozombies) {
266 jack_zombify_client (engine,
267 (jack_client_internal_t *)
268 node->data);
269 client->error = 0;
273 need_sort = TRUE;
276 node = tmp;
279 if (need_sort) {
280 jack_sort_graph (engine);
283 jack_engine_reset_rolling_usecs (engine);
285 VERBOSE (engine, "-- Removing failed clients ...");
288 static int
289 jack_load_client (jack_engine_t *engine, jack_client_internal_t *client,
290 const char *so_name)
292 const char *errstr;
293 char path_to_so[PATH_MAX+1];
295 snprintf (path_to_so, sizeof (path_to_so), ADDON_DIR "/%s.so", so_name);
296 client->handle = dlopen (path_to_so, RTLD_NOW|RTLD_GLOBAL);
298 if (client->handle == 0) {
299 if ((errstr = dlerror ()) != 0) {
300 jack_error ("%s", errstr);
301 } else {
302 jack_error ("bizarre error loading %s", so_name);
304 return -1;
307 client->initialize = dlsym (client->handle, "jack_initialize");
309 if ((errstr = dlerror ()) != 0) {
310 jack_error ("%s has no initialize() function\n", so_name);
311 dlclose (client->handle);
312 client->handle = 0;
313 return -1;
316 client->finish = (void (*)(void *)) dlsym (client->handle,
317 "jack_finish");
319 if ((errstr = dlerror ()) != 0) {
320 jack_error ("%s has no finish() function", so_name);
321 dlclose (client->handle);
322 client->handle = 0;
323 return -1;
326 return 0;
329 static void
330 jack_client_unload (jack_client_internal_t *client)
332 if (client->handle) {
333 if (client->finish) {
334 client->finish (client->private_client->process_arg);
336 dlclose (client->handle);
340 static jack_client_internal_t *
341 jack_client_by_name (jack_engine_t *engine, const char *name)
343 jack_client_internal_t *client = NULL;
344 JSList *node;
346 jack_rdlock_graph (engine);
348 for (node = engine->clients; node; node = jack_slist_next (node)) {
349 if (strcmp ((const char *) ((jack_client_internal_t *)
350 node->data)->control->name,
351 name) == 0) {
352 client = (jack_client_internal_t *) node->data;
353 break;
357 jack_unlock_graph (engine);
358 return client;
361 static jack_client_id_t
362 jack_client_id_by_name (jack_engine_t *engine, const char *name)
364 jack_client_id_t id = 0; /* NULL client ID */
365 JSList *node;
367 jack_rdlock_graph (engine);
369 for (node = engine->clients; node; node = jack_slist_next (node)) {
370 if (strcmp ((const char *) ((jack_client_internal_t *)
371 node->data)->control->name,
372 name) == 0) {
373 jack_client_internal_t *client =
374 (jack_client_internal_t *) node->data;
375 id = client->control->id;
376 break;
380 jack_unlock_graph (engine);
381 return id;
384 jack_client_internal_t *
385 jack_client_internal_by_id (jack_engine_t *engine, jack_client_id_t id)
387 jack_client_internal_t *client = NULL;
388 JSList *node;
390 /* call tree ***MUST HOLD*** the graph lock */
392 for (node = engine->clients; node; node = jack_slist_next (node)) {
394 if (((jack_client_internal_t *) node->data)->control->id
395 == id) {
396 client = (jack_client_internal_t *) node->data;
397 break;
401 return client;
404 /* generate a unique client name
406 * returns 0 if successful, updates name in place
408 static inline int
409 jack_generate_unique_name (jack_engine_t *engine, char *name)
411 int tens, ones;
412 int length = strlen (name);
414 if (length > JACK_CLIENT_NAME_SIZE - 4) {
415 jack_error ("%s exists and is too long to make unique", name);
416 return 1; /* failure */
419 /* generate a unique name by appending "-01".."-99" */
420 name[length++] = '-';
421 tens = length++;
422 ones = length++;
423 name[tens] = '0';
424 name[ones] = '1';
425 name[length] = '\0';
426 while (jack_client_by_name (engine, name)) {
427 if (name[ones] == '9') {
428 if (name[tens] == '9') {
429 jack_error ("client %s has 99 extra"
430 " instances already", name);
431 return 1; /* give up */
433 name[tens]++;
434 name[ones] = '0';
435 } else {
436 name[ones]++;
439 return 0;
442 static int
443 jack_client_name_invalid (jack_engine_t *engine, char *name,
444 jack_options_t options, jack_status_t *status)
446 /* Since this is always called from the server thread, no
447 * other new client will be created at the same time. So,
448 * testing a name for uniqueness is valid here. When called
449 * from jack_engine_load_driver() this is not strictly true,
450 * but that seems to be adequately serialized due to engine
451 * startup. There are no other clients at that point, anyway.
454 if (jack_client_by_name (engine, name)) {
456 *status |= JackNameNotUnique;
458 if (options & JackUseExactName) {
459 jack_error ("cannot create new client; %s already"
460 " exists", name);
461 *status |= JackFailure;
462 return TRUE;
465 if (jack_generate_unique_name(engine, name)) {
466 *status |= JackFailure;
467 return TRUE;
471 return FALSE;
474 /* Set up the engine's client internal and control structures for both
475 * internal and external clients. */
476 static jack_client_internal_t *
477 jack_setup_client_control (jack_engine_t *engine, int fd,
478 ClientType type, const char *name)
480 jack_client_internal_t *client;
482 client = (jack_client_internal_t *)
483 malloc (sizeof (jack_client_internal_t));
485 client->request_fd = fd;
486 client->event_fd = -1;
487 client->ports = 0;
488 client->truefeeds = 0;
489 client->sortfeeds = 0;
490 client->execution_order = UINT_MAX;
491 client->next_client = NULL;
492 client->handle = NULL;
493 client->finish = NULL;
494 client->error = 0;
496 if (type != ClientExternal) {
498 client->control = (jack_client_control_t *)
499 malloc (sizeof (jack_client_control_t));
501 } else {
503 if (jack_shmalloc (sizeof (jack_client_control_t),
504 &client->control_shm)) {
505 jack_error ("cannot create client control block for %s",
506 name);
507 free (client);
508 return 0;
511 if (jack_attach_shm (&client->control_shm)) {
512 jack_error ("cannot attach to client control block "
513 "for %s (%s)", name, strerror (errno));
514 jack_destroy_shm (&client->control_shm);
515 free (client);
516 return 0;
519 client->control = (jack_client_control_t *)
520 jack_shm_addr (&client->control_shm);
523 client->control->type = type;
524 client->control->active = 0;
525 client->control->dead = FALSE;
526 client->control->timed_out = 0;
527 client->control->id = engine->next_client_id++;
528 strcpy ((char *) client->control->name, name);
529 client->subgraph_start_fd = -1;
530 client->subgraph_wait_fd = -1;
532 client->control->process_cbset = FALSE;
533 client->control->bufsize_cbset = FALSE;
534 client->control->srate_cbset = FALSE;
535 client->control->xrun_cbset = FALSE;
536 client->control->port_register_cbset = FALSE;
537 client->control->port_connect_cbset = FALSE;
538 client->control->graph_order_cbset = FALSE;
539 client->control->client_register_cbset = FALSE;
540 client->control->thread_cb_cbset = FALSE;
542 #if 0
543 if (type != ClientExternal) {
544 client->process = NULL;
545 client->process_arg = NULL;
546 client->bufsize = NULL;
547 client->bufsize_arg = NULL;
548 client->srate = NULL;
549 client->srate_arg = NULL;
550 client->xrun = NULL;
551 client->xrun_arg = NULL;
552 client->port_register = NULL;
553 client->port_register_arg = NULL;
554 client->port_connect = NULL;
555 client->port_connect_arg = NULL;
556 client->graph_order = NULL;
557 client->graph_order_arg = NULL;
558 client->client_register = NULL;
559 client->client_register_arg = NULL;
560 client->thread_cb = NULL;
561 client->thread_cb_arg = NULL;
563 #endif
564 jack_transport_client_new (client);
566 #ifdef JACK_USE_MACH_THREADS
567 /* specific resources for server/client real-time thread
568 * communication */
569 allocate_mach_serverport(engine, client);
570 client->running = FALSE;
571 #endif
573 return client;
576 /* set up all types of clients */
577 static jack_client_internal_t *
578 setup_client (jack_engine_t *engine, ClientType type, char *name,
579 jack_options_t options, jack_status_t *status, int client_fd,
580 const char *object_path, const char *object_data)
582 /* called with the request_lock */
583 jack_client_internal_t *client;
585 /* validate client name, generate a unique one if appropriate */
586 if (jack_client_name_invalid (engine, name, options, status))
587 return NULL;
589 /* create a client struct for this name */
590 if ((client = jack_setup_client_control (engine, client_fd,
591 type, name)) == NULL) {
592 *status |= (JackFailure|JackInitFailure);
593 jack_error ("cannot create new client object");
594 return NULL;
597 /* only for internal clients, driver is already loaded */
598 if (type == ClientInternal) {
599 if (jack_load_client (engine, client, object_path)) {
600 jack_error ("cannot dynamically load client from"
601 " \"%s\"", object_path);
602 jack_client_delete (engine, client);
603 *status |= (JackFailure|JackLoadFailure);
604 return NULL;
608 VERBOSE (engine, "new client: %s, id = %" PRIu32
609 " type %d @ %p fd = %d",
610 client->control->name, client->control->id,
611 type, client->control, client_fd);
613 if (jack_client_is_internal(client)) {
615 // XXX: do i need to lock the graph here ?
616 // i moved this one up in the init process, lets see what happens.
618 /* Internal clients need to make regular JACK API
619 * calls, which need a jack_client_t structure.
620 * Create one here.
622 client->private_client =
623 jack_client_alloc_internal (client->control, engine);
625 /* Set up the pointers necessary for the request
626 * system to work. The client is in the same address
627 * space */
629 client->private_client->deliver_request = internal_client_request;
630 client->private_client->deliver_arg = engine;
633 /* add new client to the clients list */
634 jack_lock_graph (engine);
635 engine->clients = jack_slist_prepend (engine->clients, client);
636 jack_engine_reset_rolling_usecs (engine);
638 if (jack_client_is_internal(client)) {
641 jack_unlock_graph (engine);
643 /* Call its initialization function. This function
644 * may make requests of its own, so we temporarily
645 * release and then reacquire the request_lock. */
646 if (client->control->type == ClientInternal) {
648 pthread_mutex_unlock (&engine->request_lock);
649 if (client->initialize (client->private_client,
650 object_data)) {
652 /* failed: clean up client data */
653 VERBOSE (engine,
654 "%s jack_initialize() failed!",
655 client->control->name);
656 jack_lock_graph (engine);
657 jack_remove_client (engine, client);
658 jack_unlock_graph (engine);
659 *status |= (JackFailure|JackInitFailure);
660 client = NULL;
661 //JOQ: not clear that all allocated
662 //storage has been cleaned up properly.
664 pthread_mutex_lock (&engine->request_lock);
667 } else { /* external client */
669 jack_unlock_graph (engine);
672 return client;
675 jack_client_internal_t *
676 jack_create_driver_client (jack_engine_t *engine, char *name)
678 jack_client_connect_request_t req;
679 jack_status_t status;
680 jack_client_internal_t *client;
682 snprintf (req.name, sizeof (req.name), "%s", name);
684 pthread_mutex_lock (&engine->request_lock);
685 client = setup_client (engine, ClientDriver, name, JackUseExactName,
686 &status, -1, NULL, NULL);
687 pthread_mutex_unlock (&engine->request_lock);
689 return client;
692 static jack_status_t
693 handle_unload_client (jack_engine_t *engine, jack_client_id_t id)
695 /* called *without* the request_lock */
696 jack_client_internal_t *client;
697 jack_status_t status = (JackNoSuchClient|JackFailure);
699 jack_lock_graph (engine);
701 if ((client = jack_client_internal_by_id (engine, id))) {
702 VERBOSE (engine, "unloading client \"%s\"",
703 client->control->name);
704 jack_remove_client (engine, client);
705 status = 0;
708 jack_unlock_graph (engine);
710 return status;
714 jack_client_create (jack_engine_t *engine, int client_fd)
716 /* called *without* the request_lock */
717 jack_client_internal_t *client;
718 jack_client_connect_request_t req;
719 jack_client_connect_result_t res;
720 ssize_t nbytes;
722 res.status = 0;
724 nbytes = read (client_fd, &req, sizeof (req));
726 if (nbytes == 0) { /* EOF? */
727 jack_error ("cannot read connection request from client");
728 return -1;
731 /* First verify protocol version (first field of request), if
732 * present, then make sure request has the expected length. */
733 if ((nbytes < sizeof (req.protocol_v))
734 || (req.protocol_v != jack_protocol_version)
735 || (nbytes != sizeof (req))) {
737 /* JACK protocol incompatibility */
738 res.status |= (JackFailure|JackVersionError);
739 jack_error ("JACK protocol mismatch (%d vs %d)", req.protocol_v, jack_protocol_version);
740 if (write (client_fd, &res, sizeof (res)) != sizeof (res)) {
741 jack_error ("cannot write client connection response");
743 return -1;
746 if (!req.load) { /* internal client close? */
748 int rc = -1;
749 jack_client_id_t id;
751 if ((id = jack_client_id_by_name(engine, req.name))) {
752 rc = handle_unload_client (engine, id);
755 /* close does not send a reply */
756 return rc;
759 pthread_mutex_lock (&engine->request_lock);
760 client = setup_client (engine, req.type, req.name,
761 req.options, &res.status, client_fd,
762 req.object_path, req.object_data);
763 pthread_mutex_unlock (&engine->request_lock);
764 if (client == NULL) {
765 res.status |= JackFailure; /* just making sure */
766 return -1;
768 res.client_shm_index = client->control_shm.index;
769 res.engine_shm_index = engine->control_shm.index;
770 res.realtime = engine->control->real_time;
771 res.realtime_priority = engine->rtpriority - 1;
772 strncpy (res.name, req.name, sizeof(res.name));
774 #ifdef JACK_USE_MACH_THREADS
775 /* Mach port number for server/client communication */
776 res.portnum = client->portnum;
777 #endif
779 if (jack_client_is_internal(client)) {
780 /* the ->control pointers are for an internal client
781 so we know they are the right sized pointers
782 for this server. however, to keep the result
783 structure the same size for both 32 and 64 bit
784 clients/servers, the result structure stores
785 them as 64 bit integer, so we have to do a slightly
786 forced cast here.
788 res.client_control = (uint64_t) ((intptr_t) client->control);
789 res.engine_control = (uint64_t) ((intptr_t) engine->control);
790 } else {
791 strcpy (res.fifo_prefix, engine->fifo_prefix);
794 if (write (client_fd, &res, sizeof (res)) != sizeof (res)) {
795 jack_error ("cannot write connection response to client");
796 jack_client_delete (engine, client);
797 return -1;
800 if (jack_client_is_internal (client)) {
801 close (client_fd);
804 jack_client_registration_notify (engine, (const char*) client->control->name, 1);
806 return 0;
810 jack_client_activate (jack_engine_t *engine, jack_client_id_t id)
812 jack_client_internal_t *client;
813 JSList *node;
814 int ret = -1;
816 jack_lock_graph (engine);
818 for (node = engine->clients; node; node = jack_slist_next (node)) {
820 if (((jack_client_internal_t *) node->data)->control->id
821 == id) {
823 client = (jack_client_internal_t *) node->data;
824 client->control->active = TRUE;
826 jack_transport_activate(engine, client);
828 /* we call this to make sure the FIFO is
829 * built+ready by the time the client needs
830 * it. we don't care about the return value at
831 * this point.
834 jack_get_fifo_fd (engine,
835 ++engine->external_client_cnt);
836 jack_sort_graph (engine);
838 ret = 0;
839 break;
843 jack_unlock_graph (engine);
844 return ret;
848 jack_client_deactivate (jack_engine_t *engine, jack_client_id_t id)
850 JSList *node;
851 int ret = -1;
853 jack_lock_graph (engine);
855 for (node = engine->clients; node; node = jack_slist_next (node)) {
857 jack_client_internal_t *client =
858 (jack_client_internal_t *) node->data;
860 if (client->control->id == id) {
862 JSList *portnode;
863 jack_port_internal_t *port;
865 for (portnode = client->ports; portnode;
866 portnode = jack_slist_next (portnode)) {
867 port = (jack_port_internal_t *) portnode->data;
868 jack_port_clear_connections (engine, port);
871 ret = jack_client_do_deactivate (engine, client, TRUE);
872 break;
876 jack_unlock_graph (engine);
878 return ret;
882 jack_mark_client_socket_error (jack_engine_t *engine, int fd)
884 /* CALLER MUST HOLD GRAPH LOCK */
886 jack_client_internal_t *client = 0;
887 JSList *node;
889 for (node = engine->clients; node; node = jack_slist_next (node)) {
891 if (jack_client_is_internal((jack_client_internal_t *)
892 node->data)) {
893 continue;
896 if (((jack_client_internal_t *) node->data)->request_fd == fd) {
897 client = (jack_client_internal_t *) node->data;
898 break;
902 if (client) {
903 VERBOSE (engine, "marking client %s with SOCKET error state = "
904 "%s errors = %d", client->control->name,
905 jack_client_state_name (client),
906 client->error);
907 client->error += JACK_ERROR_WITH_SOCKETS;
910 return 0;
913 void
914 jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client)
916 jack_client_registration_notify (engine, (const char*) client->control->name, 0);
918 if (jack_client_is_internal (client)) {
920 jack_client_unload (client);
921 free (client->private_client);
922 free ((void *) client->control);
924 } else {
926 /* release the client segment, mark it for
927 destruction, and free up the shm registry
928 information so that it can be reused.
931 jack_release_shm (&client->control_shm);
932 jack_destroy_shm (&client->control_shm);
935 free (client);
938 void
939 jack_intclient_handle_request (jack_engine_t *engine, jack_request_t *req)
941 jack_client_internal_t *client;
943 req->status = 0;
944 if ((client = jack_client_by_name (engine, req->x.intclient.name))) {
945 req->x.intclient.id = client->control->id;
946 } else {
947 req->status |= (JackNoSuchClient|JackFailure);
951 void
952 jack_intclient_load_request (jack_engine_t *engine, jack_request_t *req)
954 /* called with the request_lock */
955 jack_client_internal_t *client;
956 jack_status_t status = 0;
958 VERBOSE (engine, "load internal client %s from %s, init `%s', "
959 "options: 0x%x", req->x.intclient.name,
960 req->x.intclient.path, req->x.intclient.init,
961 req->x.intclient.options);
963 client = setup_client (engine, ClientInternal, req->x.intclient.name,
964 req->x.intclient.options, &status, -1,
965 req->x.intclient.path, req->x.intclient.init);
967 if (client == NULL) {
968 status |= JackFailure; /* just making sure */
969 req->x.intclient.id = 0;
970 VERBOSE (engine, "load failed, status = 0x%x", status);
971 } else {
972 req->x.intclient.id = client->control->id;
975 req->status = status;
978 void
979 jack_intclient_name_request (jack_engine_t *engine, jack_request_t *req)
981 jack_client_internal_t *client;
983 jack_rdlock_graph (engine);
984 if ((client = jack_client_internal_by_id (engine,
985 req->x.intclient.id))) {
986 strncpy ((char *) req->x.intclient.name,
987 (char *) client->control->name,
988 sizeof (req->x.intclient.name));
989 req->status = 0;
990 } else {
991 req->status = (JackNoSuchClient|JackFailure);
993 jack_unlock_graph (engine);
996 void
997 jack_intclient_unload_request (jack_engine_t *engine, jack_request_t *req)
999 /* Called with the request_lock, but we need to call
1000 * handle_unload_client() *without* it. */
1002 if (req->x.intclient.id) {
1003 pthread_mutex_unlock (&engine->request_lock);
1004 req->status =
1005 handle_unload_client (engine, req->x.intclient.id);
1006 pthread_mutex_lock (&engine->request_lock);
1007 } else {
1008 VERBOSE (engine, "invalid unload request");
1009 req->status = JackFailure;