~ubuntu-branches/ubuntu/trusty/jack-audio-connection-kit/trusty

« back to all changes in this revision

Viewing changes to jackd/clientengine.c

  • Committer: Bazaar Package Importer
  • Author(s): Luca Falavigna
  • Date: 2008-12-06 11:05:15 UTC
  • mfrom: (4.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20081206110515-xa9v9pajr9jqvfvg
Tags: 0.115.6-1ubuntu1
* Merge from Debian unstable, remaining Ubuntu changes:
  - Redirect stderr in bash completion (Debian #504488).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: c; c-file-style: "bsd"; -*- */
 
2
/*
 
3
 *  Client creation and destruction interfaces for JACK engine.
 
4
 *
 
5
 *  Copyright (C) 2001-2003 Paul Davis
 
6
 *  Copyright (C) 2004 Jack O'Quin
 
7
 *  
 
8
 *  This program is free software; you can redistribute it and/or modify
 
9
 *  it under the terms of the GNU General Public License as published by
 
10
 *  the Free Software Foundation; either version 2 of the License, or
 
11
 *  (at your option) any later version.
 
12
 *
 
13
 *  This program is distributed in the hope that it will be useful,
 
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
 *  GNU General Public License for more details.
 
17
 *
 
18
 *  You should have received a copy of the GNU General Public License
 
19
 *  along with this program; if not, write to the Free Software
 
20
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
21
 *
 
22
 */
 
23
 
 
24
#include <config.h>
 
25
 
 
26
#include <errno.h>
 
27
#include <stdio.h>
 
28
#include <unistd.h>
 
29
#include <string.h>
 
30
 
 
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>
 
37
 
 
38
#include "clientengine.h"
 
39
#include "transengine.h"
 
40
 
 
41
#include "libjack/local.h"
 
42
 
 
43
static void
 
44
jack_client_disconnect_ports (jack_engine_t *engine,
 
45
                              jack_client_internal_t *client)
 
46
{
 
47
        JSList *node;
 
48
        jack_port_internal_t *port;
 
49
 
 
50
        /* call tree **** MUST HOLD *** engine->client_lock */
 
51
 
 
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);
 
57
        }
 
58
 
 
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;
 
65
}                       
 
66
 
 
67
int
 
68
jack_client_do_deactivate (jack_engine_t *engine,
 
69
                           jack_client_internal_t *client, int sort_graph)
 
70
{
 
71
        /* caller must hold engine->client_lock and must have checked for and/or
 
72
         *   cleared all connections held by client. 
 
73
         */
 
74
        VERBOSE(engine,"+++ deactivate %s", client->control->name);
 
75
 
 
76
        client->control->active = FALSE;
 
77
 
 
78
        jack_transport_client_exit (engine, client);
 
79
 
 
80
        if (!jack_client_is_internal (client) &&
 
81
            engine->external_client_cnt > 0) {  
 
82
                engine->external_client_cnt--;
 
83
        }
 
84
        
 
85
        if (sort_graph) {
 
86
                jack_sort_graph (engine);
 
87
        }
 
88
        return 0;
 
89
}
 
90
 
 
91
static void
 
92
jack_zombify_client (jack_engine_t *engine, jack_client_internal_t *client)
 
93
{
 
94
        VERBOSE (engine, "removing client \"%s\" from the processing chain",
 
95
                 client->control->name);
 
96
 
 
97
        /* caller must hold the client_lock */
 
98
 
 
99
        /* this stops jack_deliver_event() from contacing this client */
 
100
 
 
101
        client->control->dead = TRUE;
 
102
 
 
103
        jack_client_disconnect_ports (engine, client);
 
104
        jack_client_do_deactivate (engine, client, FALSE);
 
105
}
 
106
 
 
107
static void
 
108
jack_remove_client (jack_engine_t *engine, jack_client_internal_t *client)
 
109
{
 
110
        JSList *node;
 
111
 
 
112
        /* caller must write-hold the client lock */
 
113
 
 
114
        VERBOSE (engine, "removing client \"%s\"", client->control->name);
 
115
 
 
116
        /* if its not already a zombie, make it so */
 
117
 
 
118
        if (!client->control->dead) {
 
119
                jack_zombify_client (engine, client);
 
120
        }
 
121
 
 
122
        if (client->control->type == ClientExternal) {
 
123
 
 
124
                /* try to force the server thread to return from poll */
 
125
        
 
126
                close (client->event_fd);
 
127
                close (client->request_fd);
 
128
        }
 
129
 
 
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;
 
137
                }
 
138
        }
 
139
 
 
140
        jack_client_delete (engine, client);
 
141
 
 
142
        /* ignore the driver, which counts as a client. */
 
143
 
 
144
        if (engine->temporary && (jack_slist_length(engine->clients) <= 1)) {
 
145
                exit (0);
 
146
        }
 
147
}
 
148
 
 
149
static void
 
150
jack_wake_server_thread (jack_engine_t* engine)
 
151
{
 
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);
 
156
}
 
157
 
 
158
void
 
159
jack_check_clients (jack_engine_t* engine, int with_timeout_check)
 
160
{
 
161
        /* CALLER MUST HOLD graph read lock */
 
162
 
 
163
        JSList* node;
 
164
        jack_client_internal_t* client;
 
165
        int errs = 0;
 
166
 
 
167
        for (node = engine->clients; node; node = jack_slist_next (node)) {
 
168
 
 
169
                client = (jack_client_internal_t *) node->data;
 
170
 
 
171
                if (client->error) {
 
172
                        errs++;
 
173
                        continue;
 
174
                }
 
175
 
 
176
                if (with_timeout_check) {
 
177
 
 
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.
 
182
                         */
 
183
                        
 
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);
 
188
                        
 
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);
 
194
                                }
 
195
                        }
 
196
                }
 
197
        }
 
198
                
 
199
        if (errs) {
 
200
                jack_lock_problems (engine);
 
201
                engine->problems++;
 
202
                jack_unlock_problems (engine);
 
203
                jack_wake_server_thread (engine);
 
204
        }
 
205
}
 
206
 
 
207
void
 
208
jack_remove_clients (jack_engine_t* engine)
 
209
{
 
210
        JSList *tmp, *node;
 
211
        int need_sort = FALSE;
 
212
        jack_client_internal_t *client;
 
213
 
 
214
        /* CALLER MUST HOLD GRAPH LOCK */
 
215
 
 
216
        VERBOSE (engine, "++ Removing failed clients ...");
 
217
 
 
218
        /* remove all dead clients */
 
219
 
 
220
        for (node = engine->clients; node; ) {
 
221
                
 
222
                tmp = jack_slist_next (node);
 
223
                
 
224
                client = (jack_client_internal_t *) node->data;
 
225
 
 
226
                VERBOSE(engine, "client %s error status %d", client->control->name, client->error);
 
227
                
 
228
                if (client->error) {
 
229
                        
 
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.
 
236
                        */
 
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;
 
259
                                }
 
260
                        }
 
261
                        
 
262
                        need_sort = TRUE;
 
263
                }
 
264
                
 
265
                node = tmp;
 
266
        }
 
267
 
 
268
        if (need_sort) {
 
269
                jack_sort_graph (engine);
 
270
        }
 
271
        
 
272
        jack_engine_reset_rolling_usecs (engine);
 
273
 
 
274
        VERBOSE (engine, "-- Removing failed clients ...");
 
275
}
 
276
 
 
277
static int
 
278
jack_load_client (jack_engine_t *engine, jack_client_internal_t *client,
 
279
                  const char *so_name)
 
280
{
 
281
        const char *errstr;
 
282
        char path_to_so[PATH_MAX+1];
 
283
 
 
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);
 
286
        
 
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);
 
292
                }
 
293
                return -1;
 
294
        }
 
295
 
 
296
        client->initialize = dlsym (client->handle, "jack_initialize");
 
297
 
 
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;
 
303
        }
 
304
 
 
305
        client->finish = (void (*)(void *)) dlsym (client->handle,
 
306
                                                   "jack_finish");
 
307
        
 
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;
 
313
        }
 
314
 
 
315
        return 0;
 
316
}
 
317
 
 
318
static void
 
319
jack_client_unload (jack_client_internal_t *client)
 
320
{
 
321
        if (client->handle) {
 
322
                if (client->finish) {
 
323
                        client->finish (client->private_client->process_arg);
 
324
                }
 
325
                dlclose (client->handle);
 
326
        }
 
327
}
 
328
 
 
329
static jack_client_internal_t *
 
330
jack_client_by_name (jack_engine_t *engine, const char *name)
 
331
{
 
332
        jack_client_internal_t *client = NULL;
 
333
        JSList *node;
 
334
 
 
335
        jack_rdlock_graph (engine);
 
336
 
 
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;
 
343
                }
 
