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