mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-13 13:39:02 +00:00
New file autoload.h that will ultimately handle autoloading completions and functions
This commit is contained in:
parent
4dfe36feb1
commit
e94e1cc72f
4 changed files with 252 additions and 9 deletions
|
@ -110,12 +110,16 @@
|
|||
D0A0856513B3ACEE0099B651 /* xdgmimeint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xdgmimeint.cpp; sourceTree = "<group>"; };
|
||||
D0A0856613B3ACEE0099B651 /* xdgmimemagic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xdgmimemagic.cpp; sourceTree = "<group>"; };
|
||||
D0A0856713B3ACEE0099B651 /* xdgmimeparent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = xdgmimeparent.cpp; sourceTree = "<group>"; };
|
||||
D0C6FCC914CFA4B0004CE8AD /* autoload.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = autoload.cpp; sourceTree = "<group>"; };
|
||||
D0C6FCCB14CFA4B7004CE8AD /* autoload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = autoload.h; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
D0A084F013B3AC130099B651 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D0C6FCCB14CFA4B7004CE8AD /* autoload.h */,
|
||||
D0C6FCC914CFA4B0004CE8AD /* autoload.cpp */,
|
||||
D0A0850313B3ACEE0099B651 /* builtin.h */,
|
||||
D0A0853013B3ACEE0099B651 /* builtin_commandline.cpp */,
|
||||
D0A0853113B3ACEE0099B651 /* builtin_complete.cpp */,
|
||||
|
|
18
Makefile.in
18
Makefile.in
|
@ -95,7 +95,7 @@ FISH_OBJS := function.o builtin.o complete.o env.o exec.o expand.o \
|
|||
highlight.o history.o kill.o parser.o proc.o reader.o sanity.o \
|
||||
tokenizer.o wildcard.o wgetopt.o wutil.o input.o output.o intern.o \
|
||||
env_universal.o env_universal_common.o input_common.o event.o \
|
||||
signal.o io.o parse_util.o common.o screen.o path.o \
|
||||
signal.o io.o parse_util.o common.o screen.o path.o autoload.o \
|
||||
parser_keywords.o iothread.o builtin_scripts.o
|
||||
|
||||
FISH_INDENT_OBJS := fish_indent.o print_help.o common.o \
|
||||
|
@ -905,8 +905,9 @@ clean:
|
|||
|
||||
# DO NOT DELETE THIS LINE -- make depend depends on it.
|
||||
|
||||
autoload.o: autoload.h common.h util.h
|
||||
builtin.o: config.h fallback.h util.h wutil.h builtin.h io.h function.h
|
||||
builtin.o: complete.h proc.h parser.h event.h common.h reader.h env.h
|
||||
builtin.o: common.h complete.h proc.h parser.h event.h reader.h env.h
|
||||
builtin.o: wgetopt.h sanity.h tokenizer.h wildcard.h input_common.h input.h
|
||||
builtin.o: intern.h signal.h exec.h highlight.h halloc.h halloc_util.h
|
||||
builtin.o: parse_util.h parser_keywords.h expand.h path.h builtin_set.cpp
|
||||
|
@ -921,7 +922,6 @@ builtin_complete.o: io.h common.h complete.h wgetopt.h parser.h proc.h
|
|||
builtin_complete.o: event.h reader.h
|
||||
builtin_jobs.o: config.h fallback.h util.h wutil.h builtin.h io.h proc.h
|
||||
builtin_jobs.o: parser.h event.h common.h wgetopt.h
|
||||
builtin_scripts.o: builtin_scripts.h
|
||||
builtin_set.o: config.h signal.h fallback.h util.h wutil.h builtin.h io.h
|
||||
builtin_set.o: env.h common.h expand.h wgetopt.h proc.h parser.h event.h
|
||||
builtin_ulimit.o: config.h fallback.h util.h builtin.h io.h common.h
|
||||
|
@ -942,8 +942,8 @@ env_universal.o: config.h signal.h fallback.h util.h common.h wutil.h
|
|||
env_universal.o: env_universal_common.h env_universal.h
|
||||
env_universal_common.o: config.h signal.h fallback.h util.h common.h wutil.h
|
||||
env_universal_common.o: env_universal_common.h
|
||||
event.o: config.h signal.h fallback.h util.h wutil.h function.h proc.h io.h
|
||||
event.o: parser.h event.h common.h halloc_util.h
|
||||
event.o: config.h signal.h fallback.h util.h wutil.h function.h common.h
|
||||
event.o: proc.h io.h parser.h event.h halloc_util.h
|
||||
exec.o: config.h signal.h fallback.h util.h common.h wutil.h proc.h io.h
|
||||
exec.o: exec.h parser.h event.h builtin.h function.h env.h wildcard.h
|
||||
exec.o: sanity.h expand.h halloc.h halloc_util.h parse_util.h
|
||||
|
@ -966,8 +966,8 @@ fish_tests.o: parser.h event.h tokenizer.h output.h exec.h path.h halloc.h
|
|||
fish_tests.o: halloc_util.h
|
||||
fishd.o: config.h signal.h fallback.h util.h common.h wutil.h
|
||||
fishd.o: env_universal_common.h halloc.h halloc_util.h path.h print_help.h
|
||||
function.o: config.h signal.h wutil.h fallback.h util.h function.h proc.h
|
||||
function.o: io.h parser.h event.h common.h intern.h reader.h parse_util.h
|
||||
function.o: config.h signal.h wutil.h fallback.h util.h function.h common.h
|
||||
function.o: proc.h io.h parser.h event.h intern.h reader.h parse_util.h
|
||||
function.o: parser_keywords.h env.h expand.h halloc.h halloc_util.h
|
||||
halloc.o: config.h fallback.h util.h common.h halloc.h
|
||||
halloc_util.o: config.h fallback.h util.h common.h halloc.h
|
||||
|
@ -984,7 +984,7 @@ input_common.o: config.h fallback.h util.h common.h wutil.h input_common.h
|
|||
input_common.o: env_universal.h env_universal_common.h iothread.h
|
||||
intern.o: config.h fallback.h util.h wutil.h common.h intern.h
|
||||
io.o: config.h fallback.h util.h wutil.h exec.h proc.h io.h common.h halloc.h
|
||||
iothread.o: iothread.h
|
||||
iothread.o: iothread.h signal.h
|
||||
key_reader.o: config.h fallback.h input_common.h
|
||||
kill.o: config.h signal.h fallback.h util.h wutil.h kill.h proc.h io.h
|
||||
kill.o: sanity.h common.h env.h exec.h halloc.h path.h
|
||||
|
@ -993,7 +993,7 @@ output.o: config.h signal.h fallback.h util.h wutil.h expand.h common.h
|
|||
output.o: output.h halloc_util.h highlight.h env.h
|
||||
parse_util.o: config.h fallback.h util.h wutil.h common.h tokenizer.h
|
||||
parse_util.o: parse_util.h expand.h intern.h exec.h proc.h io.h env.h
|
||||
parse_util.o: signal.h wildcard.h halloc_util.h builtin_scripts.h
|
||||
parse_util.o: signal.h wildcard.h halloc_util.h
|
||||
parser.o: config.h signal.h fallback.h util.h common.h wutil.h proc.h io.h
|
||||
parser.o: parser.h event.h parser_keywords.h tokenizer.h exec.h wildcard.h
|
||||
parser.o: function.h builtin.h env.h expand.h reader.h sanity.h
|
||||
|
|
164
autoload.cpp
Normal file
164
autoload.cpp
Normal file
|
@ -0,0 +1,164 @@
|
|||
/** \file autoload.cpp
|
||||
|
||||
The classes responsible for autoloading functions and completions.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "autoload.h"
|
||||
#include "wutil.h"
|
||||
#include <assert.h>
|
||||
|
||||
const size_t kLRULimit = 256;
|
||||
|
||||
/** A node in our LRU map */
|
||||
class file_access_node_t {
|
||||
public:
|
||||
file_access_node_t *prev, *next;
|
||||
const wcstring path;
|
||||
file_access_attempt_t attempt;
|
||||
|
||||
file_access_node_t(const wcstring &pathVar) : path(pathVar) { }
|
||||
|
||||
bool operator<(const file_access_node_t &other) const { return path < other.path; }
|
||||
};
|
||||
|
||||
/* By default, things are stale after 60 seconds */
|
||||
const time_t kFishDefaultStalenessInterval = 60;
|
||||
|
||||
access_tracker_t::access_tracker_t(time_t stale, int the_mode) :
|
||||
node_count(0),
|
||||
mouth(NULL),
|
||||
stale_interval(stale),
|
||||
mode(the_mode)
|
||||
{
|
||||
VOMIT_ON_FAILURE(pthread_mutex_init(&lock, NULL));
|
||||
}
|
||||
|
||||
access_tracker_t::~access_tracker_t() {
|
||||
VOMIT_ON_FAILURE(pthread_mutex_destroy(&lock));
|
||||
}
|
||||
|
||||
void access_tracker_t::vacuum_one_node(void) {
|
||||
/* Removes the least recently used access */
|
||||
assert(mouth && mouth->prev != mouth);
|
||||
|
||||
/* Remove us from the linked list */
|
||||
file_access_node_t *condemned_node = mouth->prev;
|
||||
condemned_node->prev->next = condemned_node->next;
|
||||
condemned_node->next->prev = condemned_node->prev;
|
||||
|
||||
/* Remove us from the set */
|
||||
access_set.erase(condemned_node);
|
||||
|
||||
/* Deleted */
|
||||
node_count--;
|
||||
delete condemned_node;
|
||||
}
|
||||
|
||||
void access_tracker_t::promote_node(file_access_node_t *node) {
|
||||
/* Promotes a node to the mouth, unless we're already there... */
|
||||
if (node == mouth) return;
|
||||
|
||||
/* First unhook us */
|
||||
node->prev->next = node->next;
|
||||
node->next->prev = node->prev;
|
||||
|
||||
/* Now become the mouth */
|
||||
node->next = mouth;
|
||||
node->prev = mouth->prev;
|
||||
mouth = node;
|
||||
}
|
||||
|
||||
/* Return the node referenced by the given string, or NULL */
|
||||
file_access_node_t *access_tracker_t::while_locked_find_node(const wcstring &path) const {
|
||||
file_access_node_t key(path);
|
||||
access_set_t::iterator iter = access_set.find(&key);
|
||||
return iter != access_set.end() ? *iter : NULL;
|
||||
}
|
||||
|
||||
file_access_attempt_t access_tracker_t::attempt_access(const wcstring& path) const {
|
||||
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(), 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 result = false;
|
||||
|
||||
/* Lock our lock */
|
||||
scoped_lock locker(lock);
|
||||
|
||||
/* Search for the node */
|
||||
file_access_node_t *node = while_locked_find_node(path);
|
||||
if (node) {
|
||||
promote_node(node);
|
||||
attempt = node->attempt;
|
||||
attempt.stale = (time(NULL) - node->attempt.last_checked > this->stale_interval);
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
file_access_attempt_t access_tracker_t::access_file(const wcstring &path) {
|
||||
file_access_attempt_t result;
|
||||
|
||||
/* Try just using our cache */
|
||||
if (access_file_only_cached(path, result) && ! result.stale) {
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Really access the file. Note we are not yet locked, and don't want to be, since this may be slow. */
|
||||
result = attempt_access(path);
|
||||
|
||||
/* Take the lock so we can insert. */
|
||||
scoped_lock locker(lock);
|
||||
|
||||
/* Maybe we had it cached and it was stale, or maybe someone else may have put it in the cache while we were unlocked */
|
||||
file_access_node_t *node = while_locked_find_node(path);
|
||||
|
||||
if (node != NULL) {
|
||||
/* Someone else put it in. Promote and overwrite it. */
|
||||
node->attempt = result;
|
||||
promote_node(node);
|
||||
} else {
|
||||
/* We did not find this node. Add it. */
|
||||
file_access_node_t *node = new file_access_node_t(path);
|
||||
node->attempt = result;
|
||||
|
||||
/* Insert into the set */
|
||||
access_set.insert(node);
|
||||
|
||||
/* Insert it into the linked list */
|
||||
if (mouth == NULL) {
|
||||
/* One element circularly linked list! */
|
||||
mouth = node->next = node->prev = node;
|
||||
} else {
|
||||
/* Normal circularly linked list operation */
|
||||
node->next = mouth;
|
||||
node->prev = mouth->prev;
|
||||
mouth = node;
|
||||
}
|
||||
|
||||
/* We have one more node now */
|
||||
++node_count;
|
||||
|
||||
/* Clean up if we're over our limit */
|
||||
while (node_count > kLRULimit)
|
||||
vacuum_one_node();
|
||||
}
|
||||
return result;
|
||||
}
|
75
autoload.h
Normal file
75
autoload.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
/** \file autoload.h
|
||||
|
||||
The classes responsible for autoloading functions and completions.
|
||||
*/
|
||||
|
||||
#ifndef FISH_PARSE_UTIL_H
|
||||
#define FISH_PARSE_UTIL_H
|
||||
|
||||
#include <wchar.h>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include "common.h"
|
||||
|
||||
extern const time_t kFishDefaultStalenessInterval;
|
||||
|
||||
/** A class responsible for recording an attempt to access a file. */
|
||||
class file_access_attempt_t {
|
||||
public:
|
||||
time_t mod_time; /** The modification time of the file */
|
||||
time_t last_checked; /** When we last checked the file */
|
||||
bool accessible; /** Whether we believe we could access this file */
|
||||
bool stale; /** Whether the access attempt is stale */
|
||||
int error; /** If we could not access the file, the error code */
|
||||
};
|
||||
|
||||
class file_access_node_t;
|
||||
|
||||
/** A predicate to compare dereferenced pointers */
|
||||
struct dereference_less_t {
|
||||
template <typename ptr_t>
|
||||
bool operator()(ptr_t p1, ptr_t p2) const { return *p1 < *p2; }
|
||||
};
|
||||
|
||||
|
||||
/** A class responsible for tracking accesses to files, including auto-expiration. */
|
||||
class access_tracker_t {
|
||||
private:
|
||||
|
||||
file_access_node_t * while_locked_find_node(const wcstring &str) const;
|
||||
void vacuum_one_node(void);
|
||||
void promote_node(file_access_node_t *);
|
||||
|
||||
file_access_attempt_t attempt_access(const wcstring& path) const;
|
||||
|
||||
unsigned int node_count;
|
||||
typedef std::set<file_access_node_t *, dereference_less_t> access_set_t;
|
||||
access_set_t access_set;
|
||||
file_access_node_t *mouth;
|
||||
|
||||
/* Lock for thread safety */
|
||||
pthread_mutex_t lock;
|
||||
|
||||
/** How long until a file access attempt is considered stale. */
|
||||
const time_t stale_interval;
|
||||
|
||||
/** Mode for waccess calls */
|
||||
const int mode;
|
||||
|
||||
public:
|
||||
|
||||
/** Constructor, that takes a staleness interval */
|
||||
access_tracker_t(time_t stale, int the_mode);
|
||||
|
||||
/** Destructor */
|
||||
~access_tracker_t();
|
||||
|
||||
/** Attempt to access the given file, if the last cached access is stale. Caches and returns the access attempt. */
|
||||
file_access_attempt_t access_file(const wcstring &path);
|
||||
|
||||
/** Returns whether there is a cached access (even if stale), without touching the disk; if the result is true, return by reference that access attempt. */
|
||||
bool access_file_only_cached(const wcstring &path, file_access_attempt_t &attempt);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue