~ubuntu-branches/ubuntu/maverick/vlc/maverick

« back to all changes in this revision

Viewing changes to src/misc/objects.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2008-09-17 21:56:14 UTC
  • mfrom: (1.1.17 upstream)
  • Revision ID: james.westby@ubuntu.com-20080917215614-tj0vx8xzd57e52t8
Tags: 0.9.2-1ubuntu1
* New Upstream Release, exception granted by
    - dktrkranz, norsetto, Hobbsee (via irc). LP: #270404

Changes done in ubuntu:

* add libxul-dev to build-depends
* make sure that vlc is build against libxul in configure. This doesn't
  change anything in the package, but makes it more robust if building
  in an 'unclean' chroot or when modifying the package.
* debian/control: make Vcs-* fields point to the motumedia branch
* add libx264-dev and libass-dev to build-depends
  LP: #210354, #199870
* actually enable libass support by passing --enable-libass to configure
* enable libdca: add libdca-dev to build depends and --enable-libdca
* install the x264 plugin.

Changes already in the pkg-multimedia branch in debian:

* don't install usr/share/vlc/mozilla in debian/mozilla-plugin-vlc.install  
* new upstream .desktop file now registers flash video mimetype LP: #261567
* add Xb-Npp-Applications to mozilla-plugin-vlc
* remove duplicate entries in debian/vlc-nox.install

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 * objects.c: vlc_object_t handling
3
3
 *****************************************************************************
4
 
 * Copyright (C) 2004 the VideoLAN team
5
 
 * $Id: 24786124c515b8fb1b3fa83d5a439b133fcd8a44 $
 
4
 * Copyright (C) 2004-2008 the VideoLAN team
6
5
 *
7
6
 * Authors: Samuel Hocevar <sam@zoy.org>
8
7
 *
30
29
/*****************************************************************************
31
30
 * Preamble
32
31
 *****************************************************************************/
33
 
#include <vlc/vlc.h>
34
 
#include <vlc/input.h>
35
 
 
36
 
#ifdef HAVE_STDLIB_H
37
 
#   include <stdlib.h>                                          /* realloc() */
 
32
#ifdef HAVE_CONFIG_H
 
33
# include "config.h"
38
34
#endif
39
35
 
40
 
#include "vlc_video.h"
41
 
#include "video_output.h"
42
 
#include "vlc_spu.h"
43
 
 
44
 
#include "audio_output.h"
45
 
#include "aout_internal.h"
46
 
#include "stream_output.h"
47
 
 
48
 
#include "vlc_playlist.h"
 
36
#include <vlc_common.h>
 
37
 
 
38
#include "../libvlc.h"
 
39
#include <vlc_vout.h>
 
40
#include <vlc_aout.h>
 
41
#include "audio_output/aout_internal.h"
 
42
 
 
43
#include <vlc_access.h>
 
44
#include <vlc_demux.h>
 
45
#include <vlc_stream.h>
 
46
 
 
47
#include <vlc_sout.h>
 
48
#include "stream_output/stream_output.h"
 
49
 
49
50
#include "vlc_interface.h"
50
51
#include "vlc_codec.h"
51
52
#include "vlc_filter.h"
52
53
 
53
 
#include "vlc_httpd.h"
54
 
#include "vlc_vlm.h"
55
 
#include "vlc_vod.h"
56
 
#include "vlc_tls.h"
57
 
#include "vlc_xml.h"
58
 
#include "vlc_osd.h"
 
54
#include "variables.h"
 
55
#ifndef WIN32
 
56
# include <unistd.h>
 
57
#else
 
58
# include <io.h>
 
59
# include <fcntl.h>
 
60
# include <errno.h> /* ENOSYS */
 
61
#endif
 
62
#include <assert.h>
59
63
 
60
64
/*****************************************************************************
61
65
 * Local prototypes
64
68
                         vlc_value_t, vlc_value_t, void * );
65
69
 
66
70
static vlc_object_t * FindObject    ( vlc_object_t *, int, int );
67
 
static void           DetachObject  ( vlc_object_t * );
 
71
static vlc_object_t * FindObjectName( vlc_object_t *, const char *, int );
68
72
static void           PrintObject   ( vlc_object_t *, const char * );
69
73
static void           DumpStructure ( vlc_object_t *, int, char * );
70
 
static int            FindIndex     ( vlc_object_t *, vlc_object_t **, int );
71
 
static void           SetAttachment ( vlc_object_t *, vlc_bool_t );
72
74
 
73
75
static vlc_list_t   * NewList       ( int );
74
76
static void           ListReplace   ( vlc_list_t *, vlc_object_t *, int );
76
78
static int            CountChildren ( vlc_object_t *, int );
77
79
static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
78
80
 
 
81
static void vlc_object_destroy( vlc_object_t *p_this );
 
82
static void vlc_object_detach_unlocked (vlc_object_t *p_this);
 
83
 
 
84
#ifdef LIBVLC_REFCHECK
 
85
static vlc_threadvar_t held_objects;
 
86
typedef struct held_list_t
 
87
{
 
88
    struct held_list_t *next;
 
89
    vlc_object_t *obj;
 
90
} held_list_t;
 
91
static void held_objects_destroy (void *);
 
92
#endif
 
93
 
79
94
/*****************************************************************************
80
95
 * Local structure lock
81
96
 *****************************************************************************/
82
 
static vlc_mutex_t    structure_lock;
83
 
 
84
 
/*****************************************************************************
85
 
 * vlc_object_create: initialize a vlc object
86
 
 *****************************************************************************
87
 
 * This function allocates memory for a vlc object and initializes it. If
88
 
 * i_type is not a known value such as VLC_OBJECT_ROOT, VLC_OBJECT_VOUT and
89
 
 * so on, vlc_object_create will use its value for the object size.
90
 
 *****************************************************************************/
 
97
static vlc_mutex_t structure_lock;
 
98
static unsigned    object_counter = 0;
 
99
 
 
100
void *__vlc_custom_create( vlc_object_t *p_this, size_t i_size,
 
101
                           int i_type, const char *psz_type )
 