344
        }
 
345
 
 
346
        jack_unlock_graph (engine);
 
347
        return client;
 
348
}
 
349
 
 
350
static jack_client_id_t
 
351
jack_client_id_by_name (jack_engine_t *engine, const char *name)
 
352
{
 
353
        jack_client_id_t id = 0;        /* NULL client ID */
 
354
        JSList *node;
 
355
 
 
356
        jack_rdlock_graph (engine);
 
357
 
 
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;
 
366
                }
 
367
        }
 
368
 
 
369
        jack_unlock_graph (engine);
 
370
        return id;
 
371
}
 
372
 
 
373
jack_client_internal_t *
 
374
jack_client_internal_by_id (jack_engine_t *engine, jack_client_id_t id)
 
375
{
 
376
        jack_client_internal_t *client = NULL;
 
377
        JSList *node;
 
378
 
 
379
        /* call tree ***MUST HOLD*** the graph lock */
 
380
 
 
381
        for (node = engine->clients; node; node = jack_slist_next (node)) {
 
382
 
 
383
                if (((jack_client_internal_t *) node->data)->control->id
 
384
                    == id) {
 
385
                        client = (jack_client_internal_t *) node->data;
 
386
                        break;
 
387
                }
 
388
        }
 
389
 
 
390
        return client;
 
391
}
 
392
 
 
393
/* generate a unique client name
 
394
 *
 
395
 * returns 0 if successful, updates name in place
 
396
 */
 
397
static inline int
 
398
jack_generate_unique_name (jack_engine_t *engine, char *name)
 
399
{
 
400
        int tens, ones;
 
401
        int length = strlen (name);
 
402
 
 
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 */
 
406
        }
 
407
 
 
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 */
 
421
                        }
 
422
                        name[tens]++;
 
423
                        name[ones] = '0';
 
424
                } else {
 
425
                        name[ones]++;
 
426
                }
 
427
        }
 
428
        return 0;
 
429
}
 
430
 
 
431
static int
 
432
jack_client_name_invalid (jack_engine_t *engine, char *name,
 
433
                          jack_options_t options, jack_status_t *status)
 
434
{
 
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.
 
441
         */
 
442
 
 
443
        if (jack_client_by_name (engine, name)) {
 
444
 
 
445
                *status |= JackNameNotUnique;
 
446
 
 
447
                if (options & JackUseExactName) {
 
448
                        jack_error ("cannot create new client; %s already"
 
449
                                    " exists", name);
 
450
                        *status |= JackFailure;
 
451
                        return TRUE;
 
452
                }
 
453
 
 
454
                if (jack_generate_unique_name(engine, name)) {
 
455
                        *status |= JackFailure;
 
456
                        return TRUE;
 
457
                }
 
458
        }
 
459
 
 
460
        return FALSE;
 
461
}
 
462
 
 
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)
 
468
{
 
469
        jack_client_internal_t *client;
 
470
 
 
471
        client = (jack_client_internal_t *)
 
472
                malloc (sizeof (jack_client_internal_t));
 
473
 
 
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;
 
484
 
 
485
        if (type != ClientExternal) {
 
486
                
 
487
                client->control = (jack_client_control_t *)
 
488
                        malloc (sizeof (jack_client_control_t));                
 
489
 
 
490
        } else {
 
491
 
 
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;
 
498
                }
 
499
 
 
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;
 
506
                }
 
507
 
 
508
                client->control = (jack_client_control_t *)
 
509
                        jack_shm_addr (&client->control_shm);
 
510
        }
 
511
 
 
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;
 
520
 
 
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;
 
530
 
 
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;
 
551
        }
 
552
#endif
 
553
        jack_transport_client_new (client);
 
554
        
 
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
 
561
 
 
562
        return client;
 
563
}
 
564
 
 
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)
 
570
{
 
571
        /* called with the request_lock */
 
572
        jack_client_internal_t *client;
 
573
 
 
574
        /* validate client name, generate a unique one if appropriate */
 
575
        if (jack_client_name_invalid (engine, name, options, status))
 
576
                return NULL;
 
577
 
 
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;
 
584
        }
 
585
 
 
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;
 
594
                }
 
595
        }
 
596
 
 
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);
 
