diff --git a/autoload.cpp b/autoload.cpp index a886df522..0222bacf4 100644 --- a/autoload.cpp +++ b/autoload.cpp @@ -172,6 +172,8 @@ lru_cache_impl_t::lru_cache_impl_t() : node_count(0), mouth(L"") { mouth.prev = mouth.next = &mouth; } +void lru_cache_impl_t::node_was_evicted(lru_node_t *node) { } + void lru_cache_impl_t::evict_node(lru_node_t *condemned_node) { /* We should never evict the mouth */ assert(condemned_node != NULL && condemned_node != &mouth); @@ -184,8 +186,8 @@ void lru_cache_impl_t::evict_node(lru_node_t *condemned_node) { node_set.erase(condemned_node); node_count--; - /* Tell it */ - condemned_node->evicted(); + /* Tell ourselves */ + this->node_was_evicted(condemned_node); } void lru_cache_impl_t::evict_last_node(void) { diff --git a/autoload.h b/autoload.h index db8e89bfb..96ea628d2 100644 --- a/autoload.h +++ b/autoload.h @@ -84,13 +84,10 @@ class lru_node_t { /** Constructor */ lru_node_t(const wcstring &keyVar) : prev(NULL), next(NULL), key(keyVar) { } bool operator<(const lru_node_t &other) const { return key < other.key; } - - /** Callback when the node is evicted from an LRU cache */ - virtual void evicted(void) { } }; class lru_cache_impl_t { - private: +private: void promote_node(lru_node_t *); void evict_node(lru_node_t *node); void evict_last_node(void); @@ -105,7 +102,11 @@ class lru_cache_impl_t { /** Head of the linked list */ lru_node_t mouth; - public: +protected: + /** Overridable callback for when a node is evicted */ + virtual void node_was_evicted(lru_node_t *node); + +public: /** Constructor */ lru_cache_impl_t(); @@ -128,6 +129,9 @@ class lru_cache_t : public lru_cache_impl_t { public: node_type_t *get_node(const wcstring &key) { return static_cast(lru_cache_impl_t::get_node(key)); } bool add_node(node_type_t *node) { return lru_cache_impl_t::add_node(node); } +protected: + virtual void node_was_evicted(lru_node_t *node) { this->node_was_evicted(static_cast(node)); } + virtual void node_was_evicted(node_type_t *node) { } }; diff --git a/complete.cpp b/complete.cpp index b4031daf4..9101e8ac7 100644 --- a/complete.cpp +++ b/complete.cpp @@ -181,7 +181,27 @@ static complete_entry_t *first_entry=0; */ static hash_table_t *condition_cache=0; -static autoload_t completion_autoloader(L"fish_complete_path", internal_completion_scripts, sizeof internal_completion_scripts / sizeof *internal_completion_scripts ); +/* Autoloader for completions */ +class completion_autoload_t : public autoload_t { +public: + completion_autoload_t(); + virtual void command_removed(const wcstring &cmd); +}; + +static completion_autoload_t completion_autoloader; + +/** Constructor */ +completion_autoload_t::completion_autoload_t() : autoload_t(L"fish_complete_path", + internal_completion_scripts, + sizeof internal_completion_scripts / sizeof *internal_completion_scripts) +{ +} + +/** Callback when an autoloaded completion is removed */ +void completion_autoload_t::command_removed(const wcstring &cmd) { + complete_remove( cmd.c_str(), COMMAND, 0, 0 ); +} + static void complete_free_entry( complete_entry_t *c ); @@ -229,7 +249,7 @@ static void complete_destroy() } first_entry = 0; - completion_autoloader.reset( 0 ); + completion_autoloader.reset(); } @@ -1346,23 +1366,10 @@ static int short_ok( const wchar_t *arg, return 1; } -/** - This is an event handler triggered when the definition of a - specified function is changed. It automatcally removes the - specified function. - - This is to make sure that the function disappears if the file is - removed or if it contains a syntax error. -*/ -static void complete_load_handler( const wchar_t *cmd ) -{ - complete_remove( cmd, COMMAND, 0, 0 ); -} - void complete_load( const wchar_t *name, int reload ) { CHECK( name, ); - completion_autoloader.load( name, &complete_load_handler, reload ); + completion_autoloader.load( name, reload ); } /** diff --git a/function.cpp b/function.cpp index 6aa94a621..474640fbf 100644 --- a/function.cpp +++ b/function.cpp @@ -40,9 +40,6 @@ #include "halloc_util.h" #include "builtin_scripts.h" -/* Autoloader for functions */ -static autoload_t function_autoloader(L"fish_function_path", internal_function_scripts, sizeof internal_function_scripts / sizeof *internal_function_scripts); - /** Table containing all functions */ @@ -52,6 +49,30 @@ static function_map_t loaded_functions; /* Lock for functions */ static pthread_mutex_t functions_lock; +/* Autoloader for functions */ +class function_autoload_t : public autoload_t { +public: + function_autoload_t(); + virtual void command_removed(const wcstring &cmd); +}; + +static function_autoload_t function_autoloader; + +/** Constructor */ +function_autoload_t::function_autoload_t() : autoload_t(L"fish_function_path", + internal_function_scripts, + sizeof internal_function_scripts / sizeof *internal_function_scripts) +{ +} + +/** Removes a function from our internal table, returning true if it was found and false if not */ +static bool function_remove_ignore_autoload(const wcstring &name); + +/** Callback when an autoloaded function is removed */ +void function_autoload_t::command_removed(const wcstring &cmd) { + function_remove(cmd); +} + /* Helper macro for vomiting */ #define VOMIT_ON_FAILURE(a) do { if (0 != (a)) { int err = errno; fprintf(stderr, "%s failed on line %d in file %s: %d (%s)\n", #a, __LINE__, __FILE__, err, strerror(err)); abort(); }} while (0) @@ -78,7 +99,7 @@ static int load( const wchar_t *name ) } is_autoload = 1; - res = function_autoloader.load( name, &function_remove, 1 ); + res = function_autoloader.load( name, true ); is_autoload = was_autoload; return res; } @@ -199,32 +220,25 @@ int function_exists_no_autoload( const wchar_t *cmd ) return function_exists_internal( cmd, false ); } -void function_remove( const wchar_t *name ) +static bool function_remove_ignore_autoload(const wcstring &name) { - event_t ev; - - CHECK( name, ); - scoped_lock lock(functions_lock); bool erased = (loaded_functions.erase(name) > 0); - if( !erased ) { - return; + if (erased) { + event_t ev; + ev.type=EVENT_ANY; + ev.function_name=name.c_str(); + event_remove( &ev ); } + return erased; - ev.type=EVENT_ANY; - ev.function_name=name; - event_remove( &ev ); +} - /* - Notify the autoloader that the specified function is erased, but - only if this call to fish_remove is not made by the autoloader - itself. - */ - if( !is_autoload ) - { - function_autoloader.unload( name, 0 ); - } +void function_remove( const wcstring &name ) +{ + if (function_remove_ignore_autoload(name)) + function_autoloader.unload( name ); } shared_ptr function_get(const wcstring &name) diff --git a/function.h b/function.h index 2db437949..18f4d65e2 100644 --- a/function.h +++ b/function.h @@ -106,7 +106,7 @@ void function_add( function_data_t *data, const parser_t &parser ); /** Remove the function with the specified name. */ -void function_remove( const wchar_t *name ); +void function_remove( const wcstring &name ); /** Gets a function by name. diff --git a/parse_util.cpp b/parse_util.cpp index c30660d84..3ca8d610e 100644 --- a/parse_util.cpp +++ b/parse_util.cpp @@ -601,13 +601,6 @@ void parse_util_token_extent( const wchar_t *buff, } -autoload_function_t::~autoload_function_t() { } - -void autoload_function_t::evicted(void) { - delete this; -} - - autoload_t::autoload_t(const wcstring &env_var_name_var, const builtin_script_t * const scripts, size_t script_count) : env_var_name(env_var_name_var), builtin_scripts(scripts), @@ -615,21 +608,24 @@ autoload_t::autoload_t(const wcstring &env_var_name_var, const builtin_script_t { } -void autoload_t::reset( void (*on_load)(const wchar_t *cmd) ) -{ - function_cache.evict_all_nodes(); - /* TODO: Must call on_load on all non-placeholders */ +void autoload_t::node_was_evicted(autoload_function_t *node) { + // Tell ourselves that the command was removed, unless it was a placeholder + if (! node->is_placeholder) + this->command_removed(node->key); + delete node; } -int autoload_t::unload( const wchar_t *cmd, void (*on_load)(const wchar_t *cmd) ) +void autoload_t::reset( ) { - CHECK( cmd, 0 ); - return function_cache.evict_node(cmd); + this->evict_all_nodes(); } -int autoload_t::load( const wcstring &cmd, - void (*on_load)(const wchar_t *cmd), - int reload ) +int autoload_t::unload( const wcstring &cmd ) +{ + return this->evict_node(cmd); +} + +int autoload_t::load( const wcstring &cmd, bool reload ) { int res; int c, c2; @@ -653,7 +649,7 @@ int autoload_t::load( const wcstring &cmd, if( path_var != this->path ) { this->path = path_var; - reset( on_load); + this->reset(); } /** @@ -680,7 +676,7 @@ int autoload_t::load( const wcstring &cmd, /* Do the actual work in the internal helper function */ - res = this->load_internal( cmd, on_load, reload, path_list ); + res = this->load_internal( cmd, reload, path_list ); int erased = is_loading_set.erase(cmd); assert(erased); @@ -708,7 +704,6 @@ static bool script_name_precedes_script_name(const builtin_script_t &script1, co */ int autoload_t::load_internal( const wcstring &cmd, - void (*on_load)(const wchar_t *cmd), int reload, const wcstring_list_t &path_list ) { @@ -772,9 +767,9 @@ int autoload_t::load_internal( const wcstring &cmd, func = new autoload_function_t(cmd); func->access = access; - if( on_load ) - on_load(cmd.c_str()); - + // Remove this command because we are going to reload it + command_removed(cmd); + reloaded = 1; } else if( func ) diff --git a/parse_util.h b/parse_util.h index 84ec68f79..5e92d39c8 100644 --- a/parse_util.h +++ b/parse_util.h @@ -15,9 +15,6 @@ struct autoload_function_t : public lru_node_t { autoload_function_t(const wcstring &key) : lru_node_t(key), is_placeholder(false) { bzero(&access, sizeof access); } - virtual ~autoload_function_t(); - virtual void evicted(void); - file_access_attempt_t access; /** The last access attempt */ bool is_placeholder; /** Whether we are a placeholder that stands in for "no such function" */ }; @@ -28,10 +25,8 @@ struct builtin_script_t; /** A class that represents a path from which we can autoload, and the autoloaded contents. */ -class autoload_t { +class autoload_t : private lru_cache_t { private: - /** Access tracker */ - lru_cache_t function_cache; /** The environment variable name */ const wcstring env_var_name; @@ -80,7 +75,14 @@ class autoload_t { return autoload_functions.size(); } - int load_internal( const wcstring &cmd, void (*on_load)(const wchar_t *cmd), int reload, const wcstring_list_t &path_list ); + int load_internal( const wcstring &cmd, int reload, const wcstring_list_t &path_list ); + + virtual void node_was_evicted(autoload_function_t *node); + + + protected: + /** Overridable callback for when a command is removed */ + virtual void command_removed(const wcstring &cmd) { } public: @@ -98,17 +100,13 @@ class autoload_t { \param on_unload a callback function to run if a suitable file is found, which has not already been run. unload will also be called for old files which are unloaded. \param reload wheter to recheck file timestamps on already loaded files */ - int load( const wcstring &cmd, - void (*on_unload)(const wchar_t *cmd), - int reload ); + int load( const wcstring &cmd, bool reload ); /** Reset the loader for the specified path variable. This will cause all information on loaded files in the specified directory to be reset. - - \param on_unload a callback function which will be called before (re)loading a file, may be used to unload the previous file. */ - void reset( void (*on_unload)(const wchar_t *cmd) ); + void reset(); /** Tell the autoloader that the specified file, in the specified path, @@ -118,8 +116,7 @@ class autoload_t { \param on_unload a callback function which will be called before (re)loading a file, may be used to unload the previous file. \return non-zero if the file was removed, zero if the file had not yet been loaded */ - int unload( const wchar_t *cmd, - void (*on_unload)(const wchar_t *cmd) ); + int unload( const wcstring &cmd ); };