102
{
 
103
    vlc_object_t *p_new;
 
104
    vlc_object_internals_t *p_priv;
 
105
 
 
106
    /* NOTE:
 
107
     * VLC objects are laid out as follow:
 
108
     * - first the LibVLC-private per-object data,
 
109
     * - then VLC_COMMON members from vlc_object_t,
 
110
     * - finally, the type-specific data (if any).
 
111
     *
 
112
     * This function initializes the LibVLC and common data,
 
113
     * and zeroes the rest.
 
114
     */
 
115
    p_priv = calloc( 1, sizeof( *p_priv ) + i_size );
 
116
    if( p_priv == NULL )
 
117
        return NULL;
 
118
 
 
119
    assert (i_size >= sizeof (vlc_object_t));
 
120
    p_new = (vlc_object_t *)(p_priv + 1);
 
121
 
 
122
    p_new->i_object_type = i_type;
 
123
    p_new->psz_object_type = psz_type;
 
124
    p_new->psz_object_name = NULL;
 
125
 
 
126
    p_new->b_die = false;
 
127
    p_new->b_error = false;
 
128
    p_new->b_dead = false;
 
129
    p_new->b_force = false;
 
130
 
 
131
    p_new->psz_header = NULL;
 
132
 
 
133
    if (p_this)
 
134
        p_new->i_flags = p_this->i_flags
 
135
            & (OBJECT_FLAGS_NODBG|OBJECT_FLAGS_QUIET|OBJECT_FLAGS_NOINTERACT);
 
136
 
 
137
    p_priv->p_vars = calloc( sizeof( variable_t ), 16 );
 
138
 
 
139
    if( !p_priv->p_vars )
 
140
    {
 
141
        free( p_priv );
 
142
        return NULL;
 
143
    }
 
144
 
 
145
    libvlc_global_data_t *p_libvlc_global;
 
146
    if( p_this == NULL )
 
147
    {
 
148
        /* Only the global root object is created out of the blue */
 
149
        p_libvlc_global = (libvlc_global_data_t *)p_new;
 
150
        p_new->p_libvlc = NULL;
 
151
 
 
152
        object_counter = 0; /* reset */
 
153
        p_priv->next = p_priv->prev = p_new;
 
154
        vlc_mutex_init( &structure_lock );
 
155
#ifdef LIBVLC_REFCHECK
 
156
        /* TODO: use the destruction callback to track ref leaks */
 
157
        vlc_threadvar_create( &held_objects, held_objects_destroy );
 
158
#endif
 
159
    }
 
160
    else
 
161
    {
 
162
        p_libvlc_global = vlc_global();
 
163
        if( i_type == VLC_OBJECT_LIBVLC )
 
164
            p_new->p_libvlc = (libvlc_int_t*)p_new;
 
165
        else
 
166
            p_new->p_libvlc = p_this->p_libvlc;
 
167
    }
 
168
 
 
169
    vlc_spin_init( &p_priv->ref_spin );
 
170
    p_priv->i_refcount = 1;
 
171
    p_priv->pf_destructor = NULL;
 
172
    p_priv->b_thread = false;
 
173
    p_new->p_parent = NULL;
 
174
    p_priv->pp_children = NULL;
 
175
    p_priv->i_children = 0;
 
176
 
 
177
    p_new->p_private = NULL;
 
178
 
 
179
    /* Initialize mutexes and condvars */
 
180
    vlc_mutex_init( &p_priv->lock );
 
181
    vlc_cond_init( p_new, &p_priv->wait );
 
182
    vlc_mutex_init( &p_priv->var_lock );
 
183
    vlc_spin_init( &p_priv->spin );
 
184
    p_priv->pipes[0] = p_priv->pipes[1] = -1;
 
185
 
 
186
    p_priv->next = VLC_OBJECT (p_libvlc_global);
 
187
#if !defined (LIBVLC_REFCHECK)
 
188
    /* ... */
 
189
#elif defined (LIBVLC_USE_PTHREAD)
 
190
    p_priv->creator_id = pthread_self ();
 
191
#elif defined (WIN32)
 
192
    p_priv->creator_id = GetCurrentThreadId ();
 
193
#endif
 
194
    vlc_mutex_lock( &structure_lock );
 
195
    p_priv->prev = vlc_internals (p_libvlc_global)->prev;
 
196
    vlc_internals (p_libvlc_global)->prev = p_new;
 
197
    vlc_internals (p_priv->prev)->next = p_new;
 
198
    p_new->i_object_id = object_counter++; /* fetch THEN increment */
 
199
    vlc_mutex_unlock( &structure_lock );
 
200
 
 
201
    if( i_type == VLC_OBJECT_LIBVLC )
 
202
    {
 
203
        var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
 
204
        var_AddCallback( p_new, "list", DumpCommand, NULL );
 
205
        var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
 
206
        var_AddCallback( p_new, "tree", DumpCommand, NULL );
 
207
        var_Create( p_new, "vars", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
 
208
        var_AddCallback( p_new, "vars", DumpCommand, NULL );
 
209
    }
 
210
 
 
211
    return p_new;
 
212
}
 
213
 
91
214
 
92
215
/**
93
 
 * Initialize a vlc object
94
 
 *
95
 
 * This function allocates memory for a vlc object and initializes it. If
96
 
 * i_type is not a known value such as VLC_OBJECT_ROOT, VLC_OBJECT_VOUT and
97
 
 * so on, vlc_object_create will use its value for the object size.
 
216
 * Allocates and initializes a vlc object.
 
217
 *
 
218
 * @param i_type known object type (all of them are negative integer values),
 
219
 *               or object byte size (always positive).
 
220
 *
 
221
 * @return the new object, or NULL on error.
98
222
 */
99
223
void * __vlc_object_create( vlc_object_t *p_this, int i_type )
100
224
{
101
 
    vlc_object_t * p_new;
102
225
    const char   * psz_type;
103
226
    size_t         i_size;
104
227
 
105
228
    switch( i_type )
106
229
    {
107
 
        case VLC_OBJECT_ROOT:
108
 
            i_size = sizeof(libvlc_t);
109
 
            psz_type = "root";
110
 
            break;
111
 
        case VLC_OBJECT_VLC:
112
 
            i_size = sizeof(vlc_t);
113
 
            psz_type = "vlc";
114
 
            break;
115
 
        case VLC_OBJECT_MODULE:
116
 
            i_size = sizeof(module_t);
117
 
            psz_type = "module";
118
 
            break;
119
230
        case VLC_OBJECT_INTF:
120
231
            i_size = sizeof(intf_thread_t);
121
232
            psz_type = "interface";
122
233
            break;
123
 
        case VLC_OBJECT_DIALOGS:
124
 
            i_size = sizeof(intf_thread_t);
125
 
            psz_type = "dialogs";
126
 
            break;
127
 
        case VLC_OBJECT_PLAYLIST:
128
 
            i_size = sizeof(playlist_t);
129
 
            psz_type = "playlist";
130
 
            break;
131
 
        case VLC_OBJECT_SD:
132
 
            i_size = sizeof(services_discovery_t);
133
 
            psz_type = "services discovery";
134
 
            break;
135
 
        case VLC_OBJECT_INPUT:
136
 
            i_size = sizeof(input_thread_t);
137
 
            psz_type = "input";
138
 
            break;
139
 
        case VLC_OBJECT_DEMUX:
140
 
            i_size = sizeof(demux_t);
141
 
            psz_type = "demux";
142
 
            break;
143
 
        case VLC_OBJECT_STREAM:
144
 
            i_size = sizeof(stream_t);
145
 
            psz_type = "stream";
146
 
            break;
147
 
        case VLC_OBJECT_ACCESS:
148
 
            i_size = sizeof(access_t);
149
 
            psz_type = "access";
150
 
            break;
151
234
        case VLC_OBJECT_DECODER:
152
235
            i_size = sizeof(decoder_t);
153
236
            psz_type = "decoder";
160
243
            i_size = sizeof(encoder_t);
161
244
            psz_type = "encoder";
162
245
            break;
163
 
        case VLC_OBJECT_FILTER:
164
 
            i_size = sizeof(filter_t);
165
 
            psz_type = "filter";
166
 
            break;
167
 
        case VLC_OBJECT_VOUT:
168
 
            i_size = sizeof(vout_thread_t);
169
 
            psz_type = "video output";
170
 
            break;
171
 
        case VLC_OBJECT_SPU:
172
 
            i_size = sizeof(spu_t);
173
 
            psz_type = "subpicture";
174
 
            break;
175
246
        case VLC_OBJECT_AOUT:
176
247
            i_size = sizeof(aout_instance_t);
177
248
            psz_type = "audio output";
178
249
            break;
179
 
        case VLC_OBJECT_SOUT:
180
 
            i_size = sizeof(sout_instance_t);
181
 
            psz_type = "stream output";
182
 
            break;
183
 
        case VLC_OBJECT_HTTPD:
184
 
            i_size = sizeof( httpd_t );
185
 
            psz_type = "http server";
186
 
            break;
187
 
        case VLC_OBJECT_HTTPD_HOST:
188
 
            i_size = sizeof( httpd_host_t );
189
 
            psz_type = "http server";
190
 
            break;
191
 
        case VLC_OBJECT_VLM:
192
 
            i_size = sizeof( vlm_t );
193
 
            psz_type = "vlm dameon";
194
 
            break;
195
 
        case VLC_OBJECT_VOD:
196
 
            i_size = sizeof( vod_t );
197
 
            psz_type = "vod server";
198
 
            break;
199
 
        case VLC_OBJECT_TLS:
200
 
            i_size = sizeof( tls_t );
201
 
            psz_type = "tls";
202
 
            break;
203
 
        case VLC_OBJECT_XML:
204
 
            i_size = sizeof( xml_t );
205
 
            psz_type = "xml";
206
 
            break;
207
250
        case VLC_OBJECT_OPENGL:
208
251
            i_size = sizeof( vout_thread_t );
209
252
            psz_type = "opengl";
212
255
            i_size = sizeof( announce_handler_t );
213
256
            psz_type = "announce";
214
257
            break;
215
 
        case VLC_OBJECT_OSDMENU:
216
 
            i_size = sizeof( osd_menu_t );
217
 
            psz_type = "osd menu";
218
 
            break;
219
 
        case VLC_OBJECT_STATS:
220
 
            i_size = sizeof( stats_handler_t );
221
 
            psz_type = "statistics";
222
 
            break;
223
258
        default:
224
 
            i_size = i_type > (int)sizeof(vlc_object_t)
225
 
                         ? i_type : (int)sizeof(vlc_object_t);
 
259
            assert( i_type > 0 ); /* unknown type?! */
 
260
            i_size = i_type;
226
261
            i_type = VLC_OBJECT_GENERIC;
227
262
            psz_type = "generic";
228
263
            break;
229
264
    }
230
265
 
231
 
    if( i_type == VLC_OBJECT_ROOT )
232
 
    {
233
 
        p_new = p_this;
234
 
    }
235
 
    else
236
 
    {
237
 
        p_new = malloc( i_size );
238
 
        if( !p_new ) return NULL;
239
 
        memset( p_new, 0, i_size );
240
 
    }
241
 
 
242
 
    p_new->i_object_type = i_type;
243
 
    p_new->psz_object_type = psz_type;
244
 
 
245
 
    p_new->psz_object_name = NULL;
246
 
 
247
 
    p_new->b_die = VLC_FALSE;
248
 
    p_new->b_error = VLC_FALSE;
249
 
    p_new->b_dead = VLC_FALSE;
250
 
    p_new->b_attached = VLC_FALSE;
251
 
    p_new->b_force = VLC_FALSE;
252
 
 
253
 
    p_new->psz_header = NULL;
254
 
 
255
 
    p_new->i_flags = 0;
256
 
    if( p_this->i_flags & OBJECT_FLAGS_NODBG )
257
 
        p_new->i_flags |= OBJECT_FLAGS_NODBG;
258
 
    if( p_this->i_flags & OBJECT_FLAGS_QUIET )
259
 
        p_new->i_flags |= OBJECT_FLAGS_QUIET;
260
 
    if( p_this->i_flags & OBJECT_FLAGS_NOINTERACT )
261
 
        p_new->i_flags |= OBJECT_FLAGS_NOINTERACT;
262
 
 
263
 
    p_new->i_vars = 0;
264
 
    p_new->p_vars = (variable_t *)malloc( 16 * sizeof( variable_t ) );
265
 
 
266
 
    if( !p_new->p_vars )
267
 
    {
268
 
        if( i_type != VLC_OBJECT_ROOT )
269
 
            free( p_new );
270
 
        return NULL;
271
 
    }
272
 
 
273
 
    if( i_type == VLC_OBJECT_ROOT )
274
 
    {
275
 
        /* If i_type is root, then p_new is actually p_libvlc */
276
 
        p_new->p_libvlc = (libvlc_t*)p_new;
277
 
        p_new->p_vlc = NULL;
278
 
 
279
 
        p_new->p_libvlc->i_counter = 0;
280
 
        p_new->i_object_id = 0;
281
 
 
282
 
        p_new->p_libvlc->i_objects = 1;
283
 
        p_new->p_libvlc->pp_objects = malloc( sizeof(vlc_object_t *) );
284
 
        p_new->p_libvlc->pp_objects[0] = p_new;
285
 
        p_new->b_attached = VLC_TRUE;
286
 
    }
287
 
    else
288
 
    {
289
 
        p_new->p_libvlc = p_this->p_libvlc;
290
 
        p_new->p_vlc = ( i_type == VLC_OBJECT_VLC ) ? (vlc_t*)p_new
291
 
                                                    : p_this->p_vlc;
292
 
 
293
 
        vlc_mutex_lock( &structure_lock );
294
 
 
295
 
        p_new->p_libvlc->i_counter++;
296
 
        p_new->i_object_id = p_new->p_libvlc->i_counter;
297
 
 
298
 
        /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
299
 
         * useless to try and recover anything if pp_objects gets smashed. */
300
 
        INSERT_ELEM( p_new->p_libvlc->pp_objects,
301
 
                     p_new->p_libvlc->i_objects,
302
 
                     p_new->p_libvlc->i_objects,
303
 
                     p_new );
304
 
 
305
 
        vlc_mutex_unlock( &structure_lock );
306
 
    }
307
 
 
308
 
    p_new->i_refcount = 0;
309
 
    p_new->p_parent = NULL;
310
 
    p_new->pp_children = NULL;
311
 
    p_new->i_children = 0;
312
 
 
313
 
    p_new->p_private = NULL;
314
 
 
315
 
    /* Initialize mutexes and condvars */
316
 
    vlc_mutex_init( p_new, &p_new->object_lock );
317
 
    vlc_cond_init( p_new, &p_new->object_wait );
318
 
    vlc_mutex_init( p_new, &p_new->var_lock );
319
 
 
320
 
    if( i_type == VLC_OBJECT_ROOT )
321
 
    {
322
 
        vlc_mutex_init( p_new, &structure_lock );
323
 
 
324
 
        var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
325
 
        var_AddCallback( p_new, "list", DumpCommand, NULL );
326
 
        var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
327
 
        var_AddCallback( p_new, "tree", DumpCommand, NULL );
328
 
    }
329
 
 
330
 
    return p_new;
331
 
}
332
 
 
333
 
/**
334
 
 ****************************************************************************
335
 
 * Destroy a vlc object
 
266
    return vlc_custom_create( p_this, i_size, i_type, psz_type );
 
267
}
 
268
 
 
269
 
 
270
/**
 
271
 ****************************************************************************
 
272
 * Set the destructor of a vlc object
 
273
 *
 
274
 * This function sets the destructor of the vlc object. It will be called
 
275
 * when the object is destroyed when the its refcount reaches 0.
 
276
 * (It is called by the internal function vlc_object_destroy())
 
277
 *****************************************************************************/
 
278
void __vlc_object_set_destructor( vlc_object_t *p_this,
 
279
                                  vlc_destructor_t pf_destructor )
 
280
{
 
281
    vlc_object_internals_t *p_priv = vlc_internals(p_this );
 
282
    p_priv->pf_destructor = pf_destructor;
 
283
}
 
284
 
 
285
/**
 
286
 ****************************************************************************
 
287
 * Destroy a vlc object (Internal)
336
288
 *
337
289
 * This function destroys an object that has been previously allocated with
338
290
 * vlc_object_create. The object's refcount must be zero and it must not be
339
291
 * attached to other objects in any way.
340
292
 *****************************************************************************/
341
 
void __vlc_object_destroy( vlc_object_t *p_this )
 
293
static void vlc_object_destroy( vlc_object_t *p_this )
342
294
{
343
 
    int i_delay = 0;
344
 
 
345
 
    if( p_this->i_children )
346
 
    {
347
 
        msg_Err( p_this, "cannot delete object (%i, %s) with children" ,
348
 
                 p_this->i_object_id, p_this->psz_object_name );
349
 
        return;
350
 
    }
351
 
 
352
 
    if( p_this->p_parent )
353
 
    {
354
 
        msg_Err( p_this, "cannot delete object (%i, %s) with a parent",
355
 
                 p_this->i_object_id, p_this->psz_object_name );
356
 
        return;
357
 
    }
358
 
 
359
 
    while( p_this->i_refcount )
360
 
    {
361
 
        i_delay++;
362
 
 
363
 
        /* Don't warn immediately ... 100ms seems OK */
364
 
        if( i_delay == 2 )
365
 
        {
366
 
            msg_Warn( p_this,
367
 
                  "refcount is %i, delaying before deletion (id=%d,type=%d)",
368
 
                  p_this->i_refcount, p_this->i_object_id,
369
 
                  p_this->i_object_type );
370
 
        }
371
 
        else if( i_delay == 10 )
372
 
        {
373
 
            msg_Err( p_this,
374
 
                  "refcount is %i, delaying again (id=%d,type=%d)",
375
 
                  p_this->i_refcount, p_this->i_object_id,
376
 
                  p_this->i_object_type );
377
 
        }
378
 
        else if( i_delay == 20 )
379
 
        {
380
 
            msg_Err( p_this,
381
 
                  "waited too long, cancelling destruction (id=%d,type=%d)",
382
 
                  p_this->i_object_id, p_this->i_object_type );
383
 
            return;
384
 
        }
385
 
 
386
 
        msleep( 100000 );
387
 
    }
 
295
    vlc_object_internals_t *p_priv = vlc_internals( p_this );
 
296
 
 
297
    /* Objects are always detached beforehand */
 
298
    assert( !p_this->p_parent );
 
299
 
 
300
    /* Send a kill to the object's thread if applicable */
 
301
    vlc_object_kill( p_this );
 
302
 
 
303
    /* If we are running on a thread, wait until it ends */
 
304
    if( p_priv->b_thread )
 
305
    {
 
306
        msg_Warn (p_this->p_libvlc, /* do NOT use a dead object for logging! */
 
307
                  "%s %d destroyed while thread alive (VLC might crash)",
 
308
                  p_this->psz_object_type, p_this->i_object_id);
 
309
        vlc_thread_join( p_this );
 
310
    }
 
311
 
 
312
    /* Call the custom "subclass" destructor */
 
313
    if( p_priv->pf_destructor )
 
314
        p_priv->pf_destructor( p_this );
388
315
 
389
316
    /* Destroy the associated variables, starting from the end so that
390
317
     * no memmove calls have to be done. */
391
 
    while( p_this->i_vars )
 
318
    while( p_priv->i_vars )
392
319
    {
393
 
        var_Destroy( p_this, p_this->p_vars[p_this->i_vars - 1].psz_name );
 
320
        var_Destroy( p_this, p_priv->p_vars[p_priv->i_vars - 1].psz_name );
394
321
    }
395
322
 
396
 
    free( p_this->p_vars );
397
 
    vlc_mutex_destroy( &p_this->var_lock );
398
 
 
399
 
    if( p_this->psz_header ) free( p_this->psz_header );
400
 
 
401
 
    if( p_this->i_object_type == VLC_OBJECT_ROOT )
 
323
    free( p_priv->p_vars );
 
324
    vlc_mutex_destroy( &p_priv->var_lock );
 
325
 
 
326
    free( p_this->psz_header );
 
327
 
 
328
    if( p_this->p_libvlc == NULL )
402
329
    {
403
 
        /* We are the root object ... no need to lock. */
404
 
        free( p_this->p_libvlc->pp_objects );
405
 
        p_this->p_libvlc->pp_objects = NULL;
406
 
        p_this->p_libvlc->i_objects--;
407
 
 
 
330
#ifndef NDEBUG
 
331
        libvlc_global_data_t *p_global = (libvlc_global_data_t *)p_this;
 
332
 
 
333
        assert( p_global == vlc_global() );
 
334
        /* Test for leaks */
 
335
        if (p_priv->next != p_this)
 
336
        {
 
337
            vlc_object_t *leaked = p_priv->next, *first = leaked;
 
338
            do
 
339
            {
 
340
                /* We are leaking this object */
 
341
                fprintf( stderr,
 
342
                         "ERROR: leaking object (id:%i, type:%s, name:%s)\n",
 
343
                         leaked->i_object_id, leaked->psz_object_type,
 
344
                         leaked->psz_object_name );
 
345
                /* Dump libvlc object to ease debugging */
 
346
                vlc_object_dump( leaked );
 
347
                fflush(stderr);
 
348
                leaked = vlc_internals (leaked)->next;
 
349
            }
 
350
            while (leaked != first);
 
351
 
 
352
            /* Dump global object to ease debugging */
 
353
            vlc_object_dump( p_this );
 
354
            /* Strongly abort, cause we want these to be fixed */
 
355
            abort();
 
356
        }
 
357
#endif
 
358
 
 
359
        /* We are the global object ... no need to lock. */
408
360
        vlc_mutex_destroy( &structure_lock );
409
 
    }
 
361
#ifdef LIBVLC_REFCHECK
 
362
        held_objects_destroy( vlc_threadvar_get( &held_objects ) );
 
363
        vlc_threadvar_delete( &held_objects );
 
364
#endif
 
365
    }
 
366
 
 
367
    FREENULL( p_this->psz_object_name );
 
368
 
 
369
#if defined(WIN32) || defined(UNDER_CE)
 
370
    /* if object has an associated thread, close it now */
 
371
    if( p_priv->thread_id )
 
372
       CloseHandle(p_priv->thread_id);
 
373
#endif
 
374
 
 
375
    vlc_spin_destroy( &p_priv->ref_spin );
 
376
    vlc_mutex_destroy( &p_priv->lock );
 
377
    vlc_cond_destroy( &p_priv->wait );
 
378
    vlc_spin_destroy( &p_priv->spin );
 
379
    if( p_priv->pipes[1] != -1 )
 
380
        close( p_priv->pipes[1] );
 
381
    if( p_priv->pipes[0] != -1 )
 
382
        close( p_priv->pipes[0] );
 
383
 
 
384
    free( p_priv );
 
385
}
 
386
 
 
387
 
 
388
/** Inter-object signaling */
 
389
 
 
390
void __vlc_object_lock( vlc_object_t *obj )
 
391
{
 
392
    vlc_mutex_lock( &(vlc_internals(obj)->lock) );
 
393
}
 
394
 
 
395
void __vlc_object_unlock( vlc_object_t *obj )
 
396
{
 
397
    vlc_assert_locked( &(vlc_internals(obj)->lock) );
 
398
    vlc_mutex_unlock( &(vlc_internals(obj)->lock) );
 
399
}
 
400
 
 
401
#ifdef WIN32
 
402
# include <winsock2.h>
 
403
# include <ws2tcpip.h>
 
404
 
 
405
/**
 
406
 * select()-able pipes emulated using Winsock
 
407
 */
 
408
static int pipe (int fd[2])
 
409
{
 
410
    SOCKADDR_IN addr;
 
411
    int addrlen = sizeof (addr);
 
412
 
 
413
    SOCKET l = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP), a,
 
414
           c = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
 
415
    if ((l == INVALID_SOCKET) || (c == INVALID_SOCKET))
 
416
        goto error;
 
417
 
 
418
    memset (&addr, 0, sizeof (addr));
 
419
    addr.sin_family = AF_INET;
 
420
    addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
 
421
    if (bind (l, (PSOCKADDR)&addr, sizeof (addr))
 
422
     || getsockname (l, (PSOCKADDR)&addr, &addrlen)
 
423
     || listen (l, 1)
 
424
     || connect (c, (PSOCKADDR)&addr, addrlen))
 
425
        goto error;
 
426
 
 
427
    a = accept (l, NULL, NULL);
 
428
    if (a == INVALID_SOCKET)
 
429
        goto error;
 
430
 
 
431
    closesocket (l);
 
432
    //shutdown (a, 0);
 
433
    //shutdown (c, 1);
 
434
    fd[0] = c;
 
435
    fd[1] = a;
 
436
    return 0;
 
437
 
 
438
error:
 
439
    if (l != INVALID_SOCKET)
 
440
        closesocket (l);
 
441
    if (c != INVALID_SOCKET)
 
442
        closesocket (c);
 
443
    return -1;
 
444
}
 
445
 
 
446
#undef  read
 
447
#define read( a, b, c )  recv (a, b, c, 0)
 
448
#undef  write
 
449
#define write( a, b, c ) send (a, b, c, 0)
 
450
#undef  close
 
451
#define close( a )       closesocket (a)
 
452
#endif /* WIN32 */
 
453
 
 
454
/**
 
455
 * Returns the readable end of a pipe that becomes readable once termination
 
456
 * of the object is requested (vlc_object_kill()).
 
457
 * This can be used to wake-up out of a select() or poll() event loop, such
 
458
 * typically when doing network I/O.
 
459
 *
 
460
 * Note that the pipe will remain the same for the lifetime of the object.
 
461
 * DO NOT read the pipe nor close it yourself. Ever.
 
462
 *
 
463
 * @param obj object that would be "killed"
 
464
 * @return a readable pipe descriptor, or -1 on error.
 
465
 */
 
466
int __vlc_object_waitpipe( vlc_object_t *obj )
 
467
{
 
468
    int pfd[2] = { -1, -1 };
 
469
    vlc_object_internals_t *internals = vlc_internals( obj );
 
470
    bool killed = false;
 
471
 
 
472
    vlc_spin_lock (&internals->spin);
 
473
    if (internals->pipes[0] == -1)
 
474
    {
 
475
        /* This can only ever happen if someone killed us without locking: */
 
476
        assert (internals->pipes[1] == -1);
 
477
        vlc_spin_unlock (&internals->spin);
 
478
 
 
479
        if (pipe (pfd))
 
480
            return -1;
 
481
 
 
482
        vlc_spin_lock (&internals->spin);
 
483
        if (internals->pipes[0] == -1)
 
484
        {
 
485
            internals->pipes[0] = pfd[0];
 
486
            internals->pipes[1] = pfd[1];
 
487
            pfd[0] = pfd[1] = -1;
 
488
        }
 
489
        killed = obj->b_die;
 
490
    }
 
491
    vlc_spin_unlock (&internals->spin);
 
492
 
 
493
    if (killed)
 
494
    {
 
495
        /* Race condition: vlc_object_kill() already invoked! */
 
496
        int fd;
 
497
 
 
498
        vlc_spin_lock (&internals->spin);
 
499
        fd = internals->pipes[1];
 
500
        internals->pipes[1] = -1;
 
501
        vlc_spin_unlock (&internals->spin);
 
502
 
 
503
        msg_Dbg (obj, "waitpipe: object already dying");
 
504
        if (fd != -1)
 
505
            close (fd);
 
506
    }
 
507
 
 
508
    /* Race condition: two threads call pipe() - unlikely */
 
509
    if (pfd[0] != -1)
 
510
        close (pfd[0]);
 
511
    if (pfd[1] != -1)
 
512
        close (pfd[1]);
 
513
 
 
514
    return internals->pipes[0];
 
515
}
 
516
 
 
517
 
 
518
/**
 
519
 * Waits for the object to be signaled (using vlc_object_signal()).
 
520
 * It is assumed that the caller has locked the object. This function will
 
521
 * unlock the object, and lock it again before returning.
 
522
 * If the object was signaled before the caller locked the object, it is
 
523
 * undefined whether the signal will be lost or will wake the process.
 
524
 *
 
525
 * @return true if the object is dying and should terminate.
 
526
 */
 
527
void __vlc_object_wait( vlc_object_t *obj )
 
528
{
 
529
    vlc_object_internals_t *priv = vlc_internals( obj );
 
530
    vlc_assert_locked( &priv->lock);
 
531
    vlc_cond_wait( &priv->wait, &priv->lock );
 
532
}
 
533
 
 
534
 
 
535
/**
 
536
 * Waits for the object to be signaled (using vlc_object_signal()), or for
 
537
 * a timer to expire. It is asserted that the caller holds the object lock.
 
538
 *
 
539
 * @return 0 if the object was signaled before the timer expiration, or
 
540
 * ETIMEDOUT if the timer expired without any signal.
 
541
 */
 
542
int __vlc_object_timedwait( vlc_object_t *obj, mtime_t deadline )
 
543
{
 
544
    vlc_object_internals_t *priv = vlc_internals( obj );
 
545
    vlc_assert_locked( &priv->lock);
 
546
    return vlc_cond_timedwait( &priv->wait, &priv->lock, deadline );
 
547
}
 
548
 
 
549
 
 
550
/**
 
551
 * Signals an object for which the lock is held.
 
552
 * At least one thread currently sleeping in vlc_object_wait() or
 
553
 * vlc_object_timedwait() will wake up, assuming that there is at least one
 
554
 * such thread in the first place. Otherwise, it is undefined whether the
 
555
 * signal will be lost or will wake up one or more thread later.
 
556
 */
 
557
void __vlc_object_signal_unlocked( vlc_object_t *obj )
 
558
{
 
559
    vlc_assert_locked (&(vlc_internals(obj)->lock));
 
560
    vlc_cond_signal( &(vlc_internals(obj)->wait) );
 
561
}
 
562
 
 
563
 
 
564
/**
 
565
 * Requests termination of an object.
 
566
 * If the object is LibVLC, also request to terminate all its children.
 
567
 */
 
568
void __vlc_object_kill( vlc_object_t *p_this )
 
569
{
 
570
    vlc_object_internals_t *priv = vlc_internals( p_this );
 
571
    int fd;
 
572
 
 
573
    vlc_object_lock( p_this );
 
574
    p_this->b_die = true;
 
575
 
 
576
    vlc_spin_lock (&priv->spin);
 
577
    fd = priv->pipes[1];
 
578
    priv->pipes[1] = -1;
 
579
    vlc_spin_unlock (&priv->spin);
 
580
 
 
581
    if( fd != -1 )
 
582
    {
 
583
        msg_Dbg (p_this, "waitpipe: object killed");
 
584
        close (fd);
 
585
    }
 
586
 
 
587
    vlc_object_signal_unlocked( p_this );
 
588
    /* This also serves as a memory barrier toward vlc_object_alive(): */
 
589
    vlc_object_unlock( p_this );
 
590
}
 
591
 
 
592
 
 
593
/**
 
594
 * Find an object given its ID.
 
595
 *
 
596
 * This function looks for the object whose i_object_id field is i_id.
 
597
 * This function is slow, and often used to hide bugs. Do not use it.
 
598
 * If you need to retain reference to an object, yield the object pointer with
 
599
 * vlc_object_yield(), use the pointer as your reference, and call
 
600
 * vlc_object_release() when you're done.
 
601
 */
 
602
void * vlc_object_get( int i_id )
 
603
{
 
604
    libvlc_global_data_t *p_libvlc_global = vlc_global();
 
605
    vlc_object_t *obj = NULL;
 
606
#ifndef NDEBUG
 
607
    vlc_object_t *caller = vlc_threadobj ();
 
608
 
 
609
    if (caller)
 
610
        msg_Dbg (caller, "uses deprecated vlc_object_get(%d)", i_id);
410
611
    else
411
 
    {
412
 
        int i_index;
413
 
 
414
 
        vlc_mutex_lock( &structure_lock );
415
 
 
416
 
        /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
417
 
         * useless to try and recover anything if pp_objects gets smashed. */
418
 
        i_index = FindIndex( p_this, p_this->p_libvlc->pp_objects,
419
 
                             p_this->p_libvlc->i_objects );
420
 
        REMOVE_ELEM( p_this->p_libvlc->pp_objects,
421
 
                     p_this->p_libvlc->i_objects, i_index );
422
 
 
423
 
        vlc_mutex_unlock( &structure_lock );
424
 
    }
425
 
 
426
 
    vlc_mutex_destroy( &p_this->object_lock );
427
 
    vlc_cond_destroy( &p_this->object_wait );
428
 
 
429
 
    /* root is not dynamically allocated by vlc_object_create */
430
 
    if( p_this->i_object_type != VLC_OBJECT_ROOT )
431
 
        free( p_this );
432
 
}
433
 
 
434
 
/**
435
 
 * find an object given its ID
436
 
 *
437
 
 * This function looks for the object whose i_object_id field is i_id. We
438
 
 * use a dichotomy so that lookups are in log2(n).
439
 
 *****************************************************************************/
440
 
void * __vlc_object_get( vlc_object_t *p_this, int i_id )
441
 
{
442
 
    int i_max, i_middle;
443
 
    vlc_object_t **pp_objects;
444
 
 
 
612
        fprintf (stderr, "main thread uses deprecated vlc_object_get(%d)\n",
 
613
                 i_id);
 
614
#endif
445
615
    vlc_mutex_lock( &structure_lock );
446
616
 
447
 
    pp_objects = p_this->p_libvlc->pp_objects;
448
 
 
449
 
    /* Perform our dichotomy */
450
 
    for( i_max = p_this->p_libvlc->i_objects - 1 ; ; )
 
617
    for( obj = vlc_internals (p_libvlc_global)->next;
 
618
         obj != VLC_OBJECT (p_libvlc_global);
 
619
         obj = vlc_internals (obj)->next )
451
620
    {
452
 
        i_middle = i_max / 2;
453
 
 
454
 
        if( pp_objects[i_middle]->i_object_id > i_id )
455
 
        {
456
 
            i_max = i_middle;
457
 
        }
458
 
        else if( pp_objects[i_middle]->i_object_id < i_id )
459
 
        {
460
 
            if( i_middle )
461
 
            {
462
 
                pp_objects += i_middle;
463
 
                i_max -= i_middle;
464
 
            }
465
 
            else
466
 
            {
467
 
                /* This happens when there are only two remaining objects */
468
 
                if( pp_objects[i_middle+1]->i_object_id == i_id )
469
 
                {
470
 
                    vlc_mutex_unlock( &structure_lock );
471
 
                    pp_objects[i_middle+1]->i_refcount++;
472
 
                    return pp_objects[i_middle+1];
473
 
                }
474
 
                break;
475
 
            }
476
 
        }
477
 
        else
478
 
        {
479
 
            vlc_mutex_unlock( &structure_lock );
480
 
            pp_objects[i_middle]->i_refcount++;
481
 
            return pp_objects[i_middle];
482
 
        }
483
 
 
484
 
        if( i_max == 0 )
485
 
        {
486
 
            /* this means that i_max == i_middle, and since we have already
487
 
             * tested pp_objects[i_middle]), p_found is properly set. */
488
 
            break;
 
621
        if( obj->i_object_id == i_id )
 
622
        {
 
623
            vlc_object_yield( obj );
 
624
            goto out;
489
625
        }
490
626
    }
491
 
 
 
627
    obj = NULL;
 
628
#ifndef NDEBUG
 
629
    if (caller)
 
630
        msg_Warn (caller, "wants non-existing object %d", i_id);
 
631
    else
 
632
        fprintf (stderr, "main thread wants non-existing object %d\n", i_id);
 
633
#endif
 
634
out:
492
635
    vlc_mutex_unlock( &structure_lock );
493
 
    return NULL;
 
636
    return obj;
494
637
}
495
638
 
496
639
/**
504
647
{
505
648
    vlc_object_t *p_found;
506
649
 
507
 
    vlc_mutex_lock( &structure_lock );
508
 
 
509
650
    /* If we are of the requested type ourselves, don't look further */
510
651
    if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
511
652
    {
512
 
        p_this->i_refcount++;
513
 
        vlc_mutex_unlock( &structure_lock );
514
 
        return p_this;
515
 
    }
 
653
        vlc_object_yield( p_this );
 
654
        return p_this;
 
655
    }
 
656
 
 
657
    /* Otherwise, recursively look for the object */
 
658
    if ((i_mode & 0x000f) == FIND_ANYWHERE)
 
659
    {
 
660
#ifndef NDEBUG
 
661
        if (i_type == VLC_OBJECT_PLAYLIST)
 
662
            msg_Err (p_this, "using vlc_object_find(VLC_OBJECT_PLAYLIST) "
 
663
                     "instead of pl_Yield()");
 
664
#endif
 
665
        return vlc_object_find (p_this->p_libvlc, i_type,
 
666
                                (i_mode & ~0x000f)|FIND_CHILD);
 
667
    }
 
668
 
 
669
    vlc_mutex_lock( &structure_lock );
 
670
    p_found = FindObject( p_this, i_type, i_mode );
 
671
    vlc_mutex_unlock( &structure_lock );
 
672
    return p_found;
 
673
}
 
674
 
 
675
/**
 
676
 ****************************************************************************
 
677
 * find a named object and increment its refcount
 
678
 *****************************************************************************
 
679
 * This function recursively looks for a given object name. i_mode can be one
 
680
 * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
 
681
 *****************************************************************************/
 
682
void * __vlc_object_find_name( vlc_object_t *p_this, const char *psz_name,
 
683
                               int i_mode )
 
684
{
 
685
    vlc_object_t *p_found;
 
686
 
 
687
    /* If have the requested name ourselves, don't look further */
 
688
    if( !(i_mode & FIND_STRICT)
 
689
        && p_this->psz_object_name
 
690
        && !strcmp( p_this->psz_object_name, psz_name ) )
 
691
    {
 
692
        vlc_object_yield( p_this );
 
693
        return p_this;
 
694
    }
 
695
 
 
696
    vlc_mutex_lock( &structure_lock );
516
697
 
517
698
    /* Otherwise, recursively look for the object */
518
699
    if( (i_mode & 0x000f) == FIND_ANYWHERE )
521
702
 
522
703
        /* Find the root */
523
704
        while( p_root->p_parent != NULL &&
524
 
               p_root != VLC_OBJECT( p_this->p_vlc ) )
 
705
               p_root != VLC_OBJECT( p_this->p_libvlc ) )
525
706
        {
526
707
            p_root = p_root->p_parent;
527
708
        }
528
709
 
529
 
        p_found = FindObject( p_root, i_type, (i_mode & ~0x000f)|FIND_CHILD );
530
 
        if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_vlc ) )
 
710
        p_found = FindObjectName( p_root, psz_name,
 
711
                                 (i_mode & ~0x000f)|FIND_CHILD );
 
712
        if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
531
713
        {
532
 
            p_found = FindObject( VLC_OBJECT( p_this->p_vlc ),
533
 
                                  i_type, (i_mode & ~0x000f)|FIND_CHILD );
 
714
            p_found = FindObjectName( VLC_OBJECT( p_this->p_libvlc ),
 
715
                                      psz_name, (i_mode & ~0x000f)|FIND_CHILD );
534
716
        }
535
717
    }
536
718
    else
537
719
    {
538
 
        p_found = FindObject( p_this, i_type, i_mode );
 
720
        p_found = FindObjectName( p_this, psz_name, i_mode );
539
721
    }
540
722
 
541
723
    vlc_mutex_unlock( &structure_lock );
544
726
}
545
727
 
546
728
/**
547
 
 ****************************************************************************
548
 
 * increment an object refcount
549
 
 *****************************************************************************/
 
729
 * Increment an object reference counter.
 
730
 */
550
731
void __vlc_object_yield( vlc_object_t *p_this )
551
732
{
552
 
    vlc_mutex_lock( &structure_lock );
553
 
    p_this->i_refcount++;
554
 
    vlc_mutex_unlock( &structure_lock );
 
733
    vlc_object_internals_t *internals = vlc_internals( p_this );
 
734
 
 
735
    vlc_spin_lock( &internals->ref_spin );
 
736
    /* Avoid obvious freed object uses */
 
737
    assert( internals->i_refcount > 0 );
 
738
    /* Increment the counter */
 
739
    internals->i_refcount++;
 
740
    vlc_spin_unlock( &internals->ref_spin );
 
741
#ifdef LIBVLC_REFCHECK
 
742
    /* Update the list of referenced objects */
 
743
    /* Using TLS, so no need to lock */
 
744
    /* The following line may leak memory if a thread leaks objects. */
 
745
    held_list_t *newhead = malloc (sizeof (*newhead));
 
746
    held_list_t *oldhead = vlc_threadvar_get (&held_objects);
 
747
    newhead->next = oldhead;
 
748
    newhead->obj = p_this;
 
749
    vlc_threadvar_set (&held_objects, newhead);
 
750
#endif
555
751
}
556
752
 
557
 
/**
558
 
 ****************************************************************************
 
753
/*****************************************************************************
559
754
 * decrement an object refcount
 
755
 * And destroy the object if its refcount reach zero.
560
756
 *****************************************************************************/
561
757
void __vlc_object_release( vlc_object_t *p_this )
562
758
{
 
759
    vlc_object_internals_t *internals = vlc_internals( p_this );
 
760
    bool b_should_destroy;
 
761
 
 
762
#ifdef LIBVLC_REFCHECK
 
763
    /* Update the list of referenced objects */
 
764
    /* Using TLS, so no need to lock */
 
765
    for (held_list_t *hlcur = vlc_threadvar_get (&held_objects),
 
766
                     *hlprev = NULL;
 
767
         hlcur != NULL;
 
768
         hlprev = hlcur, hlcur = hlcur->next)
 
769
    {
 
770
        if (hlcur->obj == p_this)
 
771
        {
 
772
            if (hlprev == NULL)
 
773
                vlc_threadvar_set (&held_objects, hlcur->next);
 
774
            else
 
775
                hlprev->next = hlcur->next;
 
776
            free (hlcur);
 
777
            break;
 
778
        }
 
779
    }
 
780
    /* TODO: what if releasing without references? */
 
781
#endif
 
782
 
 
783
    vlc_spin_lock( &internals->ref_spin );
 
784
    assert( internals->i_refcount > 0 );
 
785
 
 
786
    if( internals->i_refcount > 1 )
 
787
    {
 
788
        /* Fast path */
 
789
        /* There are still other references to the object */
 
790
        internals->i_refcount--;
 
791
        vlc_spin_unlock( &internals->ref_spin );
 
792
        return;
 
793
    }
 
794
    vlc_spin_unlock( &internals->ref_spin );
 
795
 
 
796
    /* Slow path */
 
797
    /* Remember that we cannot hold the spin while waiting on the mutex */
563
798
    vlc_mutex_lock( &structure_lock );
564
 
    p_this->i_refcount--;
 
799
    /* Take the spin again. Note that another thread may have yielded the
 
800
     * object in the (very short) mean time. */
 
801
    vlc_spin_lock( &internals->ref_spin );
 
802
    b_should_destroy = --internals->i_refcount == 0;
 
803
    vlc_spin_unlock( &internals->ref_spin );
 
804
 
 
805
    if( b_should_destroy )
 
806
    {
 
807
        /* Remove the object from object list
 
808
         * so that it cannot be encountered by vlc_object_get() */
 
809
        vlc_internals (internals->next)->prev = internals->prev;
 
810
        vlc_internals (internals->prev)->next = internals->next;
 
811
 
 
812
        /* Detach from parent to protect against FIND_CHILDREN */
 
813
        vlc_object_detach_unlocked (p_this);
 
814
        /* Detach from children to protect against FIND_PARENT */
 
815
        for (int i = 0; i < internals->i_children; i++)
 
816
            internals->pp_children[i]->p_parent = NULL;
 
817
    }
 
818
 
565
819
    vlc_mutex_unlock( &structure_lock );
 
820
 
 
821
    if( b_should_destroy )
 
822
    {
 
823
        free( internals->pp_children );
 
824
        internals->pp_children = NULL;
 
825
        internals->i_children = 0;
 
826
        vlc_object_destroy( p_this );
 
827
    }
566
828
}
567
829
 
568
830
/**
574
836
 *****************************************************************************/
575
837
void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
576
838
{
 
839
    if( !p_this ) return;
 
840
 
577
841
    vlc_mutex_lock( &structure_lock );
578
842
 
579
843
    /* Attach the parent to its child */
 
844
    assert (!p_this->p_parent);
580
845
    p_this->p_parent = p_parent;
581
846
 
582
847
    /* Attach the child to its parent */
583
 
    INSERT_ELEM( p_parent->pp_children, p_parent->i_children,
584
 
                 p_parent->i_children, p_this );
585
 
 
586
 
    /* Climb up the tree to see whether we are connected with the root */
587
 
    if( p_parent->b_attached )
588
 
    {
589
 
        SetAttachment( p_this, VLC_TRUE );
590
 
    }
 
848
    vlc_object_internals_t *priv = vlc_internals( p_parent );
 
849
    INSERT_ELEM( priv->pp_children, priv->i_children, priv->i_children,
 
850
                 p_this );
591
851
 
592
852
    vlc_mutex_unlock( &structure_lock );
593
853
}
594
854
 
 
855
 
 
856
static void vlc_object_detach_unlocked (vlc_object_t *p_this)
 