601
 
 
602
        if (jack_client_is_internal(client)) {
 
603
 
 
604
            // XXX: do i need to lock the graph here ?
 
605
            // i moved this one up in the init process, lets see what happens.
 
606
 
 
607
                /* Internal clients need to make regular JACK API
 
608
                 * calls, which need a jack_client_t structure.
 
609
                 * Create one here.
 
610
                 */
 
611
                client->private_client =
 
612
                        jack_client_alloc_internal (client->control, engine);
 
613
 
 
614
                /* Set up the pointers necessary for the request
 
615
                 * system to work.  The client is in the same address
 
616
                 * space */
 
617
 
 
618
                client->private_client->deliver_request = internal_client_request;
 
619
                client->private_client->deliver_arg = engine;
 
620
        }
 
621
 
 
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);
 
626
        
 
627
        if (jack_client_is_internal(client)) {
 
628
 
 
629
 
 
630
                jack_unlock_graph (engine);
 
631
 
 
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) {
 
636
 
 
637
                        pthread_mutex_unlock (&engine->request_lock);
 
638
                        if (client->initialize (client->private_client,
 
639
                                                object_data)) {
 
640
 
 
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.
 
652
                        }
 
653
                        pthread_mutex_lock (&engine->request_lock);
 
654
                }
 
655
 
 
656
        } else {                        /* external client */
 
657
 
 
658
                jack_unlock_graph (engine);
 
659
        }
 
660
        
 
661
        return client;
 
662
}
 
663
 
 
664
jack_client_internal_t *
 
665
jack_create_driver_client (jack_engine_t *engine, char *name)
 
666
{
 
667
        jack_client_connect_request_t req;
 
668
        jack_status_t status;
 
669
        jack_client_internal_t *client;
 
670
 
 
671
        snprintf (req.name, sizeof (req.name), "%s", name);
 
672
 
 
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);
 
677
 
 
678
        return client;
 
679
}
 
680
 
 
681
static jack_status_t
 
682
handle_unload_client (jack_engine_t *engine, jack_client_id_t id)
 
683
{
 
684
        /* called *without* the request_lock */
 
685
        jack_client_internal_t *client;
 
686
        jack_status_t status = (JackNoSuchClient|JackFailure);
 
687
 
 
688
        jack_lock_graph (engine);
 
689
 
 
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;
 
695
        }
 
696
 
 
697
        jack_unlock_graph (engine);
 
698
 
 
699
        return status;
 
700
}
 
701
 
 
702
int
 
703
jack_client_create (jack_engine_t *engine, int client_fd)
 
704
{
 
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;
 
710
 
 
711
        res.status = 0;
 
712
 
 
713
        nbytes = read (client_fd, &req, sizeof (req));
 
714
 
 
715
        if (nbytes == 0) {              /* EOF? */
 
716
                jack_error ("cannot read connection request from client");
 
717
                return -1;
 
718
        }
 
719
 
 
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))) {
 
725
 
 
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");
 
731
                }
 
732
                return -1;
 
733
        }
 
734
 
 
735
        if (!req.load) {                /* internal client close? */
 
736
 
 
737
                int rc = -1;
 
738
                jack_client_id_t id;
 
739
 
 
740
                if ((id = jack_client_id_by_name(engine, req.name))) {
 
741
                        rc = handle_unload_client (engine, id);
 
742
                }
 
743
                
 
744
                /* close does not send a reply */
 
745
                return rc;
 
746
        }
 
747
        
 
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;
 
756
        }
 
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));
 
762
 
 
763
#ifdef JACK_USE_MACH_THREADS
 
764
        /* Mach port number for server/client communication */
 
765
        res.portnum = client->portnum;
 
766
#endif
 
767
        
 
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);
 
773
        }
 
774
 
 
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;
 
779
        }
 
780
 
 
781
        if (jack_client_is_internal (client)) {
 
782
                close (client_fd);
 
783
        }
 
784
 
 
785
        jack_client_registration_notify (engine, (const char*) client->control->name, 1);
 
786
 
 
787
        return 0;
 
788
}
 
789
 
 
790
int
 
791
jack_client_activate (jack_engine_t *engine, jack_client_id_t id)
 
