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.
#include "main.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__ )
# undef PACKAGE
# define PACKAGE
* @{
*/
+/** 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
{
#error You are not libvlc or one of its plugins. You cannot include this file
#endif
+#ifndef _VLC_THREADS_H_
+#define _VLC_THREADS_H_
+
#include <stdio.h>
#if defined(DEBUG) && defined(HAVE_SYS_TIME_H)
#endif
+#endif
#error You are not libvlc or one of its plugins. You cannot include this file
#endif
+#ifndef _VLC_THREADFUNCS_H_
+#define _VLC_THREADFUNCS_H_
+
/*****************************************************************************
* Function definitions
*****************************************************************************/
/*****************************************************************************
* vlc_threadvar_set: create: set the value of a thread-local variable
*****************************************************************************/
-#define vlc_threadvar_set( P_TLS , P_VAL ) \
- __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 )
+static inline int vlc_threadvar_set( vlc_threadvar_t * p_tls, void *p_value )
{
int i_ret;
/*****************************************************************************
* vlc_threadvar_get: create: get the value of a thread-local variable
*****************************************************************************/
-#define vlc_threadvar_get( 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 )
+static inline void* vlc_threadvar_get( vlc_threadvar_t * p_tls )
{
void* p_ret;
*****************************************************************************/
#define vlc_thread_join( P_THIS ) \
__vlc_thread_join( VLC_OBJECT(P_THIS), __FILE__, __LINE__ )
+
+#endif
if( p_access->p_module == NULL )
{
+ msg_StackAdd( "could not create access" );
vlc_object_detach( p_access );
free( p_access->psz_access );
free( p_access->psz_path );
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,
_("Your input can't be opened"),
_("VLC is unable to open the MRL '%s'."
# 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;
+}
{
msg_Err( p_this, "no %s module matched \"%s\"",
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 )
msg_Warn( p_this, "no %s module matching \"%s\" could be loaded",
psz_capability, (psz_name && *psz_name) ? psz_name : "any" );
}
+ else
+ msg_StackSet( VLC_EGENERIC, "no suitable %s module", psz_capability );
if( psz_shortcuts )
{
#elif defined( HAVE_CTHREADS_H )
#endif
+vlc_threadvar_t msg_context_global_key;
+
/*****************************************************************************
* vlc_threads_init: initialize threads system
*****************************************************************************
i_initializations++;
i_status = VLC_THREADS_READY;
}
+
+ vlc_threadvar_create( p_root, &msg_context_global_key );
}
else
{
*****************************************************************************/
int __vlc_threadvar_create( vlc_object_t *p_this, vlc_threadvar_t *p_tls )
{
+ int i_ret;
#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 )
msg_Err( p_this, "TLS not implemented" );
- return VLC_EGENERIC;
+ i_ret VLC_EGENERIC;
#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( WIN32 )
p_tls->handle = TlsAlloc();
- if( p_tls->handle == 0xFFFFFFFF )
- {
- return VLC_EGENERIC;
- }
-
- msg_Err( p_this, "TLS not implemented" );
- return VLC_EGENERIC;
+ i_ret = !( p_tls->handle == 0xFFFFFFFF );
#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 )
- return cthread_keycreate( &p_tls-handle );
+ i_ret = cthread_keycreate( &p_tls-handle );
#endif
+ return i_ret;
}
/*****************************************************************************