857
{
 
858
    vlc_assert_locked (&structure_lock);
 
859
 
 
860
    if (p_this->p_parent == NULL)
 
861
        return;
 
862
 
 
863
    vlc_object_internals_t *priv = vlc_internals( p_this->p_parent );
 
864
 
 
865
    int i_index, i;
 
866
 
 
867
    /* Remove p_this's parent */
 
868
    p_this->p_parent = NULL;
 
869
 
 
870
    /* Remove all of p_parent's children which are p_this */
 
871
    for( i_index = priv->i_children ; i_index-- ; )
 
872
    {
 
873
        if( priv->pp_children[i_index] == p_this )
 
874
        {
 
875
            priv->i_children--;
 
876
            for( i = i_index ; i < priv->i_children ; i++ )
 
877
                priv->pp_children[i] = priv->pp_children[i+1];
 
878
        }
 
879
    }
 
880
 
 
881
    if( priv->i_children )
 
882
    {
 
883
        priv->pp_children = (vlc_object_t **)realloc( priv->pp_children,
 
884
                               priv->i_children * sizeof(vlc_object_t *) );
 
885
    }
 
886
    else
 
887
    {
 
888
        /* Special case - don't realloc() to zero to avoid leaking */
 
889
        free( priv->pp_children );
 
890
        priv->pp_children = NULL;
 
891
    }
 
892
}
 
893
 
 
894
 
595
895
/**
596
896
 ****************************************************************************
597
897
 * detach object from its parent
600
900
 *****************************************************************************/
601
901
void __vlc_object_detach( vlc_object_t *p_this )
602
902
{
 
903
    if( !p_this ) return;
 
904
 
603
905
    vlc_mutex_lock( &structure_lock );
604
906
    if( !p_this->p_parent )
605
 
    {
606
907
        msg_Err( p_this, "object is not attached" );
607
 
        vlc_mutex_unlock( &structure_lock );
608
 
        return;
609
 
    }
610
 
 
611
 
    /* Climb up the tree to see whether we are connected with the root */
612
 
    if( p_this->p_parent->b_attached )
613
 
    {
614
 
        SetAttachment( p_this, VLC_FALSE );
615
 
    }
616
 
 
617
 
    DetachObject( p_this );
 
908
    else
 
909
        vlc_object_detach_unlocked( p_this );
618
910
    vlc_mutex_unlock( &structure_lock );
619
911
}
620
912
 
 
913
 
621
914
/**
622
915
 ****************************************************************************
623
916
 * find a list typed objects and increment their refcount
628
921
vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
629
922
{
630
923
    vlc_list_t *p_list;
631
 
    vlc_object_t **pp_current, **pp_end;
632
 
    int i_count = 0, i_index = 0;
633
 
 
634
 
    vlc_mutex_lock( &structure_lock );
 
924
    int i_count = 0;
635
925
 
636
926
    /* Look for the objects */
637
927
    switch( i_mode & 0x000f )
638
928
    {
639
929
    case FIND_ANYWHERE:
640
 
        pp_current = p_this->p_libvlc->pp_objects;
641
 
        pp_end = pp_current + p_this->p_libvlc->i_objects;
642
 
 
643
 
        for( ; pp_current < pp_end ; pp_current++ )
644
 
        {
645
 
            if( (*pp_current)->b_attached
646
 
                 && (*pp_current)->i_object_type == i_type )
647
 
            {
648
 
                i_count++;
649
 
            }
650
 
        }
651
 
 
652
 
        p_list = NewList( i_count );
653
 
        pp_current = p_this->p_libvlc->pp_objects;
654
 
 
655
 
        for( ; pp_current < pp_end ; pp_current++ )
656
 
        {
657
 
            if( (*pp_current)->b_attached
658
 
                 && (*pp_current)->i_object_type == i_type )
659
 
            {
660
 
                ListReplace( p_list, *pp_current, i_index );
661
 
                if( i_index < i_count ) i_index++;
662
 
            }
663
 
        }
664
 
    break;
 
930
        /* Modules should probably not be object, and the module should perhaps
 
931
         * not be shared across LibVLC instances. In the mean time, this ugly
 
932
         * hack is brought to you by Courmisch. */
 
933
        if (i_type == VLC_OBJECT_MODULE)
 
934
            return vlc_list_find ((vlc_object_t *)vlc_global ()->p_module_bank,
 
935
                                  i_type, FIND_CHILD);
 
936
        return vlc_list_find (p_this->p_libvlc, i_type, FIND_CHILD);
665
937
 
666
938
    case FIND_CHILD:
 
939
        vlc_mutex_lock( &structure_lock );
667
940
        i_count = CountChildren( p_this, i_type );
668
941
        p_list = NewList( i_count );
669
942
 
670
943
        /* Check allocation was successful */
671
944
        if( p_list->i_count != i_count )
672
945
        {
 
946
            vlc_mutex_unlock( &structure_lock );
673
947
            msg_Err( p_this, "list allocation failed!" );
674
948
            p_list->i_count = 0;
675
949
            break;
677
951
 
678
952
        p_list->i_count = 0;
679
953
        ListChildren( p_list, p_this, i_type );
 
954
        vlc_mutex_unlock( &structure_lock );
680
955
        break;
681
956
 
682
957
    default:
685
960
        break;
686
961
    }
687
962
 
 
963
    return p_list;
 
964
}
 
965
 
 
966
/**
 
967
 * Gets the list of children of an objects, and increment their reference
 
968
 * count.
 
969
 * @return a list (possibly empty) or NULL in case of error.
 
970
 */
 
971
vlc_list_t *__vlc_list_children( vlc_object_t *obj )
 
972
{
 
973
    vlc_list_t *l;
 
974
    vlc_object_internals_t *priv = vlc_internals( obj );
 
975
 
 
976
    vlc_mutex_lock( &structure_lock );
 
977
    l = NewList( priv->i_children );
 
978
    for (int i = 0; i < l->i_count; i++)
 
979
    {
 
980
        vlc_object_yield( priv->pp_children[i] );
 
981
        l->p_values[i].p_object = priv->pp_children[i];
 
982
    }
688
983
    vlc_mutex_unlock( &structure_lock );
689
 
 
690
 
    return p_list;
 
984
    return l;
691
985
}
692
986
 
693
987
/*****************************************************************************
700
994
static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
701
995
                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
702
996
{
703
 
    if( *psz_cmd == 't' )
704
 
    {
705
 
        char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
706
 
        vlc_object_t *p_object;
 
997
    (void)oldval; (void)p_data;
 
998
    if( *psz_cmd == 'l' )
 
999
    {
 
1000
        vlc_object_t *root = VLC_OBJECT (vlc_global ()), *cur = root; 
 
1001
 
 
1002
        vlc_mutex_lock( &structure_lock );
 
1003
        do
 
1004
        {
 
1005
            PrintObject (cur, "");
 
1006
            cur = vlc_internals (cur)->next;
 
1007
        }
 
1008
        while (cur != root);
 
1009
        vlc_mutex_unlock( &structure_lock );
 
1010
    }
 
1011
    else
 
1012
    {
 
1013
        vlc_object_t *p_object = NULL;
707
1014
 
708
1015
        if( *newval.psz_string )
709
1016
        {
710
 
            p_object = vlc_object_get( p_this, atoi(newval.psz_string) );
 
1017
            char *end;
 
1018
            int i_id = strtol( newval.psz_string, &end, 0 );
 
1019
            if( end != newval.psz_string )
 
1020
                p_object = vlc_object_get( i_id );
 
1021
            else
 
1022
                /* try using the object's name to find it */
 
1023
                p_object = vlc_object_find_name( p_this, newval.psz_string,
 
1024
                                                 FIND_ANYWHERE );
711
1025
 
712
1026
            if( !p_object )
713
1027
            {
714
1028
                return VLC_ENOOBJ;
715
1029
            }
716
1030
        }
717
 
        else
718
 
        {
719
 
            p_object = p_this->p_vlc ? VLC_OBJECT(p_this->p_vlc) : p_this;
720
 
        }
721
1031
 
722
1032
        vlc_mutex_lock( &structure_lock );
723
1033
 
724
 
        psz_foo[0] = '|';
725
 
        DumpStructure( p_object, 0, psz_foo );
 
1034
        if( *psz_cmd == 't' )
 
1035
        {
 
1036
            char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
 
1037
 
 
1038
            if( !p_object )
 
1039
                p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
 
1040
 
 
1041
            psz_foo[0] = '|';
 
1042
            DumpStructure( p_object, 0, psz_foo );
 
1043
        }
 
1044
        else if( *psz_cmd == 'v' )
 
1045
        {
 
1046
            int i;
 
1047
 
 
1048
            if( !p_object )
 
1049
                p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
 
1050
 
 
1051
            PrintObject( p_object, "" );
 
1052
 
 
1053
            if( !vlc_internals( p_object )->i_vars )
 
1054
                printf( " `-o No variables\n" );
 
1055
            for( i = 0; i < vlc_internals( p_object )->i_vars; i++ )
 
1056
            {
 
1057
                variable_t *p_var = vlc_internals( p_object )->p_vars + i;
 
1058
 
 
1059
                const char *psz_type = "unknown";
 
1060
                switch( p_var->i_type & VLC_VAR_TYPE )
 
1061
                {
 
1062
#define MYCASE( type, nice )                \
 
1063
                    case VLC_VAR_ ## type:  \
 
1064
                        psz_type = nice;    \
 
1065
                        break;
 
1066
                    MYCASE( VOID, "void" );
 
1067
                    MYCASE( BOOL, "bool" );
 
1068
                    MYCASE( INTEGER, "integer" );
 
1069
                    MYCASE( HOTKEY, "hotkey" );
 
1070
                    MYCASE( STRING, "string" );
 
1071
                    MYCASE( MODULE, "module" );
 
1072
                    MYCASE( FILE, "file" );
 
1073
                    MYCASE( DIRECTORY, "directory" );
 
1074
                    MYCASE( VARIABLE, "variable" );
 
1075
                    MYCASE( FLOAT, "float" );
 
1076
                    MYCASE( TIME, "time" );
 
1077
                    MYCASE( ADDRESS, "address" );
 
1078
                    MYCASE( MUTEX, "mutex" );
 
1079
                    MYCASE( LIST, "list" );
 
1080
#undef MYCASE
 
1081
                }
 
1082
                printf( " %c-o \"%s\" (%s",
 
1083
                        i + 1 == vlc_internals( p_object )->i_vars ? '`' : '|',
 
1084
                        p_var->psz_name, psz_type );
 
1085
                if( p_var->psz_text )
 
1086
                    printf( ", %s", p_var->psz_text );
 
1087
                printf( ")" );
 
1088
                if( p_var->i_type & VLC_VAR_ISCOMMAND )
 
1089
                    printf( ", command" );
 
1090
                if( p_var->i_entries )
 
1091
                    printf( ", %d callbacks", p_var->i_entries );
 
1092
                switch( p_var->i_type & 0x00f0 )
 
1093
                {
 
1094
                    case VLC_VAR_VOID:
 
1095
                    case VLC_VAR_MUTEX:
 
1096
                        break;
 
1097
                    case VLC_VAR_BOOL:
 
1098
                        printf( ": %s", p_var->val.b_bool ? "true" : "false" );
 
1099
                        break;
 
1100
                    case VLC_VAR_INTEGER:
 
1101
                        printf( ": %d", p_var->val.i_int );
 
1102
                        break;
 
1103
                    case VLC_VAR_STRING:
 
1104
                        printf( ": \"%s\"", p_var->val.psz_string );
 
1105
                        break;
 
1106
                    case VLC_VAR_FLOAT:
 
1107
                        printf( ": %f", p_var->val.f_float );
 
1108
                        break;
 
1109
                    case VLC_VAR_TIME:
 
1110
                        printf( ": %"PRIi64, (int64_t)p_var->val.i_time );
 
1111
                        break;
 
1112
                    case VLC_VAR_ADDRESS:
 
1113
                        printf( ": %p", p_var->val.p_address );
 
1114
                        break;
 
1115
                    case VLC_VAR_LIST:
 
1116
                        printf( ": TODO" );
 
1117
                        break;
 
1118
                }
 
1119
                printf( "\n" );
 
1120
            }
 
1121
        }