792
{
 
793
        jack_client_internal_t *client;
 
794
        JSList *node;
 
795
        int ret = -1;
 
796
 
 
797
        jack_lock_graph (engine);
 
798
 
 
799
        for (node = engine->clients; node; node = jack_slist_next (node)) {
 
800
 
 
801
                if (((jack_client_internal_t *) node->data)->control->id
 
802
                    == id) {
 
803
                       
 
804
                        client = (jack_client_internal_t *) node->data;
 
805
                        client->control->active = TRUE;
 
806
 
 
807
                        jack_transport_activate(engine, client);
 
808
 
 
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.
 
813
                         */
 
814
 
 
815
                        jack_get_fifo_fd (engine,
 
816
                                          ++engine->external_client_cnt);
 
817
                        jack_sort_graph (engine);
 
818
 
 
819
                        ret = 0;
 
820
                        break;
 
821
                }
 
822
        }
 
823
 
 
824
        jack_unlock_graph (engine);
 
825
        return ret;
 
826
}       
 
827
 
 
828
int
 
829
jack_client_deactivate (jack_engine_t *engine, jack_client_id_t id)
 
830
{
 
831
        JSList *node;
 
832
        int ret = -1;
 
833
 
 
834
        jack_lock_graph (engine);
 
835
 
 
836
        for (node = engine->clients; node; node = jack_slist_next (node)) {
 
837
 
 
838
                jack_client_internal_t *client =
 
839
                        (jack_client_internal_t *) node->data;
 
840
 
 
841
                if (client->control->id == id) {
 
842
                        
 
843
                        JSList *portnode;
 
844
                        jack_port_internal_t *port;
 
845
 
 
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);
 
850
                        }
 
851
 
 
852
                        ret = jack_client_do_deactivate (engine, client, TRUE);
 
853
                        break;
 
854
                }
 
855
        }
 
856
 
 
857
        jack_unlock_graph (engine);
 
858
 
 
859
        return ret;
 
860
}       
 
861
 
 
862
int
 
863
jack_mark_client_socket_error (jack_engine_t *engine, int fd)
 
864
{
 
865
        /* CALLER MUST HOLD GRAPH LOCK */
 
866
 
 
867
        jack_client_internal_t *client = 0;
 
868
        JSList *node;
 
869
 
 
870
        for (node = engine->clients; node; node = jack_slist_next (node)) {
 
871
 
 
872
                if (jack_client_is_internal((jack_client_internal_t *)
 
873
                                            node->data)) {
 
874
                        continue;
 
875
                }
 
876
 
 
877
                if (((jack_client_internal_t *) node->data)->request_fd == fd) {
 
878
                        client = (jack_client_internal_t *) node->data;
 
879
                        break;
 
880
                }
 
881
        }
 
882
 
 
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;
 
889
        }
 
890
 
 
891
        return 0;
 
892
}
 
893
 
 
894
void
 
895
jack_client_delete (jack_engine_t *engine, jack_client_internal_t *client)
 
896
{
 
897
        jack_client_registration_notify (engine, (const char*) client->control->name, 0);
 
898
 
 
899
        if (jack_client_is_internal (client)) {
 
900
 
 
901
                jack_client_unload (client);
 
902
                free (client->private_client);
 
903
                free ((void *) client->control);
 
904
 
 
905
        } else {
 
906
                
 
907
                /* release the client segment, mark it for
 
908
                   destruction, and free up the shm registry
 
909
                   information so that it can be reused.
 
910
                */
 
911
 
 
912
                jack_release_shm (&client->control_shm);
 
913
                jack_destroy_shm (&client->control_shm);
 
914
        }
 
915
 
 
916
        free (client);
 
917
}
 
918
 
 
919
void
 
920
jack_intclient_handle_request (jack_engine_t *engine, jack_request_t *req)
 
921
{
 
922
        jack_client_internal_t *client;
 
923
 
 
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);
 
929
        }
 
930
}
 
931
 
 
932
void
 
933
jack_intclient_load_request (jack_engine_t *engine, jack_request_t *req)
 
934
{
 
935
        /* called with the request_lock */
 
936
        jack_client_internal_t *client;
 
937
        jack_status_t status = 0;
 
938
 
 
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);
 
943
 
 
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);
 
947
 
 
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;
 
954
        }
 
955
 
 
956
        req->status = status;
 
957
}
 
958
 
 
959
void
 
960
jack_intclient_name_request (jack_engine_t *engine, jack_request_t *req)
 
961
{
 
962
        jack_client_internal_t *client;
 
963
 
 
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);
 
973
        }
 
974
        jack_unlock_graph (engine);
 
975
}
 
976
 
 
977
void
 
978
jack_intclient_unload_request (jack_engine_t *engine, jack_request_t *req)
 
979
{
 
980
        /* Called with the request_lock, but we need to call
 
981
         * handle_unload_client() *without* it. */
 
982
 
 
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;
 
991
        }
 
992
}
 
993