objects.c 45.8 KB
Newer Older
1
2
3
/*****************************************************************************
 * objects.c: vlc_object_t handling
 *****************************************************************************
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
4
 * Copyright (C) 2004-2008 the VideoLAN team
5
 * $Id$
6
7
8
9
10
11
12
 *
 * Authors: Samuel Hocevar <sam@zoy.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
13
 *
14
15
16
17
18
19
20
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22
23
 *****************************************************************************/

zorglub's avatar
zorglub committed
24
25
26
27
28
29
/**
 * \file
 * This file contains the functions to handle the vlc_object_t type
 */


30
31
32
/*****************************************************************************
 * Preamble
 *****************************************************************************/
33
34
35
36
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

37
38
#include <vlc/vlc.h>

39
#include "../libvlc.h"
zorglub's avatar
zorglub committed
40
41
42
#include <vlc_vout.h>
#include <vlc_aout.h>
#include "audio_output/aout_internal.h"
43

zorglub's avatar
zorglub committed
44
45
46
47
48
49
#include <vlc_access.h>
#include <vlc_demux.h>
#include <vlc_stream.h>

#include <vlc_sout.h>
#include "stream_output/stream_output.h"
50

51
#include "vlc_interface.h"
gbazin's avatar
   
gbazin committed
52
#include "vlc_codec.h"
53
#include "vlc_filter.h"
54

zorglub's avatar
zorglub committed
55
#include "variables.h"
56
57
58
59
60
#ifndef WIN32
# include <unistd.h>
#else
# include <io.h>
# include <fcntl.h>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
61
# include <errno.h> /* ENOSYS */
62
#endif
63
#include <assert.h>
zorglub's avatar
zorglub committed
64

65
66
67
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
68
69
static int  DumpCommand( vlc_object_t *, char const *,
                         vlc_value_t, vlc_value_t, void * );
70

71
static vlc_object_t * FindObject    ( vlc_object_t *, int, int );
72
static vlc_object_t * FindObjectName( vlc_object_t *, const char *, int );
73
74
75
76
static void           PrintObject   ( vlc_object_t *, const char * );
static void           DumpStructure ( vlc_object_t *, int, char * );
static int            FindIndex     ( vlc_object_t *, vlc_object_t **, int );

77
static vlc_list_t   * NewList       ( int );
gbazin's avatar
   
gbazin committed
78
static void           ListReplace   ( vlc_list_t *, vlc_object_t *, int );
79
/*static void           ListAppend    ( vlc_list_t *, vlc_object_t * );*/
gbazin's avatar
   
gbazin committed
80
81
static int            CountChildren ( vlc_object_t *, int );
static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
82

83
static void vlc_object_destroy( vlc_object_t *p_this );
84
static void vlc_object_detach_unlocked (vlc_object_t *p_this);
85

86
87
88
89
90
/*****************************************************************************
 * Local structure lock
 *****************************************************************************/
static vlc_mutex_t    structure_lock;

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
91
92
void *vlc_custom_create( vlc_object_t *p_this, size_t i_size,
                         int i_type, const char *psz_type )
