Update autoloader to fix concurrency issues when changing loader path in autoloaded function

darcs-hash:20061028164122-ac50b-25f978df9afeb370a06ef7576ef03183034bc057.gz
This commit is contained in:
axel 2006-10-29 02:41:22 +10:00
parent f16bb285be
commit c5eaefc8b5
3 changed files with 85 additions and 37 deletions

View file

@ -353,6 +353,9 @@ const wchar_t *function_get_definition_file( const wchar_t *argv )
CHECK( argv, 0 );
if( is_autoload )
return 0;
load( argv );
data = (function_data_t *)hash_get( &function, argv );
if( data == 0 )
@ -368,6 +371,9 @@ int function_get_definition_offset( const wchar_t *argv )
CHECK( argv, -1 );
if( is_autoload )
return -1;
load( argv );
data = (function_data_t *)hash_get( &function, argv );
if( data == 0 )

View file

@ -2,6 +2,10 @@
Various mostly unrelated utility functions related to parsing,
loading and evaluating fish code.
This library can be seen as a 'toolbox' for functions that are
used in many places in fish and that are somehow related to
parsing the code.
*/
#include "config.h"
@ -491,10 +495,19 @@ static void clear_hash_value( void *key, void *data, void *aux )
if( aux )
{
wchar_t *name = (wchar_t *)key;
time_t *time = (time_t *)data;
void (*handler)(const wchar_t *)= (void (*)(const wchar_t *))aux;
if( handler )
/*
If time[0] is 0, that means the file really doesn't exist,
it's simply been checked before. We should not unload it.
*/
if( time[0] && handler )
{
// debug( 0, L"Unloading function %ls", name );
handler( name );
}
}
free( (void *)data );
}
@ -540,13 +553,7 @@ static void parse_util_destroy()
void parse_util_load_reset( const wchar_t *path_var_name,
void (*on_load)(const wchar_t *cmd) )
{
wchar_t *path_var;
CHECK( path_var_name, );
path_var = env_get( path_var_name );
if( !path_var )
return;
if( all_loaded )
{
@ -654,7 +661,6 @@ static void parse_util_autounload( const wchar_t *path_var_name,
}
}
static int parse_util_load_internal( const wchar_t *cmd,
void (*on_load)(const wchar_t *cmd),
int reload,
@ -679,10 +685,10 @@ int parse_util_load( const wchar_t *cmd,
CHECK( path_var_name, 0 );
CHECK( cmd, 0 );
parse_util_autounload( path_var_name, cmd, on_load );
// debug( 0, L"Autoload %ls in %ls", cmd, path_var_name );
parse_util_autounload( path_var_name, cmd, on_load );
path_var = env_get( path_var_name );
/*
@ -712,6 +718,18 @@ int parse_util_load( const wchar_t *cmd,
if( loaded )
{
/*
Check if the lookup path has changed. If so, drop all loaded
files and start from scratch.
*/
if( wcscmp( path_var, loaded->old_path ) != 0 )
{
debug( 0, L"path change, new path is %ls", path_var );
parse_util_load_reset( path_var_name, on_load);
reload = parse_util_load( cmd, path_var_name, on_load, reload );
return reload;
}
/**
Warn and fail on infinite recursion
*/
@ -724,17 +742,7 @@ int parse_util_load( const wchar_t *cmd,
return 1;
}
/*
Check if the lookup path has changed. If so, drop all loaded
files and start from scratch.
*/
if( wcscmp( path_var, loaded->old_path ) != 0 )
{
parse_util_load_reset( path_var_name, on_load);
reload = parse_util_load( cmd, path_var_name, on_load, reload );
// debug( 0, L"Reload" );
return reload;
}
}
else
{
@ -742,6 +750,7 @@ int parse_util_load( const wchar_t *cmd,
We have never tried to autoload using this path name before,
set up initial data
*/
// debug( 0, L"Create brand new autoload_t for %ls->%ls", path_var_name, path_var );
loaded = malloc( sizeof( autoload_t ) );
if( !loaded )
{
@ -819,7 +828,6 @@ static int parse_util_load_internal( const wchar_t *cmd,
{
if(time(0)-tm[1]<=1)
{
// debug( 0, L"Cached" );
return 0;
}
}
@ -829,8 +837,6 @@ static int parse_util_load_internal( const wchar_t *cmd,
*/
if( !reload && tm )
{
// debug( 0, L"Weak check" );
return 0;
}
@ -871,10 +877,10 @@ static int parse_util_load_internal( const wchar_t *cmd,
intern( cmd ),
tm );
if( on_load )
on_load(cmd );
/*
Source the completion file for the specified completion
*/
@ -888,6 +894,15 @@ static int parse_util_load_internal( const wchar_t *cmd,
free(src_cmd);
reloaded = 1;
}
else if( tm )
{
/*
If we are rechecking an autoload file, and it hasn't
changed, update the 'last check' timestamp.
*/
tm[1] = time(0);
}
break;
}
}
@ -908,8 +923,6 @@ static int parse_util_load_internal( const wchar_t *cmd,
hash_put( &loaded->load_time, intern( cmd ), tm );
}
// debug( 0, L"Regular return" );
return reloaded;
}

View file

@ -470,6 +470,17 @@ void parser_push_block( int type )
void parser_pop_block()
{
block_t *old = current_block;
if( !current_block )
{
debug( 1,
L"function %s called on empty block stack. "
L"This is a bug. "
L"If you can reproduce it, please send a bug report to %s.",
__func__,
PACKAGE_BUGREPORT ); \
return;
}
current_block = current_block->outer;
halloc_free( old );
}
@ -495,7 +506,6 @@ const wchar_t *parser_get_block_desc( int block )
*/
static int parser_skip_arguments( const wchar_t *cmd )
{
return contains_str( cmd,
L"else",
L"begin",
@ -569,6 +579,8 @@ static const wchar_t *parser_find_end( const wchar_t * buff )
int error=0;
int mark=0;
CHECK( buff, 0 );
for( tok_init( &tok, buff, 0 );
tok_has_next( &tok ) && !error;
tok_next( &tok ) )
@ -652,6 +664,7 @@ void parser_forbid_function( wchar_t *function )
if( function )
debug( 2, L"Forbid %ls\n", function );
*/
CHECK( function, );
al_push( forbidden_function, function?wcsdup(function):0 );
}
@ -668,6 +681,8 @@ void error( int ec, int p, const wchar_t *str, ... )
{
va_list va;
CHECK( str, );
if( !err_buff )
err_buff = sb_halloc( global_context );
sb_clear( err_buff );
@ -820,6 +835,9 @@ void parser_destroy()
*/
static void print_errors( string_buffer_t *target, const wchar_t *prefix )
{
CHECK( target, );
CHECK( prefix, );
if( error_code && err_buff )
{
int tmp;
@ -1042,9 +1060,10 @@ void parser_stack_trace( block_t *b, string_buffer_t *buff)
}
/**
Returns true if we are currently evaluating a function. This is
tested by moving down the block-scope-stack, checking every block
if it is of type FUNCTION_CALL.
Returns the name of the currently evaluated function if we are
currently evaluating a function, null otherwise. This is tested by
moving down the block-scope-stack, checking every block if it is of
type FUNCTION_CALL.
*/
static const wchar_t *is_function()
{
@ -1121,6 +1140,9 @@ static int printed_width( const wchar_t *str, int len )
{
int res=0;
int i;
CHECK( str, 0 );
for( i=0; str[i] && i<len; i++ )
{
if( str[i] == L'\t' )
@ -1279,7 +1301,11 @@ const wchar_t *parser_get_buffer()
int parser_is_help( wchar_t *s, int min_match )
{
int len = wcslen(s);
int len;
CHECK( s, 0 );
len = wcslen(s);
min_match = maxi( min_match, 3 );
@ -1901,18 +1927,21 @@ static int parse_job( process_t *p,
if( use_function && !current_block->skip )
{
int nxt_forbidden;
int nxt_forbidden=0;
wchar_t *forbid;
if( current_block->type == FUNCTION_CALL )
{
forbid = (wchar_t *)(al_get_count( forbidden_function)?al_peek( forbidden_function ):0);
nxt_forbidden = forbid && (wcscmp( forbid, nxt) == 0 );
}
/*
Make feeble attempt to avoid infinite recursion. Will at
least catch some accidental infinite recursion calls.
*/
if( function_exists( nxt ) && !nxt_forbidden)
if( !nxt_forbidden && function_exists( nxt ) )
{
/*
Check if we have reached the maximum recursion depth