Commit 65d21833 authored by Clément Stenac's avatar Clément Stenac

Add facilities to report and enrich error messages.

The idea is that a given error should be reported only once to the user.
At the moment, for example, we can get:
- "no suitable access module" (printed by module_Need)
 - "unable to create access" (printed by input/access)
 - "unable to open stream" (printed by input/input)
 - ...

The facilities provided here are:
* msg_StackSet( code, message ) : "throw" a new error
* msg_StackAdd( message ) : Append a message allowing to trace the message
* msg_StackMsg() : Retrieve the message

So, in the previous example, module_Need would msg_StackSet( code, "no
suitable access module"), then input/input would add "unable to create
access" and finally, input/input can print the "unable to open stream:
unable to create access: no suitable module" message.

The three functions are context-free, you don't need a vlc_object, so
that we can add verbose error reporting everywhere.
parent 7e5c6ea5
...@@ -1177,6 +1177,14 @@ VLC_EXPORT( const char *, VLC_Changeset, ( void ) ); ...@@ -1177,6 +1177,14 @@ VLC_EXPORT( const char *, VLC_Changeset, ( void ) );
#include "main.h" #include "main.h"
#include "vlc_configuration.h" #include "vlc_configuration.h"
/** The global thread var for msg stack context
* We store this as a static global variable so we don't need a vlc_object_t
* everywhere.
* This key is created in vlc_threads_init and is therefore ready to use at
* the very beginning of the universe */
extern vlc_threadvar_t msg_context_global_key;
#if defined( __BORLANDC__ ) #if defined( __BORLANDC__ )
# undef PACKAGE # undef PACKAGE
# define PACKAGE # define PACKAGE
......
...@@ -44,9 +44,19 @@ int vlc_mutex_unlock( vlc_mutex_t * ) ; ...@@ -44,9 +44,19 @@ int vlc_mutex_unlock( vlc_mutex_t * ) ;
* @{ * @{
*/ */
/** Internal message stack context */
typedef struct
{
int i_code;
char * psz_message;
} msg_context_t;
VLC_EXPORT( void, msg_StackSet, ( int, const char*, ... ) );
VLC_EXPORT( void, msg_StackAdd, ( const char*, ... ) );
VLC_EXPORT( const char*, msg_StackMsg, ( void ) );
/** /**
* Store a single message. * Store a single message sent to user.
*/ */
typedef struct typedef struct
{ {
......
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
#error You are not libvlc or one of its plugins. You cannot include this file #error You are not libvlc or one of its plugins. You cannot include this file
#endif #endif
#ifndef _VLC_THREADS_H_
#define _VLC_THREADS_H_
#include <stdio.h> #include <stdio.h>
#if defined(DEBUG) && defined(HAVE_SYS_TIME_H) #if defined(DEBUG) && defined(HAVE_SYS_TIME_H)
...@@ -274,3 +277,4 @@ typedef struct ...@@ -274,3 +277,4 @@ typedef struct
#endif #endif
#endif
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
#error You are not libvlc or one of its plugins. You cannot include this file #error You are not libvlc or one of its plugins. You cannot include this file
#endif #endif
#ifndef _VLC_THREADFUNCS_H_
#define _VLC_THREADFUNCS_H_
/***************************************************************************** /*****************************************************************************
* Function definitions * Function definitions
*****************************************************************************/ *****************************************************************************/
...@@ -557,11 +560,7 @@ static inline int __vlc_cond_wait( const char * psz_file, int i_line, ...@@ -557,11 +560,7 @@ static inline int __vlc_cond_wait( const char * psz_file, int i_line,
/***************************************************************************** /*****************************************************************************
* vlc_threadvar_set: create: set the value of a thread-local variable * vlc_threadvar_set: create: set the value of a thread-local variable
*****************************************************************************/ *****************************************************************************/
#define vlc_threadvar_set( P_TLS , P_VAL ) \ static inline int vlc_threadvar_set( vlc_threadvar_t * p_tls, void *p_value )
__vlc_threadvar_set( __FILE__, __LINE__, P_TLS, P_VAL )
static inline int __vlc_threadvar_set( char* psz_file, int line,
vlc_threadvar_t * p_tls, void *p_value )
{ {
int i_ret; int i_ret;
...@@ -588,11 +587,7 @@ static inline int __vlc_threadvar_set( char* psz_file, int line, ...@@ -588,11 +587,7 @@ static inline int __vlc_threadvar_set( char* psz_file, int line,
/***************************************************************************** /*****************************************************************************
* vlc_threadvar_get: create: get the value of a thread-local variable * vlc_threadvar_get: create: get the value of a thread-local variable
*****************************************************************************/ *****************************************************************************/
#define vlc_threadvar_get( P_TLS ) \ static inline void* vlc_threadvar_get( vlc_threadvar_t * p_tls )
__vlc_threadvar_get( __FILE__, __LINE__, P_TLS )
static inline void* __vlc_threadvar_get( char* psz_file, int line,
vlc_threadvar_t * p_tls )
{ {
void* p_ret; void* p_ret;
...@@ -641,3 +636,5 @@ static inline void* __vlc_threadvar_get( char* psz_file, int line, ...@@ -641,3 +636,5 @@ static inline void* __vlc_threadvar_get( char* psz_file, int line,
*****************************************************************************/ *****************************************************************************/
#define vlc_thread_join( P_THIS ) \ #define vlc_thread_join( P_THIS ) \
__vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ ) __vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )
#endif
...@@ -101,6 +101,7 @@ static access_t *access2_InternalNew( vlc_object_t *p_obj, const char *psz_acces ...@@ -101,6 +101,7 @@ static access_t *access2_InternalNew( vlc_object_t *p_obj, const char *psz_acces
if( p_access->p_module == NULL ) if( p_access->p_module == NULL )
{ {
msg_StackAdd( "could not create access" );
vlc_object_detach( p_access ); vlc_object_detach( p_access );
free( p_access->psz_access ); free( p_access->psz_access );
free( p_access->psz_path ); free( p_access->psz_path );
......
...@@ -2073,7 +2073,8 @@ static int InputSourceInit( input_thread_t *p_input, ...@@ -2073,7 +2073,8 @@ static int InputSourceInit( input_thread_t *p_input,
if( in->p_access == NULL ) if( in->p_access == NULL )
{ {
msg_Err( p_input, "no suitable access module for `%s'", psz_mrl ); msg_Err( p_input, "open of `%s' failed: %s", psz_mrl,
msg_StackMsg() );
intf_UserFatal( VLC_OBJECT( p_input), VLC_FALSE, intf_UserFatal( VLC_OBJECT( p_input), VLC_FALSE,
_("Your input can't be opened"), _("Your input can't be opened"),
_("VLC is unable to open the MRL '%s'." _("VLC is unable to open the MRL '%s'."
......
...@@ -583,3 +583,64 @@ static void PrintMsg ( vlc_object_t * p_this, msg_item_t * p_item ) ...@@ -583,3 +583,64 @@ static void PrintMsg ( vlc_object_t * p_this, msg_item_t * p_item )
# endif # endif
#endif #endif
} }
static msg_context_t* GetContext(void)
{
msg_context_t *p_ctx = vlc_threadvar_get( &msg_context_global_key );
if( p_ctx == NULL )
{
MALLOC_NULL( p_ctx, msg_context_t );
p_ctx->psz_message = NULL;
vlc_threadvar_set( &msg_context_global_key, p_ctx );
}
return p_ctx;
}
void msg_StackSet( int i_code, const char *psz_message, ... )
{
va_list ap;
msg_context_t *p_ctx = GetContext();
assert( p_ctx );
va_start( ap, psz_message );
if( p_ctx->psz_message != NULL )
{
free( p_ctx->psz_message );
}
vasprintf( &p_ctx->psz_message, psz_message, ap );
va_end( ap );
p_ctx->i_code = i_code;
}
void msg_StackAdd( const char *psz_message, ... )
{
char *psz_tmp;
va_list ap;
msg_context_t *p_ctx = GetContext();
assert( p_ctx );
va_start( ap, psz_message );
vasprintf( &psz_tmp, psz_message, ap );
va_end( ap );
if( !p_ctx->psz_message )
p_ctx->psz_message = psz_tmp;
else
{
char *psz_old = malloc( strlen( p_ctx->psz_message ) + 1 );
memcpy( psz_old, p_ctx->psz_message, strlen( p_ctx->psz_message ) + 1 );
p_ctx->psz_message = realloc( p_ctx->psz_message,
strlen( p_ctx->psz_message ) +
/* ':', ' ', '0' */
strlen( psz_tmp ) + 3 );
sprintf( p_ctx->psz_message, "%s: %s", psz_tmp, psz_old );
free( psz_tmp ); free( psz_old );
}
}
const char* msg_StackMsg( void )
{
msg_context_t *p_ctx = GetContext();
assert( p_ctx );
return p_ctx->psz_message;
}
...@@ -699,6 +699,9 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, ...@@ -699,6 +699,9 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability,
{ {
msg_Err( p_this, "no %s module matched \"%s\"", msg_Err( p_this, "no %s module matched \"%s\"",
psz_capability, (psz_name && *psz_name) ? psz_name : "any" ); psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
msg_StackSet( VLC_EGENERIC, "no %s module matched \"%s\"",
psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
} }
} }
else if( psz_name != NULL && *psz_name ) else if( psz_name != NULL && *psz_name )
...@@ -706,6 +709,8 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability, ...@@ -706,6 +709,8 @@ module_t * __module_Need( vlc_object_t *p_this, const char *psz_capability,
msg_Warn( p_this, "no %s module matching \"%s\" could be loaded", msg_Warn( p_this, "no %s module matching \"%s\" could be loaded",
psz_capability, (psz_name && *psz_name) ? psz_name : "any" ); psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
} }
else
msg_StackSet( VLC_EGENERIC, "no suitable %s module", psz_capability );
if( psz_shortcuts ) if( psz_shortcuts )
{ {
......
...@@ -49,6 +49,8 @@ static vlc_object_t *p_root; ...@@ -49,6 +49,8 @@ static vlc_object_t *p_root;
#elif defined( HAVE_CTHREADS_H ) #elif defined( HAVE_CTHREADS_H )
#endif #endif
vlc_threadvar_t msg_context_global_key;
/***************************************************************************** /*****************************************************************************
* vlc_threads_init: initialize threads system * vlc_threads_init: initialize threads system
***************************************************************************** *****************************************************************************
...@@ -130,6 +132,8 @@ int __vlc_threads_init( vlc_object_t *p_this ) ...@@ -130,6 +132,8 @@ int __vlc_threads_init( vlc_object_t *p_this )
i_initializations++; i_initializations++;
i_status = VLC_THREADS_READY; i_status = VLC_THREADS_READY;
} }
vlc_threadvar_create( p_root, &msg_context_global_key );
} }
else else
{ {
...@@ -505,30 +509,25 @@ int __vlc_cond_destroy( const char * psz_file, int i_line, vlc_cond_t *p_condvar ...@@ -505,30 +509,25 @@ int __vlc_cond_destroy( const char * psz_file, int i_line, vlc_cond_t *p_condvar
*****************************************************************************/ *****************************************************************************/
int __vlc_threadvar_create( vlc_object_t *p_this, vlc_threadvar_t *p_tls ) int __vlc_threadvar_create( vlc_object_t *p_this, vlc_threadvar_t *p_tls )
{ {
int i_ret;
#if defined( PTH_INIT_IN_PTH_H ) #if defined( PTH_INIT_IN_PTH_H )
return pth_key_create( &p_tls->handle, NULL ); i_ret = pth_key_create( &p_tls->handle, NULL );
#elif defined( HAVE_KERNEL_SCHEDULER_H ) #elif defined( HAVE_KERNEL_SCHEDULER_H )
msg_Err( p_this, "TLS not implemented" ); msg_Err( p_this, "TLS not implemented" );
return VLC_EGENERIC; i_ret VLC_EGENERIC;
#elif defined( ST_INIT_IN_ST_H ) #elif defined( ST_INIT_IN_ST_H )
return st_key_create( &p_tls->handle, NULL ); i_ret = st_key_create( &p_tls->handle, NULL );
#elif defined( UNDER_CE ) || defined( WIN32 ) #elif defined( UNDER_CE ) || defined( WIN32 )
#elif defined( WIN32 ) #elif defined( WIN32 )
p_tls->handle = TlsAlloc(); p_tls->handle = TlsAlloc();
if( p_tls->handle == 0xFFFFFFFF ) i_ret = !( p_tls->handle == 0xFFFFFFFF );
{
return VLC_EGENERIC;
}
msg_Err( p_this, "TLS not implemented" );
return VLC_EGENERIC;
#elif defined( PTHREAD_COND_T_IN_PTHREAD_H ) #elif defined( PTHREAD_COND_T_IN_PTHREAD_H )
return pthread_key_create( &p_tls->handle, NULL ); i_ret = pthread_key_create( &p_tls->handle, NULL );
#elif defined( HAVE_CTHREADS_H ) #elif defined( HAVE_CTHREADS_H )
return cthread_keycreate( &p_tls-handle ); i_ret = cthread_keycreate( &p_tls-handle );
#endif #endif
return i_ret;
} }
/***************************************************************************** /*****************************************************************************
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment