mirror of
https://github.com/fish-shell/fish-shell
synced 2024-12-27 05:13:10 +00:00
LRU cache work
This commit is contained in:
parent
e94e1cc72f
commit
8e56763c98
4 changed files with 214 additions and 143 deletions
134
autoload.cpp
134
autoload.cpp
|
@ -10,6 +10,26 @@ The classes responsible for autoloading functions and completions.
|
||||||
|
|
||||||
const size_t kLRULimit = 256;
|
const size_t kLRULimit = 256;
|
||||||
|
|
||||||
|
file_access_attempt_t access_file(const wcstring &path, int mode) {
|
||||||
|
file_access_attempt_t result = {0};
|
||||||
|
struct stat statbuf;
|
||||||
|
if (wstat(path.c_str(), &statbuf)) {
|
||||||
|
result.error = errno;
|
||||||
|
} else {
|
||||||
|
result.mod_time = statbuf.st_mtime;
|
||||||
|
if (waccess(path.c_str(), mode)) {
|
||||||
|
result.error = errno;
|
||||||
|
} else {
|
||||||
|
result.accessible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that we record the last checked time after the call, on the assumption that in a slow filesystem, the lag comes before the kernel check, not after.
|
||||||
|
result.stale = false;
|
||||||
|
result.last_checked = time(NULL);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/** A node in our LRU map */
|
/** A node in our LRU map */
|
||||||
class file_access_node_t {
|
class file_access_node_t {
|
||||||
public:
|
public:
|
||||||
|
@ -77,23 +97,7 @@ file_access_node_t *access_tracker_t::while_locked_find_node(const wcstring &pat
|
||||||
}
|
}
|
||||||
|
|
||||||
file_access_attempt_t access_tracker_t::attempt_access(const wcstring& path) const {
|
file_access_attempt_t access_tracker_t::attempt_access(const wcstring& path) const {
|
||||||
file_access_attempt_t result = {0};
|
return ::access_file(path, this->mode);
|
||||||
struct stat statbuf;
|
|
||||||
if (wstat(path.c_str(), &statbuf)) {
|
|
||||||
result.error = errno;
|
|
||||||
} else {
|
|
||||||
result.mod_time = statbuf.st_mtime;
|
|
||||||
if (waccess(path.c_str(), this->mode)) {
|
|
||||||
result.error = errno;
|
|
||||||
} else {
|
|
||||||
result.accessible = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note that we record the last checked time after the call, on the assumption that in a slow filesystem, the lag comes before the kernel check, not after.
|
|
||||||
result.stale = false;
|
|
||||||
result.last_checked = time(NULL);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool access_tracker_t::access_file_only_cached(const wcstring &path, file_access_attempt_t &attempt) {
|
bool access_tracker_t::access_file_only_cached(const wcstring &path, file_access_attempt_t &attempt) {
|
||||||
|
@ -162,3 +166,99 @@ file_access_attempt_t access_tracker_t::access_file(const wcstring &path) {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lru_cache_impl_t::lru_cache_impl_t() : node_count(0), mouth(L"") {
|
||||||
|
/* Hook up the mouth to itself: a one node circularly linked list */
|
||||||
|
mouth.prev = mouth.next = &mouth;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* Remove it from the linked list */
|
||||||
|
condemned_node->prev->next = condemned_node->next;
|
||||||
|
condemned_node->next->prev = condemned_node->prev;
|
||||||
|
|
||||||
|
/* Remove us from the set */
|
||||||
|
node_set.erase(condemned_node);
|
||||||
|
node_count--;
|
||||||
|
|
||||||
|
/* Tell it */
|
||||||
|
condemned_node->evicted();
|
||||||
|
}
|
||||||
|
|
||||||
|
void lru_cache_impl_t::evict_last_node(void) {
|
||||||
|
/* Simple */
|
||||||
|
evict_node(mouth.prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lru_cache_impl_t::evict_node(const wcstring &key) {
|
||||||
|
/* Construct a fake node as our key */
|
||||||
|
lru_node_t node_key(key);
|
||||||
|
|
||||||
|
/* Look for it in the set */
|
||||||
|
node_set_t::iterator iter = node_set.find(&node_key);
|
||||||
|
if (iter == node_set.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Evict the given node */
|
||||||
|
evict_node(*iter);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lru_cache_impl_t::promote_node(lru_node_t *node) {
|
||||||
|
/* We should never promote the mouth */
|
||||||
|
assert(node != &mouth);
|
||||||
|
|
||||||
|
/* First unhook us */
|
||||||
|
node->prev->next = node->next;
|
||||||
|
node->next->prev = node->prev;
|
||||||
|
|
||||||
|
/* Put us after the mouth */
|
||||||
|
node->next = mouth.next;
|
||||||
|
node->prev = &mouth;
|
||||||
|
mouth.next = node;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool lru_cache_impl_t::add_node(lru_node_t *node) {
|
||||||
|
assert(node != NULL && node != &mouth);
|
||||||
|
|
||||||
|
/* Try inserting; return false if it was already in the set */
|
||||||
|
if (! node_set.insert(node).second)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Update the count */
|
||||||
|
node_count++;
|
||||||
|
|
||||||
|
/* Add the node after the mouth */
|
||||||
|
node->next = mouth.next;
|
||||||
|
node->prev = &mouth;
|
||||||
|
mouth.next = node;
|
||||||
|
|
||||||
|
/* Success */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
lru_node_t *lru_cache_impl_t::get_node(const wcstring &key) {
|
||||||
|
lru_node_t *result = NULL;
|
||||||
|
|
||||||
|
/* Construct a fake node as our key */
|
||||||
|
lru_node_t node_key(key);
|
||||||
|
|
||||||
|
/* Look for it in the set */
|
||||||
|
node_set_t::iterator iter = node_set.find(&node_key);
|
||||||
|
|
||||||
|
/* If we found a node, promote and return it */
|
||||||
|
if (iter != node_set.end()) {
|
||||||
|
result = *iter;
|
||||||
|
promote_node(result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lru_cache_impl_t::evict_all_nodes() {
|
||||||
|
while (node_count > 0) {
|
||||||
|
evict_last_node();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
69
autoload.h
69
autoload.h
|
@ -3,8 +3,8 @@
|
||||||
The classes responsible for autoloading functions and completions.
|
The classes responsible for autoloading functions and completions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FISH_PARSE_UTIL_H
|
#ifndef FISH_AUTOLOAD_H
|
||||||
#define FISH_PARSE_UTIL_H
|
#define FISH_AUTOLOAD_H
|
||||||
|
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
@ -14,9 +14,8 @@
|
||||||
|
|
||||||
extern const time_t kFishDefaultStalenessInterval;
|
extern const time_t kFishDefaultStalenessInterval;
|
||||||
|
|
||||||
/** A class responsible for recording an attempt to access a file. */
|
/** A struct responsible for recording an attempt to access a file. */
|
||||||
class file_access_attempt_t {
|
struct file_access_attempt_t {
|
||||||
public:
|
|
||||||
time_t mod_time; /** The modification time of the file */
|
time_t mod_time; /** The modification time of the file */
|
||||||
time_t last_checked; /** When we last checked the file */
|
time_t last_checked; /** When we last checked the file */
|
||||||
bool accessible; /** Whether we believe we could access this file */
|
bool accessible; /** Whether we believe we could access this file */
|
||||||
|
@ -32,6 +31,7 @@ struct dereference_less_t {
|
||||||
bool operator()(ptr_t p1, ptr_t p2) const { return *p1 < *p2; }
|
bool operator()(ptr_t p1, ptr_t p2) const { return *p1 < *p2; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
file_access_attempt_t access_file(const wcstring &path, int mode);
|
||||||
|
|
||||||
/** A class responsible for tracking accesses to files, including auto-expiration. */
|
/** A class responsible for tracking accesses to files, including auto-expiration. */
|
||||||
class access_tracker_t {
|
class access_tracker_t {
|
||||||
|
@ -72,4 +72,63 @@ class access_tracker_t {
|
||||||
bool access_file_only_cached(const wcstring &path, file_access_attempt_t &attempt);
|
bool access_file_only_cached(const wcstring &path, file_access_attempt_t &attempt);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class lru_node_t {
|
||||||
|
friend class lru_cache_impl_t;
|
||||||
|
/** Our linked list pointer */
|
||||||
|
lru_node_t *prev, *next;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** The key used to look up in the cache */
|
||||||
|
const wcstring key;
|
||||||
|
|
||||||
|
/** 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:
|
||||||
|
void promote_node(lru_node_t *);
|
||||||
|
void evict_node(lru_node_t *node);
|
||||||
|
void evict_last_node(void);
|
||||||
|
|
||||||
|
/** Count of nodes */
|
||||||
|
unsigned int node_count;
|
||||||
|
|
||||||
|
/** The set of nodes */
|
||||||
|
typedef std::set<lru_node_t *, dereference_less_t> node_set_t;
|
||||||
|
node_set_t node_set;
|
||||||
|
|
||||||
|
/** Head of the linked list */
|
||||||
|
lru_node_t mouth;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructor */
|
||||||
|
lru_cache_impl_t();
|
||||||
|
|
||||||
|
/** Returns the node for a given key, or NULL */
|
||||||
|
lru_node_t *get_node(const wcstring &key);
|
||||||
|
|
||||||
|
/** Evicts the node for a given key, returning true if a node was evicted. */
|
||||||
|
bool evict_node(const wcstring &key);
|
||||||
|
|
||||||
|
/** Adds a node under the given key. Returns true if the node was added, false if the node was not because a node with that key is already in the set. */
|
||||||
|
bool add_node(lru_node_t *node);
|
||||||
|
|
||||||
|
/** Evicts all nodes */
|
||||||
|
void evict_all_nodes(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Template cover to avoid casting */
|
||||||
|
template<class node_type_t>
|
||||||
|
class lru_cache_t : public lru_cache_impl_t {
|
||||||
|
public:
|
||||||
|
node_type_t *get_node(const wcstring &key) { return static_cast<node_type_t>(lru_cache_impl_t::get_node(key)); }
|
||||||
|
bool add_node(node_type_t *node) { return lru_cache_impl_t::add_node(node); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
110
parse_util.cpp
110
parse_util.cpp
|
@ -54,43 +54,6 @@
|
||||||
#define AUTOLOAD_MIN_AGE 60
|
#define AUTOLOAD_MIN_AGE 60
|
||||||
|
|
||||||
|
|
||||||
/* Get the name of the function that was least recently loaded, if it was loaded before cutoff_access. Return NULL if no function qualifies. */
|
|
||||||
const wcstring *autoload_t::get_lru_function_name(const wcstring &skip, time_t cutoff_access) const
|
|
||||||
{
|
|
||||||
const wcstring *resultName = NULL;
|
|
||||||
const autoload_function_t *resultFunction = NULL;
|
|
||||||
autoload_functions_map_t::const_iterator iter;
|
|
||||||
for (iter = autoload_functions.begin(); iter != autoload_functions.end(); iter++)
|
|
||||||
{
|
|
||||||
/* Skip the skip */
|
|
||||||
if (iter->first == skip) continue;
|
|
||||||
|
|
||||||
/* Skip items that are still loading */
|
|
||||||
if (is_loading(iter->first)) continue;
|
|
||||||
|
|
||||||
/* Skip placeholder items */
|
|
||||||
if (iter->second.is_placeholder) continue;
|
|
||||||
|
|
||||||
/* Check cutoff_access */
|
|
||||||
if (iter->second.load_time > cutoff_access) continue;
|
|
||||||
|
|
||||||
/* Remember this if it was used earlier */
|
|
||||||
if (resultFunction == NULL || iter->second.load_time < resultFunction->load_time) {
|
|
||||||
resultName = &iter->first;
|
|
||||||
resultFunction = &iter->second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resultName;
|
|
||||||
}
|
|
||||||
|
|
||||||
void autoload_t::apply_handler_to_nonplaceholder_function_names(void (*handler)(const wchar_t *cmd)) const
|
|
||||||
{
|
|
||||||
autoload_functions_map_t::const_iterator iter;
|
|
||||||
for (iter = autoload_functions.begin(); iter != autoload_functions.end(); iter++)
|
|
||||||
handler(iter->first.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int parse_util_lineno( const wchar_t *str, int len )
|
int parse_util_lineno( const wchar_t *str, int len )
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -638,6 +601,13 @@ 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) :
|
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),
|
env_var_name(env_var_name_var),
|
||||||
builtin_scripts(scripts),
|
builtin_scripts(scripts),
|
||||||
|
@ -647,50 +617,14 @@ 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) )
|
void autoload_t::reset( void (*on_load)(const wchar_t *cmd) )
|
||||||
{
|
{
|
||||||
if (! autoload_functions.empty()) {
|
function_cache.evict_all_nodes();
|
||||||
if (on_load) {
|
/* TODO: Must call on_load on all non-placeholders */
|
||||||
/* Call the on_load handler on each real function name. */
|
|
||||||
this->apply_handler_to_nonplaceholder_function_names(on_load);
|
|
||||||
}
|
|
||||||
/* Empty the functino set */
|
|
||||||
this->remove_all_functions();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int autoload_t::unload( const wchar_t *cmd, void (*on_load)(const wchar_t *cmd) )
|
int autoload_t::unload( const wchar_t *cmd, void (*on_load)(const wchar_t *cmd) )
|
||||||
{
|
{
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
CHECK( cmd, 0 );
|
CHECK( cmd, 0 );
|
||||||
|
return function_cache.evict_node(cmd);
|
||||||
if (this->remove_function_with_name(cmd))
|
|
||||||
{
|
|
||||||
if (on_load)
|
|
||||||
on_load(cmd);
|
|
||||||
result = 1;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
Unload one autoloaded item that has expired, that where loaded in
|
|
||||||
the specified path.
|
|
||||||
|
|
||||||
\param skip unloading the the specified file
|
|
||||||
\param on_load the callback function to call for every unloaded file
|
|
||||||
|
|
||||||
*/
|
|
||||||
void autoload_t::autounload( const wchar_t *skip,
|
|
||||||
void (*on_load)(const wchar_t *cmd) )
|
|
||||||
{
|
|
||||||
if( this->function_count() >= AUTOLOAD_MAX )
|
|
||||||
{
|
|
||||||
time_t cutoff_access = time(0) - AUTOLOAD_MIN_AGE;
|
|
||||||
const wcstring *lru = this->get_lru_function_name(skip, cutoff_access);
|
|
||||||
if (lru)
|
|
||||||
unload( lru->c_str(), on_load );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int autoload_t::load( const wcstring &cmd,
|
int autoload_t::load( const wcstring &cmd,
|
||||||
|
@ -702,7 +636,6 @@ int autoload_t::load( const wcstring &cmd,
|
||||||
|
|
||||||
CHECK_BLOCK( 0 );
|
CHECK_BLOCK( 0 );
|
||||||
|
|
||||||
autounload( cmd.c_str(), on_load );
|
|
||||||
const env_var_t path_var = env_get_string( env_var_name.c_str() );
|
const env_var_t path_var = env_get_string( env_var_name.c_str() );
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -791,7 +724,7 @@ int autoload_t::load_internal( const wcstring &cmd,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Nothing to do if we just checked it */
|
/* Nothing to do if we just checked it */
|
||||||
if (func && time(NULL) - func->load_time <= 1)
|
if (func && time(NULL) - func->access.last_checked <= 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* The source of the script will end up here */
|
/* The source of the script will end up here */
|
||||||
|
@ -825,24 +758,19 @@ int autoload_t::load_internal( const wcstring &cmd,
|
||||||
*/
|
*/
|
||||||
for( i=0; i<path_list.size(); i++ )
|
for( i=0; i<path_list.size(); i++ )
|
||||||
{
|
{
|
||||||
struct stat buf;
|
|
||||||
wcstring next = path_list.at(i);
|
wcstring next = path_list.at(i);
|
||||||
wcstring path = next + L"/" + cmd + L".fish";
|
wcstring path = next + L"/" + cmd + L".fish";
|
||||||
|
|
||||||
if( (wstat( path.c_str(), &buf )== 0) &&
|
const file_access_attempt_t access = access_file(path, R_OK);
|
||||||
(waccess( path.c_str(), R_OK ) == 0) )
|
if (access.accessible) {
|
||||||
{
|
if (! func || access.mod_time != func->access.mod_time) {
|
||||||
if( !func || (func->modification_time != buf.st_mtime ) )
|
|
||||||
{
|
|
||||||
wcstring esc = escape_string(path, 1);
|
wcstring esc = escape_string(path, 1);
|
||||||
script_source = L". " + esc;
|
script_source = L". " + esc;
|
||||||
has_script_source = true;
|
has_script_source = true;
|
||||||
|
|
||||||
if( !func )
|
if( !func )
|
||||||
func = this->create_function_with_name(cmd);
|
func = new autoload_function_t(cmd);
|
||||||
|
func->access = access;
|
||||||
func->modification_time = buf.st_mtime;
|
|
||||||
func->load_time = time(NULL);
|
|
||||||
|
|
||||||
if( on_load )
|
if( on_load )
|
||||||
on_load(cmd.c_str());
|
on_load(cmd.c_str());
|
||||||
|
@ -855,7 +783,7 @@ int autoload_t::load_internal( const wcstring &cmd,
|
||||||
If we are rechecking an autoload file, and it hasn't
|
If we are rechecking an autoload file, and it hasn't
|
||||||
changed, update the 'last check' timestamp.
|
changed, update the 'last check' timestamp.
|
||||||
*/
|
*/
|
||||||
func->load_time = time(NULL);
|
func->access = access;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -869,8 +797,8 @@ int autoload_t::load_internal( const wcstring &cmd,
|
||||||
*/
|
*/
|
||||||
if( !func )
|
if( !func )
|
||||||
{
|
{
|
||||||
func = this->create_function_with_name(cmd);
|
func = new autoload_function_t(cmd);
|
||||||
func->load_time = time(NULL);
|
func->access.last_checked = time(NULL);
|
||||||
func->is_placeholder = true;
|
func->is_placeholder = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
38
parse_util.h
38
parse_util.h
|
@ -7,20 +7,22 @@
|
||||||
#ifndef FISH_PARSE_UTIL_H
|
#ifndef FISH_PARSE_UTIL_H
|
||||||
#define FISH_PARSE_UTIL_H
|
#define FISH_PARSE_UTIL_H
|
||||||
|
|
||||||
|
#include "autoload.h"
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
|
||||||
struct autoload_function_t
|
struct autoload_function_t : public lru_node_t
|
||||||
{
|
{
|
||||||
bool is_placeholder; //whether we are a placeholder that stands in for "no such function"
|
autoload_function_t(const wcstring &key) : lru_node_t(key), is_placeholder(false) { bzero(&access, sizeof access); }
|
||||||
time_t modification_time; // st_mtime
|
virtual ~autoload_function_t();
|
||||||
time_t load_time; // when function was loaded
|
virtual void evicted(void);
|
||||||
|
|
||||||
|
file_access_attempt_t access; /** The last access attempt */
|
||||||
autoload_function_t() : is_placeholder(false), modification_time(0), load_time(0) { }
|
bool is_placeholder; /** Whether we are a placeholder that stands in for "no such function" */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct builtin_script_t;
|
struct builtin_script_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,6 +30,9 @@ struct builtin_script_t;
|
||||||
*/
|
*/
|
||||||
class autoload_t {
|
class autoload_t {
|
||||||
private:
|
private:
|
||||||
|
/** Access tracker */
|
||||||
|
lru_cache_t<autoload_function_t> function_cache;
|
||||||
|
|
||||||
/** The environment variable name */
|
/** The environment variable name */
|
||||||
const wcstring env_var_name;
|
const wcstring env_var_name;
|
||||||
|
|
||||||
|
@ -54,10 +59,6 @@ private:
|
||||||
return is_loading_set.find(name) != is_loading_set.end();
|
return is_loading_set.find(name) != is_loading_set.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
autoload_function_t *create_function_with_name(const wcstring &name) {
|
|
||||||
return &autoload_functions[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool remove_function_with_name(const wcstring &name) {
|
bool remove_function_with_name(const wcstring &name) {
|
||||||
return autoload_functions.erase(name) > 0;
|
return autoload_functions.erase(name) > 0;
|
||||||
}
|
}
|
||||||
|
@ -79,25 +80,8 @@ private:
|
||||||
return autoload_functions.size();
|
return autoload_functions.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the name of the function that was least recently loaded, if it was loaded before cutoff_access. Return NULL if no function qualifies. */
|
|
||||||
const wcstring *get_lru_function_name(const wcstring &skip, time_t cutoff_access) const;
|
|
||||||
|
|
||||||
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, void (*on_load)(const wchar_t *cmd), int reload, const wcstring_list_t &path_list );
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
Unload all autoloaded items that have expired, that where loaded in
|
|
||||||
the specified path.
|
|
||||||
|
|
||||||
\param skip unloading the the specified file
|
|
||||||
\param on_load the callback function to call for every unloaded file
|
|
||||||
|
|
||||||
*/
|
|
||||||
void autounload( const wchar_t *skip,
|
|
||||||
void (*on_load)(const wchar_t *cmd) );
|
|
||||||
|
|
||||||
void apply_handler_to_nonplaceholder_function_names(void (*handler)(const wchar_t *cmd)) const;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** Create an autoload_t for the given environment variable name */
|
/** Create an autoload_t for the given environment variable name */
|
||||||
|
|
Loading…
Reference in a new issue