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;