]> git.sesse.net Git - vlc/blob - src/misc/modules.c
94b67231c775c73778195e08bc26bac2d04d5fe5
[vlc] / src / misc / modules.c
1 /*****************************************************************************
2  * modules.c : Built-in and dynamic modules management functions
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  *
6  * Authors: Samuel Hocevar <sam@zoy.org>
7  *          Ethan C. Baldridge <BaldridgeE@cadmus.com>
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 #include "defs.h"
24
25 #include "config.h"
26
27 /* Some faulty libcs have a broken struct dirent when _FILE_OFFSET_BITS
28  * is set to 64. Don't try to be cleverer. */
29 #ifdef _FILE_OFFSET_BITS
30 #undef _FILE_OFFSET_BITS
31 #endif
32
33 #include <stdlib.h>                                      /* free(), strtol() */
34 #include <stdio.h>                                              /* sprintf() */
35 #include <string.h>                                              /* strdup() */
36 #include <dirent.h>
37
38 #if defined(HAVE_DLFCN_H)                                /* Linux, BSD, Hurd */
39 #include <dlfcn.h>                           /* dlopen(), dlsym(), dlclose() */
40
41 #elif defined(HAVE_IMAGE_H)                                          /* BeOS */
42 #include <image.h>
43
44 #else
45 /* FIXME: this isn't supposed to be an error */
46 #error no dynamic plugins available on your system !
47 #endif
48
49 #ifdef SYS_BEOS
50 #include "beos_specific.h"
51 #endif
52
53 #include "common.h"
54 #include "threads.h"
55
56 #include "intf_msg.h"
57 #include "modules.h"
58 #include "modules_core.h"
59
60 /* Local prototypes */
61 static int AllocateDynModule( module_bank_t * p_bank, char * psz_filename );
62 static int HideModule( module_t * p_module );
63 static int FreeModule( module_bank_t * p_bank, module_t * p_module );
64 static int LockModule( module_t * p_module );
65 static int UnlockModule( module_t * p_module );
66 static int CallSymbol( module_t * p_module, char * psz_name );
67
68 /*****************************************************************************
69  * module_CreateBank: create the module bank.
70  *****************************************************************************
71  * This function creates a module bank structure.
72  *****************************************************************************/
73 module_bank_t * module_CreateBank( void )
74 {
75     module_bank_t * p_bank;
76
77     p_bank = malloc( sizeof( module_bank_t ) );
78
79     return( p_bank );
80 }
81
82 /*****************************************************************************
83  * module_InitBank: create the module bank.
84  *****************************************************************************
85  * This function creates a module bank structure and fills it with the
86  * built-in modules, as well as all the dynamic modules it can find.
87  *****************************************************************************/
88 void module_InitBank( module_bank_t * p_bank )
89 {
90     static char * path[] = { ".", "lib", PLUGIN_PATH, NULL } ;
91
92     char **         ppsz_path = path;
93     char *          psz_file;
94 #ifdef SYS_BEOS
95     char *          psz_vlcpath = beos_GetProgramPath();
96     int             i_vlclen = strlen( psz_vlcpath );
97 #endif
98     DIR *           dir;
99     struct dirent * file;
100
101     p_bank->first = NULL;
102     vlc_mutex_init( &p_bank->lock );
103
104     intf_WarnMsg( 1, "module: module bank initialized" );
105
106     for( ; *ppsz_path != NULL ; ppsz_path++ )
107     {
108         if( (dir = opendir( *ppsz_path )) )
109         {
110             /* Store strlen(*ppsz_path) for later use. */
111             int i_dirlen = strlen( *ppsz_path );
112
113             /* Parse the directory and try to load all files it contains. */
114             while( (file = readdir( dir )) )
115             {
116                 int i_filelen = strlen( file->d_name );
117
118                 /* We only load files ending with ".so" */
119                 if( i_filelen > 3
120                         && !strncmp( file->d_name + i_filelen - 3, ".so", 3 ) )
121                 {
122 #ifdef SYS_BEOS
123                     /* Under BeOS, we need to add beos_GetProgramPath() to
124                      * access files under the current directory */
125                     if( strncmp( file->d_name, "/", 1 ) )
126                     {
127                         psz_file = malloc( i_vlclen + i_dirlen
128                                                + i_filelen + 3 );
129                         if( psz_file == NULL )
130                         {
131                             continue;
132                         }
133                         sprintf( psz_file, "%s/%s/%s", psz_vlcpath,
134                                  *ppsz_path, file->d_name );
135                     }
136                     else
137 #endif
138                     {
139                         psz_file = malloc( i_dirlen + i_filelen + 2 );
140                         if( psz_file == NULL )
141                         {
142                             continue;
143                         }
144                         sprintf( psz_file, "%s/%s", *ppsz_path, file->d_name );
145                     }
146                     /* We created a nice filename -- now we just try to load
147                      * it as a dynamic module. */
148                     AllocateDynModule( p_bank, psz_file );
149
150                     /* We don't care if the allocation succeeded */
151                     free( psz_file );
152                 }
153             }
154         }
155     }
156
157     return;
158 }
159
160 /*****************************************************************************
161  * module_DestroyBank: destroy the module bank.
162  *****************************************************************************
163  * This function unloads all unused dynamic modules and removes the module
164  * bank in case of success.
165  *****************************************************************************/
166 void module_DestroyBank( module_bank_t * p_bank )
167 {
168     module_t * p_next;
169
170     while( p_bank->first != NULL )
171     {
172         if( FreeModule( p_bank, p_bank->first ) )
173         {
174             /* Module deletion failed */
175             intf_ErrMsg( "module error: `%s' can't be removed. trying harder.",
176                          p_bank->first->psz_name );
177
178             /* We just free the module by hand. Niahahahahaha. */
179             p_next = p_bank->first->next;
180             free(p_bank->first);
181             p_bank->first = p_next;
182         }
183     }
184
185     /* Destroy the lock */
186     vlc_mutex_destroy( &p_bank->lock );
187     
188     /* We can free the module bank */
189     free( p_bank );
190
191     return;
192 }
193
194 /*****************************************************************************
195  * module_ResetBank: reset the module bank.
196  *****************************************************************************
197  * This function resets the module bank by unloading all unused dynamic
198  * modules.
199  *****************************************************************************/
200 void module_ResetBank( module_bank_t * p_bank )
201 {
202     intf_ErrMsg( "FIXME: module_ResetBank unimplemented" );
203     return;
204 }
205
206 /*****************************************************************************
207  * module_ManageBank: manage the module bank.
208  *****************************************************************************
209  * This function parses the module bank and hides modules that have been
210  * unused for a while.
211  *****************************************************************************/
212 void module_ManageBank( module_bank_t * p_bank )
213 {
214     module_t * p_module;
215
216     /* We take the global lock */
217     vlc_mutex_lock( &p_bank->lock );
218
219     /* Parse the module list to see if any modules need to be unloaded */
220     for( p_module = p_bank->first ;
221          p_module != NULL ;
222          p_module = p_module->next )
223     {
224         /* If the module is unused and if it is a dynamic module... */
225         if( p_module->i_usage == 0 && !p_module->b_builtin )
226         {
227             if( p_module->i_unused_delay < MODULE_HIDE_DELAY )
228             {
229                 p_module->i_unused_delay++;
230             }
231             else
232             {
233                 intf_WarnMsg( 1, "module: hiding unused module `%s'",
234                               p_module->psz_name );
235                 HideModule( p_module );
236             }
237         }
238     }
239
240     /* We release the global lock */
241     vlc_mutex_unlock( &p_bank->lock );
242
243     return;
244 }
245
246 /*****************************************************************************
247  * module_Need: return the best module function, given a capability list.
248  *****************************************************************************
249  * This function returns the module that best fits the asked capabilities.
250  *****************************************************************************/
251 module_t * module_Need( module_bank_t *p_bank,
252                         int i_capabilities, void *p_data )
253 {
254     module_t * p_module;
255     module_t * p_bestmodule = NULL;
256     int i_score, i_totalscore, i_bestscore = 0;
257     int i_index;
258
259     /* We take the global lock */
260     vlc_mutex_lock( &p_bank->lock );
261
262     /* Parse the module list for capabilities and probe each of them */
263     for( p_module = p_bank->first ;
264          p_module != NULL ;
265          p_module = p_module->next )
266     {
267         /* Test that this module can do everything we need */
268         if( ( p_module->i_capabilities & i_capabilities ) == i_capabilities )
269         {
270             i_totalscore = 0;
271
272             LockModule( p_module );
273
274             /* Parse all the requested capabilities and test them */
275             for( i_index = 0 ; (1 << i_index) <= i_capabilities ; i_index++ )
276             {
277                 if( ( (1 << i_index) & i_capabilities ) )
278                 {
279                     i_score = ( (function_list_t *)p_module->p_functions)
280                                                   [i_index].pf_probe( p_data );
281
282                     if( i_score )
283                     {
284                         i_totalscore += i_score;
285                     }
286                     else
287                     {
288                         break;
289                     }
290                 }
291             }
292
293             /* If the high score was broken, we have a new champion */
294             if( i_totalscore > i_bestscore )
295             {
296                 /* Keep the current module locked, but release the previous */
297                 if( p_bestmodule != NULL )
298                 {
299                     UnlockModule( p_bestmodule );
300                 }
301
302                 /* This is the new best module */
303                 i_bestscore = i_totalscore;
304                 p_bestmodule = p_module;
305             }
306             else
307             {
308                 /* This module wasn't interesting, unlock it and forget it */
309                 UnlockModule( p_module );
310             }
311         }
312     }
313
314     /* We release the global lock */
315     vlc_mutex_unlock( &p_bank->lock );
316
317     if( p_bestmodule != NULL )
318     {
319         intf_WarnMsg( 1, "module: locking module `%s'",
320                       p_bestmodule->psz_name );
321     }
322
323     /* Don't forget that the module is still locked if bestmodule != NULL */
324     return( p_bestmodule );
325 }
326
327 /*****************************************************************************
328  * module_Unneed: decrease the usage count of a module.
329  *****************************************************************************
330  * This function must be called by the thread that called module_Need, to
331  * decrease the reference count and allow for hiding of modules.
332  *****************************************************************************/
333 void module_Unneed( module_bank_t * p_bank, module_t * p_module )
334 {
335     /* We take the global lock */
336     vlc_mutex_lock( &p_bank->lock );
337
338     /* Just unlock the module - we can't do anything if it fails,
339      * so there is no need to check the return value. */
340     UnlockModule( p_module );
341
342     intf_WarnMsg( 1, "module: unlocking module `%s'", p_module->psz_name );
343
344     /* We release the global lock */
345     vlc_mutex_unlock( &p_bank->lock );
346
347     return;
348 }
349
350 /*****************************************************************************
351  * Following functions are local.
352  *****************************************************************************/
353
354 /*****************************************************************************
355  * AllocateDynModule: load a module into memory and initialize it.
356  *****************************************************************************
357  * This function loads a dynamically loadable module and allocates a structure
358  * for its information data. The module can then be handled by module_Need,
359  * module_Unneed and HideModule. It can be removed by FreeModule.
360  *****************************************************************************/
361 static int AllocateDynModule( module_bank_t * p_bank, char * psz_filename )
362 {
363     module_t * p_module, * p_othermodule;
364     module_handle_t handle;
365
366     /* Try to dynamically load the module. */
367     if( module_load( psz_filename, &handle ) )
368     {
369         /* The dynamic module couldn't be opened */
370         intf_WarnMsgImm( 1, "module warning: cannot open %s (%s)",
371                          psz_filename, module_error() );
372         return( -1 );
373     }
374
375     /* Now that we have successfully loaded the module, we can
376      * allocate a structure for it */ 
377     p_module = malloc( sizeof( module_t ) );
378     if( p_module == NULL )
379     {
380         intf_ErrMsg( "module error: can't allocate p_module" );
381         module_unload( handle );
382         return( -1 );
383     }
384
385     /* We need to fill these since they may be needed by CallSymbol() */
386     p_module->psz_filename = psz_filename;
387     p_module->handle = handle;
388
389     /* Initialize the module : fill p_module->psz_name, etc. */
390     if( CallSymbol( p_module, "InitModule" ) != 0 )
391     {
392         /* We couldn't call InitModule() */
393         free( p_module );
394         module_unload( handle );
395         return( -1 );
396     }
397
398     /* Check that version numbers match */
399     if( strcmp( VERSION, p_module->psz_version ) )
400     {
401         free( p_module );
402         module_unload( handle );
403         return( -1 );
404     }
405
406     /* Check that we don't already have a module with this name */
407     for( p_othermodule = p_bank->first ;
408          p_othermodule != NULL ;
409          p_othermodule = p_othermodule->next )
410     {
411         if( !strcmp( p_othermodule->psz_name, p_module->psz_name ) )
412         {
413             free( p_module );
414             module_unload( handle );
415             return( -1 );
416         }
417     }
418
419     /* Activate the module : fill the capability structure, etc. */
420     if( CallSymbol( p_module, "ActivateModule" ) != 0 )
421     {
422         /* We couldn't call ActivateModule() */
423         free( p_module );
424         module_unload( handle );
425         return( -1 );
426     }
427
428     /* We strdup() these entries so that they are still valid when the
429      * module is unloaded. */
430     p_module->psz_filename = strdup( p_module->psz_filename );
431     p_module->psz_name = strdup( p_module->psz_name );
432     p_module->psz_longname = strdup( p_module->psz_longname );
433     p_module->psz_version = strdup( p_module->psz_version );
434     if( p_module->psz_filename == NULL 
435             || p_module->psz_name == NULL
436             || p_module->psz_longname == NULL
437             || p_module->psz_version == NULL )
438     {
439         intf_ErrMsg( "module error: can't duplicate strings" );
440         free( p_module->psz_filename );
441         free( p_module->psz_name );
442         free( p_module->psz_longname );
443         free( p_module->psz_version );
444         free( p_module );
445         module_unload( handle );
446         return( -1 );
447     }
448
449     /* Everything worked fine ! The module is ready to be added to the list. */
450     p_module->i_usage = 0;
451     p_module->i_unused_delay = 0;
452
453     p_module->b_builtin = 0;
454
455     /* Link module into the linked list */
456     if( p_bank->first != NULL )
457     {
458         p_bank->first->prev = p_module;
459     }
460     p_module->next = p_bank->first;
461     p_module->prev = NULL;
462     p_bank->first = p_module;
463
464     /* Immediate message so that a slow module doesn't make the user wait */
465     intf_WarnMsgImm( 1, "module: dynamic module `%s', %s",
466                      p_module->psz_name, p_module->psz_longname );
467
468     return( 0 );
469 }
470
471 /*****************************************************************************
472  * HideModule: remove a module from memory but keep its structure.
473  *****************************************************************************
474  * This function can only be called if i_usage == 0. It will make a call
475  * to the module's inner DeactivateModule() symbol, and then unload it
476  * from memory. A call to module_Need() will automagically load it again.
477  *****************************************************************************/
478 static int HideModule( module_t * p_module )
479 {
480     if( p_module->b_builtin )
481     {
482         /* A built-in module should never be hidden. */
483         intf_ErrMsg( "module error: trying to hide built-in module `%s'",
484                      p_module->psz_name );
485         return( -1 );
486     }
487
488     if( p_module->i_usage >= 1 )
489     {
490         intf_ErrMsg( "module error: trying to hide module `%s' which is still"
491                      " in use", p_module->psz_name );
492         return( -1 );
493     }
494
495     if( p_module->i_usage <= -1 )
496     {
497         intf_ErrMsg( "module error: trying to hide module `%s' which is already"
498                      " hidden", p_module->psz_name );
499         return( -1 );
500     }
501
502     /* Deactivate the module : free the capability structure, etc. */
503     if( CallSymbol( p_module, "DeactivateModule" ) != 0 )
504     {
505         /* We couldn't call DeactivateModule() -- looks nasty, but
506          * we can't do much about it. Just try to unload module anyway. */
507         module_unload( p_module->handle );
508         p_module->i_usage = -1;
509         return( -1 );
510     }
511
512     /* Everything worked fine, we can safely unload the module. */
513     module_unload( p_module->handle );
514     p_module->i_usage = -1;
515
516     return( 0 );
517 }
518
519 /*****************************************************************************
520  * FreeModule: delete a module and its structure.
521  *****************************************************************************
522  * This function can only be called if i_usage <= 0.
523  *****************************************************************************/
524 static int FreeModule( module_bank_t * p_bank, module_t * p_module )
525 {
526     /* If the module is not in use but is still in memory, we first have
527      * to hide it and remove it from memory before we can free the
528      * data structure. */
529     if( p_module->b_builtin )
530     {
531         if( p_module->i_usage != 0 )
532         {
533             intf_ErrMsg( "module error: trying to free builtin module `%s' with"
534                          " usage %i", p_module->psz_name, p_module->i_usage );
535             return( -1 );
536         }
537     }
538     else
539     {
540         if( p_module->i_usage >= 1 )
541         {
542             intf_ErrMsg( "module error: trying to free module `%s' which is"
543                          " still in use", p_module->psz_name );
544             return( -1 );
545         }
546
547         /* Two possibilities here: i_usage == -1 and the module is already
548          * unloaded, we can continue, or i_usage == 0, and we have to hide
549          * the module before going on. */
550         if( p_module->i_usage == 0 )
551         {
552             if( HideModule( p_module ) != 0 )
553             {
554                 return( -1 );
555             }
556         }
557     }
558
559     /* Unlink the module from the linked list. */
560     if( p_module == p_bank->first )
561     {
562         p_bank->first = p_module->next;
563     }
564
565     if( p_module->prev != NULL )
566     {
567         p_module->prev->next = p_module->next;
568     }
569
570     if( p_module->next != NULL )
571     {
572         p_module->next->prev = p_module->prev;
573     }
574
575     /* We free the structures that we strdup()ed in Allocate*Module(). */
576     free( p_module->psz_filename );
577     free( p_module->psz_name );
578     free( p_module->psz_longname );
579     free( p_module->psz_version );
580
581     free( p_module );
582
583     return( 0 );
584 }
585
586 /*****************************************************************************
587  * LockModule: increase the usage count of a module and load it if needed.
588  *****************************************************************************
589  * This function has to be called before a thread starts using a module. If
590  * the module is already loaded, we just increase its usage count. If it isn't
591  * loaded, we have to dynamically open it and initialize it.
592  * If you successfully call LockModule() at any moment, be careful to call
593  * UnlockModule() when you don't need it anymore.
594  *****************************************************************************/
595 static int LockModule( module_t * p_module )
596 {
597     if( p_module->i_usage >= 0 )
598     {
599         /* This module is already loaded and activated, we can return */
600         p_module->i_usage++;
601         return( 0 );
602     }
603
604     if( p_module->b_builtin )
605     {
606         /* A built-in module should always have a refcount >= 0 ! */
607         intf_ErrMsg( "module error: built-in module `%s' has refcount %i",
608                      p_module->psz_name, p_module->i_usage );
609         return( -1 );
610     }
611
612     if( p_module->i_usage != -1 )
613     {
614         /* This shouldn't happen. Ever. We have serious problems here. */
615         intf_ErrMsg( "module error: dynamic module `%s' has refcount %i",
616                      p_module->psz_name, p_module->i_usage );
617         return( -1 );
618     }
619
620     /* i_usage == -1, which means that the module isn't in memory */
621     if( module_load( p_module->psz_filename, &p_module->handle ) )
622     {
623         /* The dynamic module couldn't be opened */
624         intf_ErrMsg( "module error: cannot open %s (%s)",
625                      p_module->psz_filename, module_error() );
626         return( -1 );
627     }
628
629     /* FIXME: what to do if the guy modified the plugin while it was
630      * unloaded ? It makes XMMS crash nastily, perhaps we should try
631      * to be a bit more clever here. */
632
633     /* Activate the module : fill the capability structure, etc. */
634     if( CallSymbol( p_module, "ActivateModule" ) != 0 )
635     {
636         /* We couldn't call ActivateModule() -- looks nasty, but
637          * we can't do much about it. Just try to unload module. */
638         module_unload( p_module->handle );
639         p_module->i_usage = -1;
640         return( -1 );
641     }
642
643     /* Everything worked fine ! The module is ready to be used */
644     p_module->i_usage = 1;
645
646     return( 0 );
647 }
648
649 /*****************************************************************************
650  * UnlockModule: decrease the usage count of a module.
651  *****************************************************************************
652  * We decrease the usage count of a module so that we know when a module
653  * becomes unused and can be hidden.
654  *****************************************************************************/
655 static int UnlockModule( module_t * p_module )
656 {
657     if( p_module->i_usage <= 0 )
658     {
659         /* This shouldn't happen. Ever. We have serious problems here. */
660         intf_ErrMsg( "module error: trying to call module_Unneed() on `%s'"
661                      " which isn't even in use", p_module->psz_name );
662         return( -1 );
663     }
664
665     /* This module is still in use, we can return */
666     p_module->i_usage--;
667     p_module->i_unused_delay = 0;
668
669     return( 0 );
670 }
671
672 /*****************************************************************************
673  * CallSymbol: calls a module symbol.
674  *****************************************************************************
675  * This function calls a symbol given its name and a module structure. The
676  * symbol MUST refer to a function returning int and taking a module_t* as
677  * an argument.
678  *****************************************************************************/
679 static int CallSymbol( module_t * p_module, char * psz_name )
680 {
681     typedef int ( symbol_t ) ( module_t * p_module );
682     symbol_t * p_symbol;
683
684     /* Try to resolve the symbol */
685     p_symbol = module_getsymbol( p_module->handle, psz_name );
686
687     if( !p_symbol )
688     {
689         /* We couldn't load the symbol */
690         intf_WarnMsg( 1, "module warning: "
691                          "cannot find symbol %s in module %s (%s)",
692                          psz_name, p_module->psz_filename, module_error() );
693         return( -1 );
694     }
695
696     /* We can now try to call the symbol */
697     if( p_symbol( p_module ) != 0 )
698     {
699         /* With a well-written module we shouldn't have to print an
700          * additional error message here, but just make sure. */
701         intf_ErrMsg( "module error: failed calling symbol %s in module %s",
702                      psz_name, p_module->psz_filename );
703         return( -1 );
704     }
705
706     /* Everything worked fine, we can return */
707     return( 0 );
708 }
709