726
1122
 
727
1123
        vlc_mutex_unlock( &structure_lock );
728
1124
 
729
1125
        if( *newval.psz_string )
730
1126
        {
731
 
            vlc_object_release( p_this );
732
 
        }
733
 
    }
734
 
    else if( *psz_cmd == 'l' )
735
 
    {
736
 
        vlc_object_t **pp_current, **pp_end;
737
 
 
738
 
        vlc_mutex_lock( &structure_lock );
739
 
 
740
 
        pp_current = p_this->p_libvlc->pp_objects;
741
 
        pp_end = pp_current + p_this->p_libvlc->i_objects;
742
 
 
743
 
        for( ; pp_current < pp_end ; pp_current++ )
744
 
        {
745
 
            if( (*pp_current)->b_attached )
746
 
            {
747
 
                PrintObject( *pp_current, "" );
748
 
            }
749
 
            else
750
 
            {
751
 
                printf( " o %.8i %s (not attached)\n",
752
 
                        (*pp_current)->i_object_id,
753
 
                        (*pp_current)->psz_object_type );
754
 
            }
755
 
        }
756
 
 
757
 
        vlc_mutex_unlock( &structure_lock );
 
1127
            vlc_object_release( p_object );
 
1128
        }
758
1129
    }
759
1130
 
760
1131
    return VLC_SUCCESS;
772
1143
 
773
1144
    for( i_index = 0; i_index < p_list->i_count; i_index++ )
774
1145
    {
775
 
        vlc_mutex_lock( &structure_lock );
776
 
 
777
 
        p_list->p_values[i_index].p_object->i_refcount--;
778
 
 
779
 
        vlc_mutex_unlock( &structure_lock );
 
1146
        vlc_object_release( p_list->p_values[i_index].p_object );
780
1147
    }
781
1148
 
782
1149
    free( p_list->p_values );
783
1150
    free( p_list );
784
1151
}
785
1152
 
 
1153
/*****************************************************************************
 
1154
 * dump an object. (Debug function)
 
1155
 *****************************************************************************/
 
1156
void __vlc_object_dump( vlc_object_t *p_this )
 
1157
{
 
1158
    vlc_mutex_lock( &structure_lock );
 
1159
    char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
 
1160
    psz_foo[0] = '|';
 
1161
    DumpStructure( p_this, 0, psz_foo );
 
1162
    vlc_mutex_unlock( &structure_lock );
 
1163
}
 
1164
 
786
1165
/* Following functions are local */
787
1166
 
788
 
/*****************************************************************************
789
 
 * FindIndex: find the index of an object in an array of objects
790
 
 *****************************************************************************
791
 
 * This function assumes that p_this can be found in pp_objects. It will not
792
 
 * crash if p_this cannot be found, but will return a wrong value. It is your
793
 
 * duty to check the return value if you are not certain that the object could
794
 
 * be found for sure.
795
 
 *****************************************************************************/
796
 
static int FindIndex( vlc_object_t *p_this,
797
 
                      vlc_object_t **pp_objects, int i_count )
798
 
{
799
 
    int i_middle = i_count / 2;
800
 
 
801
 
    if( i_count == 0 )
802
 
    {
803
 
        return 0;
804
 
    }
805
 
 
806
 
    if( pp_objects[i_middle] == p_this )
807
 
    {
808
 
        return i_middle;
809
 
    }
810
 
 
811
 
    if( i_count == 1 )
812
 
    {
813
 
        return 0;
814
 
    }
815
 
 
816
 
    /* We take advantage of the sorted array */
817
 
    if( pp_objects[i_middle]->i_object_id < p_this->i_object_id )
818
 
    {
819
 
        return i_middle + FindIndex( p_this, pp_objects + i_middle,
820
 
                                             i_count - i_middle );
821
 
    }
822
 
    else
823
 
    {
824
 
        return FindIndex( p_this, pp_objects, i_middle );
825
 
    }
826
 
}
827
 
 
828
1167
static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
829
1168
{
830
1169
    int i;
838
1177
        {
839
1178
            if( p_tmp->i_object_type == i_type )
840
1179
            {
841
 
                p_tmp->i_refcount++;
 
1180
                vlc_object_yield( p_tmp );
842
1181
                return p_tmp;
843
1182
            }
844
1183
            else
849
1188
        break;
850
1189
 
851
1190
    case FIND_CHILD:
852
 
        for( i = p_this->i_children; i--; )
 
1191
        for( i = vlc_internals( p_this )->i_children; i--; )
853
1192
        {
854
 
            p_tmp = p_this->pp_children[i];
 
1193
            p_tmp = vlc_internals( p_this )->pp_children[i];
855
1194
            if( p_tmp->i_object_type == i_type )
856
1195
            {
857
 
                p_tmp->i_refcount++;
 
1196
                vlc_object_yield( p_tmp );
858
1197
                return p_tmp;
859
1198
            }
860
 
            else if( p_tmp->i_children )
 
1199
            else if( vlc_internals( p_tmp )->i_children )
861
1200
            {
862
1201
                p_tmp = FindObject( p_tmp, i_type, i_mode );
863
1202
                if( p_tmp )
876
1215
    return NULL;
877
1216
}
878
1217
 
879
 
static void DetachObject( vlc_object_t *p_this )
880
 
{
881
 
    vlc_object_t *p_parent = p_this->p_parent;
882
 
    int i_index, i;
883
 
 
884
 
    /* Remove p_this's parent */
885
 
    p_this->p_parent = NULL;
886
 
 
887
 
    /* Remove all of p_parent's children which are p_this */
888
 
    for( i_index = p_parent->i_children ; i_index-- ; )
889
 
    {
890
 
        if( p_parent->pp_children[i_index] == p_this )
891
 
        {
892
 
            p_parent->i_children--;
893
 
            for( i = i_index ; i < p_parent->i_children ; i++ )
894
 
            {
895
 
                p_parent->pp_children[i] = p_parent->pp_children[i+1];
896
 
            }
897
 
        }
898
 
    }
899
 
 
900
 
    if( p_parent->i_children )
901
 
    {
902
 
        p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
903
 
                               p_parent->i_children * sizeof(vlc_object_t *) );
904
 
    }
905
 
    else
906
 
    {
907
 
        free( p_parent->pp_children );
908
 
        p_parent->pp_children = NULL;
909
 
    }
910
 
}
911
 
 
912
 
/*****************************************************************************
913
 
 * SetAttachment: recursively set the b_attached flag of a subtree.
914
 
 *****************************************************************************
915
 
 * This function is used by the attach and detach functions to propagate
916
 
 * the b_attached flag in a subtree.
917
 
 *****************************************************************************/
918
 
static void SetAttachment( vlc_object_t *p_this, vlc_bool_t b_attached )
919
 
{
920
 
    int i_index;
921
 
 
922
 
    for( i_index = p_this->i_children ; i_index-- ; )
923
 
    {
924
 
        SetAttachment( p_this->pp_children[i_index], b_attached );
925
 
    }
926
 
 
927
 
    p_this->b_attached = b_attached;
928
 
}
 
1218
static vlc_object_t * FindObjectName( vlc_object_t *p_this,
 
1219
                                      const char *psz_name,
 
1220
                                      int i_mode )
 
1221
{
 
1222
    int i;
 
1223
    vlc_object_t *p_tmp;
 
1224
 
 
1225
    switch( i_mode & 0x000f )
 
1226
    {
 
1227
    case FIND_PARENT:
 
1228
        p_tmp = p_this->p_parent;
 
1229
        if( p_tmp )
 
1230
        {
 
1231
            if( p_tmp->psz_object_name
 
1232
                && !strcmp( p_tmp->psz_object_name, psz_name ) )
 
1233
            {
 
1234
                vlc_object_yield( p_tmp );
 
1235
                return p_tmp;
 
1236
            }
 
1237
            else
 
1238
            {
 
1239
                return FindObjectName( p_tmp, psz_name, i_mode );
 
1240
            }
 
1241
        }
 
1242
        break;
 
1243
 
 
1244
    case FIND_CHILD:
 
1245
        for( i = vlc_internals( p_this )->i_children; i--; )
 
1246
        {
 
1247
            p_tmp = vlc_internals( p_this )->pp_children[i];
 
1248
            if( p_tmp->psz_object_name
 
1249
                && !strcmp( p_tmp->psz_object_name, psz_name ) )
 
1250
            {
 
1251
                vlc_object_yield( p_tmp );
 
1252
                return p_tmp;
 
1253
            }
 
1254
            else if( vlc_internals( p_tmp )->i_children )
 
1255
            {
 
1256
                p_tmp = FindObjectName( p_tmp, psz_name, i_mode );
 
1257
                if( p_tmp )
 
1258
                {
 
1259
                    return p_tmp;
 
1260
                }
 
1261
            }
 
1262
        }
 
1263
        break;
 
1264
 
 
1265
    case FIND_ANYWHERE:
 
1266
        /* Handled in vlc_object_find */
 
1267
        break;
 
1268
    }
 
1269
 
 
1270
    return NULL;
 
1271
}
 
1272
 
929
1273
 
930
1274
static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
931
1275
{
932
 
    char psz_children[20], psz_refcount[20], psz_thread[20], psz_name[50];
 
1276
    char psz_children[20], psz_refcount[20], psz_thread[30], psz_name[50],
 
1277
         psz_parent[20];
933
1278
 
934
 
    psz_name[0] = '\0';
 
1279
    memset( &psz_name, 0, sizeof(psz_name) );
935
1280
    if( p_this->psz_object_name )
936
1281
    {
937
 
        snprintf( psz_name, 50, " \"%s\"", p_this->psz_object_name );
938
 
        psz_name[48] = '\"';
939
 
        psz_name[49] = '\0';
 
1282
        snprintf( psz_name, 49, " \"%s\"", p_this->psz_object_name );
 
1283
        if( psz_name[48] )
 
1284
            psz_name[48] = '\"';
940
1285
    }
941
1286
 
942
1287
    psz_children[0] = '\0';
943
 
    switch( p_this->i_children )
 
1288
    switch( vlc_internals( p_this )->i_children )
944
1289
    {
945
1290
        case 0:
946
1291
            break;
948
1293
            strcpy( psz_children, ", 1 child" );
949
1294
            break;
950
1295
        default:
951
 
            snprintf( psz_children, 20,
952
 
                      ", %i children", p_this->i_children );
953
 
            psz_children[19] = '\0';
 
1296
            snprintf( psz_children, 19, ", %i children",
 
1297
                      vlc_internals( p_this )->i_children );
954
1298
            break;
955
1299
    }
956
1300
 
957
1301
    psz_refcount[0] = '\0';
958
 
    if( p_this->i_refcount )
959
 
    {
960
 
        snprintf( psz_refcount, 20, ", refcount %i", p_this->i_refcount );
961
 
        psz_refcount[19] = '\0';
962
 
    }
 
1302
    if( vlc_internals( p_this )->i_refcount > 0 )
 
1303
        snprintf( psz_refcount, 19, ", refcount %u",
 
1304
                  vlc_internals( p_this )->i_refcount );
963
1305
 
964
1306
    psz_thread[0] = '\0';
965
 
    if( p_this->b_thread )
966
 
    {
967
 
        snprintf( psz_thread, 20, " (thread %d)", (int)p_this->thread_id );
968
 
        psz_thread[19] = '\0';
969
 
    }
970
 
 
971
 
    printf( " %so %.8i %s%s%s%s%s\n", psz_prefix,
 
1307
    if( vlc_internals( p_this )->b_thread )
 
1308
        snprintf( psz_thread, 29, " (thread %lu)",
 
1309
                  (unsigned long)vlc_internals( p_this )->thread_id );
 
1310
 
 
1311
    psz_parent[0] = '\0';
 
1312
    if( p_this->p_parent )
 
1313
        snprintf( psz_parent, 19, ", parent %i", p_this->p_parent->i_object_id );
 
1314
 
 
1315
    printf( " %so %.8i %s%s%s%s%s%s\n", psz_prefix,
972
1316
            p_this->i_object_id, p_this->psz_object_type,
973
 
            psz_name, psz_thread, psz_refcount, psz_children );
 
1317
            psz_name, psz_thread, psz_refcount, psz_children,
 
1318
            psz_parent );
974
1319
}
975
1320
 
976
1321
static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
989
1334
        return;
990
1335
    }
991
1336
 
992
 
    for( i = 0 ; i < p_this->i_children ; i++ )
 
1337
    for( i = 0 ; i < vlc_internals( p_this )->i_children ; i++ )
993
1338
    {
994
1339
        if( i_level )
995
1340
        {
1001
1346
            }
1002
1347
        }
1003
1348
 
1004
 
        if( i == p_this->i_children - 1 )
 
1349
        if( i == vlc_internals( p_this )->i_children - 1 )
1005
1350
        {
1006
1351
            psz_foo[i_level] = '`';
1007
1352
        }
1013
1358
        psz_foo[i_level+1] = '-';
1014
1359
        psz_foo[i_level+2] = '\0';
1015
1360
 
1016
 
        DumpStructure( p_this->pp_children[i], i_level + 2, psz_foo );
 
1361
        DumpStructure( vlc_internals( p_this )->pp_children[i], i_level + 2,
 
1362
                       psz_foo );
1017
1363
    }