93
{
94
95
    vlc_object_t *p_new;
    vlc_object_internals_t *p_priv;
96

97
98
99
100
101
102
103
104
105
    /* NOTE:
     * VLC objects are laid out as follow:
     * - first the LibVLC-private per-object data,
     * - then VLC_COMMON members from vlc_object_t,
     * - finally, the type-specific data (if any).
     *
     * This function initializes the LibVLC and common data,
     * and zeroes the rest.
     */
106
107
108
109
    p_priv = calloc( 1, sizeof( *p_priv ) + i_size );
    if( p_priv == NULL )
        return NULL;

110
111
    assert (i_size >= sizeof (vlc_object_t));
    p_new = (vlc_object_t *)(p_priv + 1);
112
113
114
115
116

    p_new->i_object_type = i_type;
    p_new->psz_object_type = psz_type;
    p_new->psz_object_name = NULL;

117
118
119
120
    p_new->b_die = false;
    p_new->b_error = false;
    p_new->b_dead = false;
    p_new->b_force = false;
121
122
123

    p_new->psz_header = NULL;

124
125
126
    if (p_this)
        p_new->i_flags = p_this->i_flags
            & (OBJECT_FLAGS_NODBG|OBJECT_FLAGS_QUIET|OBJECT_FLAGS_NOINTERACT);
127

128
    p_priv->p_vars = calloc( sizeof( variable_t ), 16 );
129

130
    if( !p_priv->p_vars )
131
    {
132
        free( p_priv );
133
134
135
        return NULL;
    }

136
    libvlc_global_data_t *p_libvlc_global;
137
    if( p_this == NULL )
138
    {
139
        /* Only the global root object is created out of the blue */
140
        p_libvlc_global = (libvlc_global_data_t *)p_new;
141
142
        p_new->p_libvlc = NULL;

143
        p_libvlc_global->i_counter = 0;
144
145
        p_libvlc_global->i_objects = 0;
        p_libvlc_global->pp_objects = NULL;
146
        vlc_mutex_init( &structure_lock );
147
148
149
    }
    else
    {
150
        p_libvlc_global = vlc_global();
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
151
        if( i_type == VLC_OBJECT_LIBVLC )
152
            p_new->p_libvlc = (libvlc_int_t*)p_new;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
153
154
        else
            p_new->p_libvlc = p_this->p_libvlc;
155
    }
156

157
    vlc_spin_init( &p_priv->ref_spin );
158
    p_priv->i_refcount = 1;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
159
    p_priv->pf_destructor = NULL;
160
    p_priv->b_thread = false;
161
162
163
164
165
166
167
    p_new->p_parent = NULL;
    p_new->pp_children = NULL;
    p_new->i_children = 0;

    p_new->p_private = NULL;

    /* Initialize mutexes and condvars */
168
    vlc_mutex_init( &p_new->object_lock );
169
    vlc_cond_init( p_new, &p_new->object_wait );
170
    vlc_mutex_init( &p_priv->var_lock );
171
    vlc_spin_init( &p_priv->spin );
172
    p_priv->pipes[0] = p_priv->pipes[1] = -1;
173

174
175
176
177
178
179
180
181
    vlc_mutex_lock( &structure_lock );
    p_new->i_object_id = p_libvlc_global->i_counter++;
    /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
     * useless to try and recover anything if pp_objects gets smashed. */
    TAB_APPEND( p_libvlc_global->i_objects, p_libvlc_global->pp_objects,
                p_new );
    vlc_mutex_unlock( &structure_lock );

182
183
    if( i_type == VLC_OBJECT_LIBVLC )
    {
184
185
186
187
        var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
        var_AddCallback( p_new, "list", DumpCommand, NULL );
        var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
        var_AddCallback( p_new, "tree", DumpCommand, NULL );
188
189
        var_Create( p_new, "vars", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
        var_AddCallback( p_new, "vars", DumpCommand, NULL );
190
191
192
193
194
195
    }

    return p_new;
}


zorglub's avatar
zorglub committed
196
/**
197
 * Allocates and initializes a vlc object.
zorglub's avatar
zorglub committed
198
 *
199
200
201
202
 * @param i_type known object type (all of them are negative integer values),
 *               or object byte size (always positive).
 *
 * @return the new object, or NULL on error.
zorglub's avatar
zorglub committed
203
 */
204
205
void * __vlc_object_create( vlc_object_t *p_this, int i_type )
{
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
206
    const char   * psz_type;
207
208
209
210
    size_t         i_size;

    switch( i_type )
    {
211
212
213
        case VLC_OBJECT_LIBVLC:
            i_size = sizeof(libvlc_int_t);
            psz_type = "libvlc";
214
            break;
215
216
217
218
        case VLC_OBJECT_INTF:
            i_size = sizeof(intf_thread_t);
            psz_type = "interface";
            break;
gbazin's avatar
   
gbazin committed
219
220
        case VLC_OBJECT_DIALOGS:
            i_size = sizeof(intf_thread_t);
zorglub's avatar
zorglub committed
221
            psz_type = "dialogs";
gbazin's avatar
   
gbazin committed
222
            break;
223
224
225
226
        case VLC_OBJECT_DEMUX:
            i_size = sizeof(demux_t);
            psz_type = "demux";
            break;
227
228
229
230
        case VLC_OBJECT_ACCESS:
            i_size = sizeof(access_t);
            psz_type = "access";
            break;
231
        case VLC_OBJECT_DECODER:
gbazin's avatar
   
gbazin committed
232
233
234
            i_size = sizeof(decoder_t);
            psz_type = "decoder";
            break;
gbazin's avatar
   
gbazin committed
235
236
237
238
239
240
241
242
        case VLC_OBJECT_PACKETIZER:
            i_size = sizeof(decoder_t);
            psz_type = "packetizer";
            break;
        case VLC_OBJECT_ENCODER:
            i_size = sizeof(encoder_t);
            psz_type = "encoder";
            break;
243
244
245
246
        case VLC_OBJECT_FILTER:
            i_size = sizeof(filter_t);
            psz_type = "filter";
            break;
247
248
249
250
251
        case VLC_OBJECT_VOUT:
            i_size = sizeof(vout_thread_t);
            psz_type = "video output";
            break;
        case VLC_OBJECT_AOUT:
252
            i_size = sizeof(aout_instance_t);
253
254
            psz_type = "audio output";
            break;
255
256
257
258
        case VLC_OBJECT_SOUT:
            i_size = sizeof(sout_instance_t);
            psz_type = "stream output";
            break;
259
        case VLC_OBJECT_OPENGL:
260
            i_size = sizeof( vout_thread_t );
zorglub's avatar
zorglub committed
261
            psz_type = "opengl";
262
            break;
zorglub's avatar
zorglub committed
263
264
        case VLC_OBJECT_ANNOUNCE:
            i_size = sizeof( announce_handler_t );
zorglub's avatar
zorglub committed
265
            psz_type = "announce";
zorglub's avatar
zorglub committed
266
            break;
267
268
269
270
        case VLC_OBJECT_INTERACTION:
            i_size = sizeof( interaction_t );
            psz_type = "interaction";
            break;
271
        default:
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
272
273
            i_size = i_type > (int)sizeof(vlc_object_t)
                         ? i_type : (int)sizeof(vlc_object_t);
274
275
            i_type = VLC_OBJECT_GENERIC;
            psz_type = "generic";
276
277
278
            break;
    }

279
    return vlc_custom_create( p_this, i_size, i_type, psz_type );
280
281
}

282

283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/**
 ****************************************************************************
 * Set the destructor of a vlc object
 *
 * This function sets the destructor of the vlc object. It will be called
 * when the object is destroyed when the its refcount reaches 0.
 * (It is called by the internal function vlc_object_destroy())
 *****************************************************************************/
void __vlc_object_set_destructor( vlc_object_t *p_this,
                                  vlc_destructor_t pf_destructor )
{
    vlc_object_internals_t *p_priv = vlc_internals(p_this );
    p_priv->pf_destructor = pf_destructor;
}

zorglub's avatar
zorglub committed
298
299
/**
 ****************************************************************************
300
 * Destroy a vlc object (Internal)
zorglub's avatar
zorglub committed
301
 *
302
303
304
305
 * This function destroys an object that has been previously allocated with
 * vlc_object_create. The object's refcount must be zero and it must not be
 * attached to other objects in any way.
 *****************************************************************************/
306
static void vlc_object_destroy( vlc_object_t *p_this )
307
{
308
    vlc_object_internals_t *p_priv = vlc_internals( p_this );
309

310
311
    /* Objects are always detached beforehand */
    assert( !p_this->p_parent );
312
313
314
315
316
317
318
319
320
321
322
323

    /* Send a kill to the object's thread if applicable */
    vlc_object_kill( p_this );

    /* If we are running on a thread, wait until it ends */
    if( p_priv->b_thread )
        vlc_thread_join( p_this );

    /* Call the custom "subclass" destructor */
    if( p_priv->pf_destructor )
        p_priv->pf_destructor( p_this );

324
    /* Sanity checks */
325
326
    if( p_this->i_children )
    {
327
328
        int i;

329
330
331
332
        fprintf( stderr,
                 "ERROR: cannot delete object (%i, %s) with %d children\n",
                 p_this->i_object_id, p_this->psz_object_name,
                 p_this->i_children );
333
334
335

        for( i = 0; i < p_this->i_children; i++ )
        {
336
337
338
339
340
341
            fprintf( stderr,
                     "ERROR: Remaining children object "
                     "(id:%i, type:%s, name:%s)\n",
                     p_this->pp_children[i]->i_object_id,
                     p_this->pp_children[i]->psz_object_type,
                     p_this->pp_children[i]->psz_object_name );
342
        }
343
        fflush(stderr);
344

345
346
        /* Dump libvlc object to ease debugging */
        vlc_object_dump( p_this->p_libvlc );
347

348
        abort();
349
350
    }

Sam Hocevar's avatar
Sam Hocevar committed
351
352
    /* Destroy the associated variables, starting from the end so that
     * no memmove calls have to be done. */
353
    while( p_priv->i_vars )
Sam Hocevar's avatar
Sam Hocevar committed
354
    {
355
        var_Destroy( p_this, p_priv->p_vars[p_priv->i_vars - 1].psz_name );
Sam Hocevar's avatar
Sam Hocevar committed
356
357
    }

358
359
    free( p_priv->p_vars );
    vlc_mutex_destroy( &p_priv->var_lock );
Sam Hocevar's avatar
Sam Hocevar committed
360

361
    free( p_this->psz_header );
zorglub's avatar
Free    
zorglub committed
362

363
    if( p_this->p_libvlc == NULL )
364
    {
365
        libvlc_global_data_t *p_global = (libvlc_global_data_t *)p_this;
366

367
368
#ifndef NDEBUG
        assert( p_global == vlc_global() );
369
370
371
372
373
374
375
376
        /* Test for leaks */
        if( p_global->i_objects > 0 )
        {
            int i;
            for( i = 0; i < p_global->i_objects; i++ )
            {
                /* We are leaking this object */
                fprintf( stderr,
377
378
379
380
                         "ERROR: leaking object (id:%i, type:%s, name:%s)\n",
                         p_global->pp_objects[i]->i_object_id,
                         p_global->pp_objects[i]->psz_object_type,
                         p_global->pp_objects[i]->psz_object_name );
381
382
383
384

                /* Dump libvlc object to ease debugging */
                vlc_object_dump( p_global->pp_objects[i] );

385
386
                fflush(stderr);
            }
387
388
389
390

            /* Dump libvlc object to ease debugging */
            vlc_object_dump( p_this );

391
392
393
            /* Strongly abort, cause we want these to be fixed */
            abort();
        }
394
#endif
395

396
        /* We are the global object ... no need to lock. */
397
398
        free( p_global->pp_objects );
        p_global->pp_objects = NULL;
399
400
401

        vlc_mutex_destroy( &structure_lock );
    }
402

403
404
    FREENULL( p_this->psz_object_name );

405
406
#if defined(WIN32) || defined(UNDER_CE)
    /* if object has an associated thread, close it now */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
407
408
    if( p_priv->thread_id )
       CloseHandle(p_priv->thread_id);
409
410
#endif

411
    vlc_spin_destroy( &p_priv->ref_spin );
Sam Hocevar's avatar
Sam Hocevar committed
412
413
    vlc_mutex_destroy( &p_this->object_lock );
    vlc_cond_destroy( &p_this->object_wait );
414
    vlc_spin_destroy( &p_priv->spin );
415
416
    if( p_priv->pipes[1] != -1 )
        close( p_priv->pipes[1] );
417
418
    if( p_priv->pipes[0] != -1 )
        close( p_priv->pipes[0] );
Sam Hocevar's avatar
Sam Hocevar committed
419

420
    free( p_priv );
421
422
}

423

424
425
426
/** Inter-object signaling */

void __vlc_object_lock( vlc_object_t *obj )
427
{
428
429
    vlc_mutex_lock( &obj->object_lock );
}
430

431
432
void __vlc_object_unlock( vlc_object_t *obj )
{
Rémi Denis-Courmont's avatar
Typo    
Rémi Denis-Courmont committed
433
    vlc_assert_locked( &obj->object_lock );
434
435
    vlc_mutex_unlock( &obj->object_lock );
}
436

437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
#ifdef WIN32
# include <winsock2.h>
# include <ws2tcpip.h>

/**
 * select()-able pipes emulated using Winsock
 */
static int pipe (int fd[2])
{
    SOCKADDR_IN addr;
    int addrlen = sizeof (addr);

    SOCKET l = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP), a,
           c = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if ((l == INVALID_SOCKET) || (c == INVALID_SOCKET))
        goto error;

    memset (&addr, 0, sizeof (addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
    if (bind (l, (PSOCKADDR)&addr, sizeof (addr))
     || getsockname (l, (PSOCKADDR)&addr, &addrlen)
     || listen (l, 1)
     || connect (c, (PSOCKADDR)&addr, addrlen))
        goto error;

    a = accept (l, NULL, NULL);
    if (a == INVALID_SOCKET)
        goto error;

    closesocket (l);
468
469
    //shutdown (a, 0);
    //shutdown (c, 1);
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
    fd[0] = c;
    fd[1] = a;
    return 0;

error:
    if (l != INVALID_SOCKET)
        closesocket (l);
    if (c != INVALID_SOCKET)
        closesocket (c);
    return -1;
}

#undef  read
#define read( a, b, c )  recv (a, b, c, 0)
#undef  write
#define write( a, b, c ) send (a, b, c, 0)
#undef  close
#define close( a )       closesocket (a)
#endif /* WIN32 */

490
/**
491
492
493
494
 * Returns the readable end of a pipe that becomes readable once termination
 * of the object is requested (vlc_object_kill()).
 * This can be used to wake-up out of a select() or poll() event loop, such
 * typically when doing network I/O.
495
496
 *
 * Note that the pipe will remain the same for the lifetime of the object.
497
 * DO NOT read the pipe nor close it yourself. Ever.
498
 *
499
 * @param obj object that would be "killed"
500
501
 * @return a readable pipe descriptor, or -1 on error.
 */
502
int __vlc_object_waitpipe( vlc_object_t *obj )
503
{
504
    int pfd[2] = { -1, -1 };
505
    vlc_object_internals_t *internals = vlc_internals( obj );
506
    bool killed = false;
507

508
509
    vlc_spin_lock (&internals->spin);
    if (internals->pipes[0] == -1)
510
    {
511
512
513
        /* This can only ever happen if someone killed us without locking: */
        assert (internals->pipes[1] == -1);
        vlc_spin_unlock (&internals->spin);
514

515
        if (pipe (pfd))
516
            return -1;
517
518

        vlc_spin_lock (&internals->spin);
519
        if (internals->pipes[0] == -1)
520
521
522
        {
            internals->pipes[0] = pfd[0];
            internals->pipes[1] = pfd[1];
523
            pfd[0] = pfd[1] = -1;
524
        }
525
        killed = obj->b_die;
526
    }
527
    vlc_spin_unlock (&internals->spin);
528

529
530
531
532
533
534
535
536
537
    if (killed)
    {
        /* Race condition: vlc_object_kill() already invoked! */
        int fd;

        vlc_spin_lock (&internals->spin);
        fd = internals->pipes[1];
        internals->pipes[1] = -1;
        vlc_spin_unlock (&internals->spin);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
538
539

        msg_Dbg (obj, "waitpipe: object already dying");
540
541
        if (fd != -1)
            close (fd);
542
543
    }

544
545
546
547
548
    /* Race condition: two threads call pipe() - unlikely */
    if (pfd[0] != -1)
        close (pfd[0]);
    if (pfd[1] != -1)
        close (pfd[1]);
549

550
    return internals->pipes[0];
551
552
553
}


554
555
556
557
558
559
560
/**
 * Waits for the object to be signaled (using vlc_object_signal()).
 * If the object already has a signal pending, this function will return
 * immediately. It is asserted that the caller holds the object lock.
 *
 * @return true if the object is dying and should terminate.
 */
561
bool __vlc_object_wait( vlc_object_t *obj )
562
563
564
565
{
    vlc_assert_locked( &obj->object_lock );
    vlc_cond_wait( &obj->object_wait, &obj->object_lock );
    return obj->b_die;
566
567
568
}


569
570
571
572
573
574
575
576
577
578
579
/**
 * Waits for the object to be signaled (using vlc_object_signal()), or for
 * a timer to expire.
 * If the object already has a signal pending, this function will return
 * immediately. It is asserted that the caller holds the object lock.
 *
 * @return negative if the object is dying and should terminate,
 * positive if the the object has been signaled but is not dying,
 * 0 if timeout has been reached.
 */
int __vlc_object_timedwait( vlc_object_t *obj, mtime_t deadline )
580
{
581
582
583
584
585
586
587
588
589
590
    int v;

    vlc_assert_locked( &obj->object_lock );
    v = vlc_cond_timedwait( &obj->object_wait, &obj->object_lock, deadline );
    if( v == 0 ) /* signaled */
        return obj->b_die ? -1 : 1;
    return 0;
}


591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
/**
 * Checks whether an object has been "killed".
 * The object lock must be held.
 *
 * Typical code for an object thread could be:
 *
   vlc_object_lock (self);
   ...initialization...
   while (vlc_object_alive (self))
   {
       ...preprocessing...

       if (vlc_object_wait (self))
           continue;

       ...postprocessing...
   }
   ...deinitialization...
   vlc_object_unlock (self);
 *
 *
 * @return true iff the object has not been killed yet
 */
614
bool __vlc_object_alive( vlc_object_t *obj )
615
616
617
618
619
620
{
    vlc_assert_locked( &obj->object_lock );
    return !obj->b_die;
}


621
622
623
624
625
/**
 * Signals an object for which the lock is held.
 */
void __vlc_object_signal_unlocked( vlc_object_t *obj )
{
626
    vlc_assert_locked (&obj->object_lock);
627
628
629
630
631
632
633
634
635
    vlc_cond_signal( &obj->object_wait );
}


/**
 * Requests termination of an object.
 * If the object is LibVLC, also request to terminate all its children.
 */
void __vlc_object_kill( vlc_object_t *p_this )
636
{
637
    vlc_object_internals_t *internals = vlc_internals( p_this );
638
639
    int fd;

640
    vlc_mutex_lock( &p_this->object_lock );
641
    p_this->b_die = true;
642

643
644
645
646
647
648
    vlc_spin_lock (&internals->spin);
    fd = internals->pipes[1];
    internals->pipes[1] = -1;
    vlc_spin_unlock (&internals->spin);

    if( fd != -1 )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
649
650
    {
        msg_Dbg (p_this, "waitpipe: object killed");
651
        close (fd);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
652
    }
653

654
655
656
657
658
659
    if( p_this->i_object_type == VLC_OBJECT_LIBVLC )
        for( int i = 0; i < p_this->i_children ; i++ )
            vlc_object_kill( p_this->pp_children[i] );

    vlc_object_signal_unlocked( p_this );
    vlc_mutex_unlock( &p_this->object_lock );
660
661
662
}


zorglub's avatar
zorglub committed
663
664
665
/**
 * find an object given its ID
 *
Sam Hocevar's avatar
Sam Hocevar committed
666
667
668
 * This function looks for the object whose i_object_id field is i_id. We
 * use a dichotomy so that lookups are in log2(n).
 *****************************************************************************/
669
void * vlc_object_get( int i_id )
Sam Hocevar's avatar
Sam Hocevar committed
670
671
672
{
    int i_max, i_middle;
    vlc_object_t **pp_objects;
673
    libvlc_global_data_t *p_libvlc_global = vlc_global();
674
    vlc_object_t *obj = NULL;
Sam Hocevar's avatar
Sam Hocevar committed
675
676
677

    vlc_mutex_lock( &structure_lock );

678
    pp_objects = p_libvlc_global->pp_objects;
Sam Hocevar's avatar
Sam Hocevar committed
679
680

    /* Perform our dichotomy */
681
    for( i_max = p_libvlc_global->i_objects - 1 ; ; )
Sam Hocevar's avatar
Sam Hocevar committed
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
    {
        i_middle = i_max / 2;

        if( pp_objects[i_middle]->i_object_id > i_id )
        {
            i_max = i_middle;
        }
        else if( pp_objects[i_middle]->i_object_id < i_id )
        {
            if( i_middle )
            {
                pp_objects += i_middle;
                i_max -= i_middle;
            }
            else
            {
                /* This happens when there are only two remaining objects */
699
                if( pp_objects[i_middle+1]->i_object_id == i_id )
Sam Hocevar's avatar
Sam Hocevar committed
700
                {
701
                    vlc_object_yield( pp_objects[i_middle+1] );
702
                    obj = pp_objects[i_middle+1];
Sam Hocevar's avatar
Sam Hocevar committed
703
704
705
706
                }
                break;
            }
        }
707
        else
Sam Hocevar's avatar
Sam Hocevar committed
708
        {
709
            vlc_object_yield( pp_objects[i_middle] );
710
711
            obj = pp_objects[i_middle];
            break;
Sam Hocevar's avatar
Sam Hocevar committed
712
713
714
715
        }
    }

    vlc_mutex_unlock( &structure_lock );
716
    return obj;
Sam Hocevar's avatar
Sam Hocevar committed
717
718
}

zorglub's avatar
zorglub committed
719
720
721
/**
 ****************************************************************************
 * find a typed object and increment its refcount
722
723
724
725
 *****************************************************************************
 * This function recursively looks for a given object type. i_mode can be one
 * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
 *****************************************************************************/
726
727
728
729
730
void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
{
    vlc_object_t *p_found;

    /* If we are of the requested type ourselves, don't look further */
731
    if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
732
    {
733
        vlc_object_yield( p_this );
734
735
736
        return p_this;
    }

737
738
    vlc_mutex_lock( &structure_lock );

739
    /* Otherwise, recursively look for the object */
740
741
    if( (i_mode & 0x000f) == FIND_ANYWHERE )
    {
742
743
744
745
        vlc_object_t *p_root = p_this;

        /* Find the root */
        while( p_root->p_parent != NULL &&
746
               p_root != VLC_OBJECT( p_this->p_libvlc ) )
747
748
749
750
751
        {
            p_root = p_root->p_parent;
        }

        p_found = FindObject( p_root, i_type, (i_mode & ~0x000f)|FIND_CHILD );
752
        if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
753
        {
754
            p_found = FindObject( VLC_OBJECT( p_this->p_libvlc ),
755
756
                                  i_type, (i_mode & ~0x000f)|FIND_CHILD );
        }
757
758
759
    }
    else
    {
760
        p_found = FindObject( p_this, i_type, i_mode );
761
    }
762

763
    vlc_mutex_unlock( &structure_lock );
764
765
766
767

    return p_found;
}

768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
/**
 ****************************************************************************
 * find a named object and increment its refcount
 *****************************************************************************
 * This function recursively looks for a given object name. i_mode can be one
 * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
 *****************************************************************************/
void * __vlc_object_find_name( vlc_object_t *p_this, const char *psz_name,
                               int i_mode )
{
    vlc_object_t *p_found;

    /* If have the requested name ourselves, don't look further */
    if( !(i_mode & FIND_STRICT)
        && p_this->psz_object_name
783
        && !strcmp( p_this->psz_object_name, psz_name ) )
784
    {
785
        vlc_object_yield( p_this );
786
787
788
        return p_this;
    }

789
790
    vlc_mutex_lock( &structure_lock );

791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
    /* Otherwise, recursively look for the object */
    if( (i_mode & 0x000f) == FIND_ANYWHERE )
    {
        vlc_object_t *p_root = p_this;

        /* Find the root */
        while( p_root->p_parent != NULL &&
               p_root != VLC_OBJECT( p_this->p_libvlc ) )
        {
            p_root = p_root->p_parent;
        }

        p_found = FindObjectName( p_root, psz_name,
                                 (i_mode & ~0x000f)|FIND_CHILD );
        if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
        {
            p_found = FindObjectName( VLC_OBJECT( p_this->p_libvlc ),
                                      psz_name, (i_mode & ~0x000f)|FIND_CHILD );
        }
    }
    else
    {
        p_found = FindObjectName( p_this, psz_name, i_mode );
    }

    vlc_mutex_unlock( &structure_lock );

    return p_found;
}

zorglub's avatar
zorglub committed
821
/**
822
823
824
 * Increment an object reference counter.
 */
void __vlc_object_yield( vlc_object_t *p_this )
Pierre's avatar
Pierre committed
825
{
826
    vlc_object_internals_t *internals = vlc_internals( p_this );
827

828
    vlc_spin_lock( &internals->ref_spin );
Pierre's avatar
Pierre committed
829
    /* Avoid obvious freed object uses */
830
    assert( internals->i_refcount > 0 );
Pierre's avatar
Pierre committed
831
    /* Increment the counter */
832
833
    internals->i_refcount++;
    vlc_spin_unlock( &internals->ref_spin );
834
835
}

836
/*****************************************************************************
zorglub's avatar
zorglub committed
837
 * decrement an object refcount
838
 * And destroy the object if its refcount reach zero.
839
 *****************************************************************************/
840
841
void __vlc_object_release( vlc_object_t *p_this )
{
842
    vlc_object_internals_t *internals = vlc_internals( p_this );
843
    bool b_should_destroy;
844

845
846
    vlc_spin_lock( &internals->ref_spin );
    assert( internals->i_refcount > 0 );
847

848
    if( internals->i_refcount > 1 )
849
850
851
    {
        /* Fast path */
        /* There are still other references to the object */
852
        internals->i_refcount--;
853
854
855
856
857
        vlc_spin_unlock( &internals->ref_spin );
        return;
    }
    vlc_spin_unlock( &internals->ref_spin );

858
    /* Slow path */
859
860
    /* Remember that we cannot hold the spin while waiting on the mutex */
    vlc_mutex_lock( &structure_lock );
861
862
863
864
865
    /* Take the spin again. Note that another thread may have yielded the
     * object in the (very short) mean time. */
    vlc_spin_lock( &internals->ref_spin );
    b_should_destroy = --internals->i_refcount == 0;
    vlc_spin_unlock( &internals->ref_spin );
866

867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
    if( b_should_destroy )
    {
        /* Remove the object from the table
         * so that it cannot be encountered by vlc_object_get() */
        libvlc_global_data_t *p_libvlc_global = vlc_global();
        int i_index;

        i_index = FindIndex( p_this, p_libvlc_global->pp_objects,
                             p_libvlc_global->i_objects );
        REMOVE_ELEM( p_libvlc_global->pp_objects,
                     p_libvlc_global->i_objects, i_index );

        /* Detach from parent to protect against FIND_CHILDREN */
        if (p_this->p_parent)
            vlc_object_detach_unlocked (p_this);
        /* Detach from children to protect against FIND_PARENT */
        for (int i = 0; i < p_this->i_children; i++)
            p_this->pp_children[i]->p_parent = NULL;
    }
886

887
    vlc_mutex_unlock( &structure_lock );
888

889
890
    if( b_should_destroy )
        vlc_object_destroy( p_this );
891
892
}

zorglub's avatar
zorglub committed
893
894
895
/**
 ****************************************************************************
 * attach object to a parent object
896
897
898
899
900
901
 *****************************************************************************
 * This function sets p_this as a child of p_parent, and p_parent as a parent
 * of p_this. This link can be undone using vlc_object_detach.
 *****************************************************************************/
void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
{
902
903
    if( !p_this ) return;

904
    vlc_mutex_lock( &structure_lock );
905

906
    /* Attach the parent to its child */
907
    assert (!p_this->p_parent);
908
    p_this->p_parent = p_parent;
909

910
    /* Attach the child to its parent */
911
912
    INSERT_ELEM( p_parent->pp_children, p_parent->i_children,
                 p_parent->i_children, p_this );
913

914
    vlc_mutex_unlock( &structure_lock );
915
916
}

917
918
919
920
921

static void vlc_object_detach_unlocked (vlc_object_t *p_this)
{
    assert (p_this->p_parent);

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
    vlc_object_t *p_parent = p_this->p_parent;
    int i_index, i;

    /* Remove p_this's parent */
    p_this->p_parent = NULL;

    /* Remove all of p_parent's children which are p_this */
    for( i_index = p_parent->i_children ; i_index-- ; )
    {
        if( p_parent->pp_children[i_index] == p_this )
        {
            p_parent->i_children--;
            for( i = i_index ; i < p_parent->i_children ; i++ )
            {
                p_parent->pp_children[i] = p_parent->pp_children[i+1];
            }
        }
    }

    if( p_parent->i_children )
    {
        p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
                               p_parent->i_children * sizeof(vlc_object_t *) );
    }
    else
    {
        /* Special case - don't realloc() to zero to avoid leaking */
        free( p_parent->pp_children );
        p_parent->pp_children = NULL;
    }
952
953
954
}


zorglub's avatar
zorglub committed
955
956
957
/**
 ****************************************************************************
 * detach object from its parent
958
 *****************************************************************************
959
 * This function removes all links between an object and its parent.
960
 *****************************************************************************/
961
void __vlc_object_detach( vlc_object_t *p_this )
962
{
963
964
    if( !p_this ) return;

965
    vlc_mutex_lock( &structure_lock );
Pierre's avatar
Pierre committed
966

967
    if( !p_this->p_parent )
968
    {
969
        msg_Err( p_this, "object is not attached" );
970
        vlc_mutex_unlock( &structure_lock );
971
        return;
972
973
    }

974
    vlc_object_detach_unlocked( p_this );
975
    vlc_mutex_unlock( &structure_lock );
976
977
}

978

zorglub's avatar
zorglub committed
979
980
981
/**
 ****************************************************************************
 * find a list typed objects and increment their refcount
982
983
984
985
 *****************************************************************************
 * This function recursively looks for a given object type. i_mode can be one
 * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
 *****************************************************************************/
986
vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
987
{
988
    vlc_list_t *p_list;
989
    int i_count = 0;
990
991

    /* Look for the objects */
gbazin's avatar
   
gbazin committed
992
    switch( i_mode & 0x000f )
993
    {
gbazin's avatar
   
gbazin committed
994
    case FIND_ANYWHERE:
995
        return vlc_list_find (vlc_global (), i_type, FIND_CHILD);
gbazin's avatar
   
gbazin committed
996
997

    case FIND_CHILD:
998
        vlc_mutex_lock( &structure_lock );
gbazin's avatar
   
gbazin committed
999
        i_count = CountChildren( p_this, i_type );
1000
        p_list = NewList( i_count );
gbazin's avatar
   
gbazin committed
1001
1002

        /* Check allocation was successful */
1003
        if( p_list->i_count != i_count )
gbazin's avatar
   
gbazin committed
1004
1005
        {
            msg_Err( p_this, "list allocation failed!" );
1006
            p_list->i_count = 0;
gbazin's avatar
   
gbazin committed
1007
1008
1009
            break;
        }

1010
1011
        p_list->i_count = 0;
        ListChildren( p_list, p_this, i_type );
1012
        vlc_mutex_unlock( &structure_lock );
gbazin's avatar
   
gbazin committed
1013
1014
1015
        break;

    default:
1016
        msg_Err( p_this, "unimplemented!" );
1017
        p_list = NewList( 0 );
gbazin's avatar
   
gbazin committed
1018
        break;
1019
1020
    }

1021
    return p_list;
1022
1023
}

1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
/**
 * Gets the list of children of an objects, and increment their reference
 * count.
 * @return a list (possibly empty) or NULL in case of error.
 */
vlc_list_t *__vlc_list_children( vlc_object_t *obj )
{
    vlc_list_t *l;

    vlc_mutex_lock( &structure_lock );
    l = NewList( obj->i_children );
    for (int i = 0; i < l->i_count; i++)
    {
        vlc_object_yield( obj->pp_children[i] );
        l->p_values[i].p_object = obj->pp_children[i];
    }
    vlc_mutex_unlock( &structure_lock );
    return l;
}

1044
/*****************************************************************************
1045
 * DumpCommand: print the current vlc structure
1046
 *****************************************************************************
1047
1048
1049
 * This function prints either an ASCII tree showing the connections between
 * vlc objects, and additional information such as their refcount, thread ID,
 * etc. (command "tree"), or the same data as a simple list (command "list").
1050
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
1051
1052
static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
1053
{
1054
    libvlc_global_data_t *p_libvlc_global = vlc_global();
1055

1056
    (void)oldval; (void)p_data;
1057
    if( *psz_cmd == 'l' )
1058
    {
1059
1060
1061
1062
        vlc_mutex_lock( &structure_lock );

        vlc_object_t **pp_current, **pp_end;

1063
1064
        pp_current = p_libvlc_global->pp_objects;
        pp_end = pp_current + p_libvlc_global->i_objects;
1065
1066

        for( ; pp_current < pp_end ; pp_current++ )
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
1067
            PrintObject( *pp_current, "" );
1068
1069
1070
1071
1072
1073

        vlc_mutex_unlock( &structure_lock );
    }
    else
    {
        vlc_object_t *p_object = NULL;
1074

gbazin's avatar
   
gbazin committed
1075
        if( *newval.psz_string )
Sam Hocevar's avatar