]> git.sesse.net Git - vlc/blob - src/misc/objects.c
c57cacd31e427d0a7d31a846b6436bb53fdd7f7b
[vlc] / src / misc / objects.c
1 /*****************************************************************************
2  * objects.c: vlc_object_t handling
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: objects.c,v 1.5 2002/06/02 15:51:30 gbazin Exp $
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  * 
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <vlc/vlc.h>
28
29 #ifdef HAVE_STDLIB_H
30 #   include <stdlib.h>                                          /* realloc() */
31 #endif
32
33 #include "stream_control.h"
34 #include "input_ext-intf.h"
35 #include "input_ext-dec.h"
36
37 #include "video.h"
38 #include "video_output.h"
39
40 #include "vdec_ext-plugins.h"
41
42 #include "audio_output.h"
43
44 #include "playlist.h"
45 #include "interface.h"
46
47 /*****************************************************************************
48  * Local prototypes
49  *****************************************************************************/
50 static vlc_object_t * vlc_object_find_inner( vlc_object_t *, int, int );
51 static void vlc_object_detach_inner( vlc_object_t *, vlc_object_t * );
52 static void vlc_dumpstructure_inner( vlc_object_t *, int, char * );
53
54 /*****************************************************************************
55  * vlc_object_create: initialize a vlc object
56  *****************************************************************************
57  * This function allocates memory for a vlc object and initializes it. If
58  * i_type is not a known value such as VLC_OBJECT_ROOT, VLC_OBJECT_VOUT and
59  * so on, vlc_object_create will use its value for the object size.
60  *****************************************************************************/
61 void * __vlc_object_create( vlc_object_t *p_this, int i_type )
62 {
63     vlc_object_t * p_new;
64     char *         psz_type;
65     size_t         i_size;
66
67     switch( i_type )
68     {
69         case VLC_OBJECT_ROOT:
70             i_size = sizeof(vlc_t);
71             psz_type = "root";
72             break;
73         case VLC_OBJECT_MODULE:
74             i_size = sizeof(module_t);
75             psz_type = "module";
76             break;
77         case VLC_OBJECT_INTF:
78             i_size = sizeof(intf_thread_t);
79             psz_type = "interface";
80             break;
81         case VLC_OBJECT_PLAYLIST:
82             i_size = sizeof(playlist_t);
83             psz_type = "playlist";
84             break;
85         case VLC_OBJECT_INPUT:
86             i_size = sizeof(input_thread_t);
87             psz_type = "input";
88             break;
89         case VLC_OBJECT_DECODER:
90             i_size = sizeof(decoder_fifo_t);
91             psz_type = "decoder";
92             break;
93         case VLC_OBJECT_VOUT:
94             i_size = sizeof(vout_thread_t);
95             psz_type = "video output";
96             break;
97         case VLC_OBJECT_AOUT:
98             i_size = sizeof(aout_thread_t);
99             psz_type = "audio output";
100             break;
101         default:
102             i_size = i_type > sizeof(vlc_object_t)
103                    ? i_type : sizeof(vlc_object_t);
104             i_type = VLC_OBJECT_PRIVATE;
105             psz_type = "private";
106             break;
107     }
108
109     p_new = malloc( i_size );
110
111     if( !p_new )
112     {
113         return NULL;
114     }
115
116     memset( p_new, 0, i_size );
117
118     p_new->i_object_type = i_type;
119     p_new->psz_object_type = psz_type;
120
121     p_new->psz_object_name = NULL;
122
123     p_new->i_refcount = 0;
124     p_new->b_die = 0;
125     p_new->b_error = 0;
126
127     /* If i_type is root, then p_new is our own p_vlc */
128     if( i_type == VLC_OBJECT_ROOT )
129     {
130         p_new->p_vlc = (vlc_t*)p_new;
131         p_new->p_vlc->i_counter = 0;
132         p_new->i_object_id = 0;
133     }
134     else
135     {
136         p_new->p_vlc = p_this->p_vlc;
137
138         vlc_mutex_lock( &p_this->p_vlc->structure_lock );
139         p_new->p_vlc->i_counter++;
140         p_new->i_object_id = p_new->p_vlc->i_counter;
141         vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
142     }
143
144     p_new->pp_parents = NULL;
145     p_new->i_parents = 0;
146     p_new->pp_children = NULL;
147     p_new->i_children = 0;
148
149     //msg_Dbg( p_new, "created object" );
150
151     return p_new;
152 }
153
154 /*****************************************************************************
155  * vlc_object_destroy: destroy a vlc object
156  *****************************************************************************
157  * This function destroys an object that has been previously allocated with
158  * vlc_object_create. The object's refcount must be zero and it must not be
159  * attached to other objects in any way.
160  *****************************************************************************/
161 void __vlc_object_destroy( vlc_object_t *p_this )
162 {
163     if( p_this->i_refcount )
164     {
165         msg_Err( p_this, "refcount is %i", p_this->i_refcount );
166         vlc_dumpstructure( p_this );
167     }
168
169     if( p_this->i_children )
170     {
171         msg_Err( p_this, "object still has children" );
172         vlc_dumpstructure( p_this );
173     }
174
175     if( p_this->i_parents )
176     {
177         msg_Err( p_this, "object still has parents" );
178         vlc_dumpstructure( p_this );
179     }
180
181     //msg_Dbg( p_this, "destroyed object" );
182
183     free( p_this );
184 }
185
186 /*****************************************************************************
187  * vlc_object_find: find a typed object and increment its refcount
188  *****************************************************************************
189  * This function recursively looks for a given object type. i_mode can be one
190  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
191  *****************************************************************************/
192 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
193 {
194     vlc_object_t *p_found;
195
196     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
197
198     /* If we are of the requested type ourselves, don't look further */
199     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
200     {
201         p_this->i_refcount++;
202         vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
203         return p_this;
204     }
205
206     /* Otherwise, recursively look for the object */
207     if( (i_mode & 0x000f) == FIND_ANYWHERE )
208     {
209         p_found = vlc_object_find_inner( CAST_TO_VLC_OBJECT(p_this->p_vlc),
210                                          i_type,
211                                          (i_mode & ~0x000f) | FIND_CHILD );
212     }
213     else
214     {
215         p_found = vlc_object_find_inner( p_this, i_type, i_mode );
216     }
217
218     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
219
220     return p_found;
221 }
222
223 static vlc_object_t * vlc_object_find_inner( vlc_object_t *p_this,
224                                              int i_type, int i_mode )
225 {
226     int i;
227     vlc_object_t *p_tmp;
228
229     switch( i_mode & 0x000f )
230     {
231     case FIND_PARENT:
232         for( i = p_this->i_parents; i--; )
233         {
234             p_tmp = p_this->pp_parents[i];
235             if( p_tmp->i_object_type == i_type )
236             {
237                 p_tmp->i_refcount++;
238                 return p_tmp;
239             }
240             else if( p_tmp->i_parents )
241             {
242                 p_tmp = vlc_object_find_inner( p_tmp, i_type, i_mode );
243                 if( p_tmp )
244                 {
245                     return p_tmp;
246                 }
247             }
248         }
249         break;
250
251     case FIND_CHILD:
252         for( i = p_this->i_children; i--; )
253         {
254             p_tmp = p_this->pp_children[i];
255             if( p_tmp->i_object_type == i_type )
256             {
257                 p_tmp->i_refcount++;
258                 return p_tmp;
259             }
260             else if( p_tmp->i_children )
261             {
262                 p_tmp = vlc_object_find_inner( p_tmp, i_type, i_mode );
263                 if( p_tmp )
264                 {
265                     return p_tmp;
266                 }
267             }
268         }
269         break;
270
271     case FIND_ANYWHERE:
272         /* Handled in vlc_object_find */
273         break;
274     }
275
276     return NULL;
277 }
278
279 /*****************************************************************************
280  * vlc_object_yield: increment an object refcount
281  *****************************************************************************/
282 void __vlc_object_yield( vlc_object_t *p_this )
283 {
284     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
285     p_this->i_refcount++;
286     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
287 }
288
289 /*****************************************************************************
290  * vlc_object_release: decrement an object refcount
291  *****************************************************************************/
292 void __vlc_object_release( vlc_object_t *p_this )
293 {
294     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
295     p_this->i_refcount--;
296     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
297 }
298
299 /*****************************************************************************
300  * vlc_object_attach: attach object to a parent object
301  *****************************************************************************
302  * This function sets p_this as a child of p_parent, and p_parent as a parent
303  * of p_this. This link can be undone using vlc_object_detach.
304  *****************************************************************************/
305 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
306 {
307     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
308
309     p_this->i_parents++;
310     p_this->pp_parents = (vlc_object_t **)realloc( p_this->pp_parents,
311                             p_this->i_parents * sizeof(vlc_object_t *) );
312     p_this->pp_parents[p_this->i_parents - 1] = p_parent;
313
314     p_parent->i_children++;
315     p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
316                                p_parent->i_children * sizeof(vlc_object_t *) );
317     p_parent->pp_children[p_parent->i_children - 1] = p_this;
318
319     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
320 }
321
322 #if 0 /* UNUSED */
323 /* vlc_object_setchild: attach a child object */
324 void __vlc_object_setchild( vlc_object_t *p_this, vlc_object_t *p_child )
325 {
326     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
327
328     p_this->i_children++;
329     p_this->pp_children = (vlc_object_t **)realloc( p_this->pp_children,
330                              p_this->i_children * sizeof(vlc_object_t *) );
331     p_this->pp_children[p_this->i_children - 1] = p_child;
332
333     p_child->i_parents++;
334     p_child->pp_parents = (vlc_object_t **)realloc( p_child->pp_parents,
335                              p_child->i_parents * sizeof(vlc_object_t *) );
336     p_child->pp_parents[p_child->i_parents - 1] = p_this;
337
338     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
339 }
340 #endif
341
342 /*****************************************************************************
343  * vlc_object_detach_all: detach object from its parents
344  *****************************************************************************
345  * This function unlinks an object from all its parents. It is up to the
346  * object to get rid of its children, so this function doesn't do anything
347  * with them.
348  *****************************************************************************/
349 void __vlc_object_detach_all( vlc_object_t *p_this )
350 {
351     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
352
353     /* FIXME: BORK ! BORK ! BORK !!! THIS STUFF IS BORKED !! FIXME */
354     while( p_this->i_parents )
355     {
356         /* Not very effective because we know the index, but we'd have to
357          * parse p_parent->pp_children anyway. Plus, we remove duplicates
358          * by not using the object's index */
359         vlc_object_detach_inner( p_this, p_this->pp_parents[0] );
360     }
361
362     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
363 }
364
365 /*****************************************************************************
366  * vlc_object_detach: remove a parent/child link
367  *****************************************************************************
368  * This function removes all links between an object and a given parent.
369  *****************************************************************************/
370 void __vlc_object_detach( vlc_object_t *p_this, vlc_object_t *p_parent )
371 {
372     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
373     vlc_object_detach_inner( p_this, p_parent );
374     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
375 }
376
377 static void vlc_object_detach_inner( vlc_object_t *p_this,
378                                      vlc_object_t *p_parent )
379 {
380     int i_index, i;
381
382     /* Remove all of p_this's parents which are p_parent */
383     for( i_index = p_this->i_parents ; i_index-- ; )
384     {
385         if( p_this->pp_parents[i_index] == p_parent )
386         {
387             p_this->i_parents--;
388             for( i = i_index ; i < p_this->i_parents ; i++ )
389             {
390                 p_this->pp_parents[i] = p_this->pp_parents[i+1];
391             }
392         }
393     }
394
395     if( p_this->i_parents )
396     {
397         p_this->pp_parents = (vlc_object_t **)realloc( p_this->pp_parents,
398                                 p_this->i_parents * sizeof(vlc_object_t *) );
399     }
400     else
401     {
402         free( p_this->pp_parents );
403         p_this->pp_parents = NULL;
404     }
405
406     /* Remove all of p_parent's children which are p_this */
407     for( i_index = p_parent->i_children ; i_index-- ; )
408     {
409         if( p_parent->pp_children[i_index] == p_this )
410         {
411             p_parent->i_children--;
412             for( i = i_index ; i < p_parent->i_children ; i++ )
413             {
414                 p_parent->pp_children[i] = p_parent->pp_children[i+1];
415             }
416         }
417     }
418
419     if( p_parent->i_children )
420     {
421         p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
422                                p_parent->i_children * sizeof(vlc_object_t *) );
423     }
424     else
425     {
426         free( p_parent->pp_children );
427         p_parent->pp_children = NULL;
428     }
429 }
430
431 /*****************************************************************************
432  * vlc_dumpstructure: print the current vlc structure
433  *****************************************************************************
434  * This function prints an ASCII tree showing the connections between vlc
435  * objects, and additional information such as their refcount, thread ID,
436  * address, etc.
437  *****************************************************************************/
438 void __vlc_dumpstructure( vlc_object_t *p_this )
439 {
440     char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
441
442     vlc_mutex_lock( &p_this->p_vlc->structure_lock );
443     psz_foo[0] = '|';
444     vlc_dumpstructure_inner( p_this, 0, psz_foo );
445     vlc_mutex_unlock( &p_this->p_vlc->structure_lock );
446 }
447
448 static void vlc_dumpstructure_inner( vlc_object_t *p_this,
449                                      int i_level, char *psz_foo )
450 {
451     int i;
452     char i_back = psz_foo[i_level];
453     char psz_children[20], psz_refcount[20], psz_thread[20], psz_name[50];
454
455     psz_name[0] = '\0';
456     if( p_this->psz_object_name )
457     {
458         snprintf( psz_name, 50, " \"%s\"", p_this->psz_object_name );
459         psz_name[48] = '\"';
460         psz_name[49] = '\0';
461     }
462
463     psz_children[0] = '\0';
464     switch( p_this->i_children )
465     {
466         case 0:
467             break;
468         case 1:
469             strcpy( psz_children, ", 1 child" );
470             break;
471         default:
472             snprintf( psz_children, 20, ", %i children", p_this->i_children );
473             psz_children[19] = '\0';
474             break;
475     }
476
477     psz_refcount[0] = '\0';
478     if( p_this->i_refcount )
479     {
480         snprintf( psz_refcount, 20, ", refcount %i", p_this->i_refcount );
481         psz_refcount[19] = '\0';
482     }
483
484     psz_thread[0] = '\0';
485     if( p_this->b_thread )
486     {
487         snprintf( psz_thread, 20, " (thread %d)", (int)p_this->thread_id );
488         psz_thread[19] = '\0';
489     }
490
491     psz_foo[i_level] = '\0';
492     msg_Info( p_this, "%so %s %p%s%s%s%s", psz_foo, p_this->psz_object_type,
493               p_this, psz_name, psz_thread, psz_refcount, psz_children );
494     psz_foo[i_level] = i_back;
495
496     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
497     {
498         msg_Warn( p_this, "structure tree is too deep" );
499         return;
500     }
501
502     for( i = 0 ; i < p_this->i_children ; i++ )
503     {
504         if( i_level )
505         {
506             psz_foo[i_level-1] = ' ';
507
508             if( psz_foo[i_level-2] == '`' )
509             {
510                 psz_foo[i_level-2] = ' ';
511             }
512         }
513
514         if( i == p_this->i_children - 1 )
515         {
516             psz_foo[i_level] = '`';
517         }
518         else
519         {
520             psz_foo[i_level] = '|';
521         }
522
523         psz_foo[i_level+1] = '-';
524         psz_foo[i_level+2] = '\0';
525
526         vlc_dumpstructure_inner( p_this->pp_children[i], i_level + 2, psz_foo );
527     }
528 }
529