1018
1364
}
1019
1365
 
1051
1397
        return;
1052
1398
    }
1053
1399
 
1054
 
    p_object->i_refcount++;
 
1400
    vlc_object_yield( p_object );
1055
1401
 
1056
1402
    p_list->p_values[i_index].p_object = p_object;
1057
1403
 
1073
1419
        return;
1074
1420
    }
1075
1421
 
1076
 
    p_object->i_refcount++;
 
1422
    vlc_object_yield( p_object );
1077
1423
 
1078
1424
    p_list->p_values[p_list->i_count].p_object = p_object;
1079
1425
    p_list->i_count++;
1086
1432
    vlc_object_t *p_tmp;
1087
1433
    int i, i_count = 0;
1088
1434
 
1089
 
    for( i = 0; i < p_this->i_children; i++ )
 
1435
    for( i = 0; i < vlc_internals( p_this )->i_children; i++ )
1090
1436
    {
1091
 
        p_tmp = p_this->pp_children[i];
 
1437
        p_tmp = vlc_internals( p_this )->pp_children[i];
1092
1438
 
1093
1439
        if( p_tmp->i_object_type == i_type )
1094
1440
        {
1095
1441
            i_count++;
1096
1442
        }
1097
 
 
1098
 
        if( p_tmp->i_children )
1099
 
        {
1100
 
            i_count += CountChildren( p_tmp, i_type );
1101
 
        }
 
1443
        i_count += CountChildren( p_tmp, i_type );
1102
1444
    }
1103
1445
 
1104
1446
    return i_count;
1109
1451
    vlc_object_t *p_tmp;
1110
1452
    int i;
1111
1453
 
1112
 
    for( i = 0; i < p_this->i_children; i++ )
 
1454
    for( i = 0; i < vlc_internals( p_this )->i_children; i++ )
1113
1455
    {
1114
 
        p_tmp = p_this->pp_children[i];
 
1456
        p_tmp = vlc_internals( p_this )->pp_children[i];
1115
1457
 
1116
1458
        if( p_tmp->i_object_type == i_type )
1117
 
        {
1118
1459
            ListReplace( p_list, p_tmp, p_list->i_count++ );
1119
 
        }
1120
 
 
1121
 
        if( p_tmp->i_children )
1122
 
        {
1123
 
            ListChildren( p_list, p_tmp, i_type );
1124
 
        }
1125
 
    }
1126
 
}
 
1460
 
 
1461
        ListChildren( p_list, p_tmp, i_type );
 
1462
    }
 
1463
}
 
1464
 
 
1465
#ifdef LIBVLC_REFCHECK
 
1466
# if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE)
 
1467
#  include <execinfo.h>
 
1468
# endif
 
1469
 
 
1470
void vlc_refcheck (vlc_object_t *obj)
 
1471
{
 
1472
    static unsigned errors = 0;
 
1473
    if (errors > 100)
 
1474
        return;
 
1475
 
 
1476
    /* Anyone can use the root object (though it should not exist) */
 
1477
    if (obj == VLC_OBJECT (vlc_global ()))
 
1478
        return;
 
1479
 
 
1480
    /* Anyone can use its libvlc instance object */
 
1481
    if (obj == VLC_OBJECT (obj->p_libvlc))
 
1482
        return;
 
1483
 
 
1484
    /* The thread that created the object holds the initial reference */
 
1485
    vlc_object_internals_t *priv = vlc_internals (obj);
 
1486
#if defined (LIBVLC_USE_PTHREAD)
 
1487
    if (pthread_equal (priv->creator_id, pthread_self ()))
 
1488
#elif defined WIN32
 
1489
    if (priv->creator_id == GetCurrentThreadId ())
 
1490
#else
 
1491
    if (0)
 
1492
#endif
 
1493
        return;
 
1494
 
 
1495
    /* A thread can use its own object without references! */
 
1496
    vlc_object_t *caller = vlc_threadobj ();
 
1497
    if (caller == obj)
 
1498
        return;
 
1499
#if 0
 
1500
    /* The calling thread is younger than the object.
 
1501
     * Access could be valid through cross-thread synchronization;
 
1502
     * we would need better accounting. */
 
1503
    if (caller && (caller->i_object_id > obj->i_object_id))
 
1504
        return;
 
1505
#endif
 
1506
    int refs;
 
1507
    vlc_spin_lock (&priv->ref_spin);
 
1508
    refs = priv->i_refcount;
 
1509
    vlc_spin_unlock (&priv->ref_spin);
 
1510
 
 
1511
    for (held_list_t *hlcur = vlc_threadvar_get (&held_objects);
 
1512
         hlcur != NULL; hlcur = hlcur->next)
 
1513
        if (hlcur->obj == obj)
 
1514
            return;
 
1515
 
 
1516
    fprintf (stderr, "The %s %s thread object is accessing...\n"
 
1517
             "the %s %s object without references.\n",
 
1518
             caller && caller->psz_object_name
 
1519
                     ? caller->psz_object_name : "unnamed",
 
1520
             caller ? caller->psz_object_type : "main",
 
1521
             obj->psz_object_name ? obj->psz_object_name : "unnamed",
 
1522
             obj->psz_object_type);
 
1523
    fflush (stderr);
 
1524
 
 
1525
#ifdef HAVE_BACKTRACE
 
1526
    void *stack[20];
 
1527
    int stackdepth = backtrace (stack, sizeof (stack) / sizeof (stack[0]));
 
1528
    backtrace_symbols_fd (stack, stackdepth, 2);
 
1529
#endif
 
1530
 
 
1531
    if (++errors == 100)
 
1532
        fprintf (stderr, "Too many reference errors!\n");
 
1533
}
 
1534
 
 
1535
static void held_objects_destroy (void *data)
 
1536
{
 
1537
    VLC_UNUSED( data );
 
1538
    held_list_t *hl = vlc_threadvar_get (&held_objects);
 
1539
    vlc_object_t *caller = vlc_threadobj ();
 
1540
 
 
1541
    while (hl != NULL)
 
1542
    {
 
1543
        held_list_t *buf = hl->next;
 
1544
        vlc_object_t *obj = hl->obj;
 
1545
 
 
1546
        fprintf (stderr, "The %s %s thread object leaked a reference to...\n"
 
1547
                         "the %s %s object.\n",
 
1548
                 caller && caller->psz_object_name
 
1549
                     ? caller->psz_object_name : "unnamed",
 
1550
                 caller ? caller->psz_object_type : "main",
 
1551
                 obj->psz_object_name ? obj->psz_object_name : "unnamed",
 
1552
                 obj->psz_object_type);
 
1553
        free (hl);
 
1554
        hl = buf;
 
1555
    }
 
1556
}
 
1557
#endif