Some reference counting code to help ref. count files

上级 cac83063
...@@ -4,13 +4,15 @@ ...@@ -4,13 +4,15 @@
#include "ns.hh" #include "ns.hh"
#include "gc.hh" #include "gc.hh"
#include "atomic.hh" #include "atomic.hh"
#include "ref.hh"
u64 namehash(const strbuf<DIRSIZ>&); u64 namehash(const strbuf<DIRSIZ>&);
struct file { struct file : public referenced {
file() : type(file::FD_NONE), readable(0), writable(0), file() : type(file::FD_NONE), readable(0), writable(0),
socket(0), pipe(nullptr), ip(nullptr), off(0), socket(0), pipe(nullptr), ip(nullptr), off(0) {
ref_(1) {} inc();
}
file *dup(); file *dup();
void close(); void close();
...@@ -25,8 +27,8 @@ struct file { ...@@ -25,8 +27,8 @@ struct file {
u32 off; u32 off;
NEW_DELETE_OPS(file); NEW_DELETE_OPS(file);
private: protected:
std::atomic<int> ref_; virtual void onzero() const;
}; };
// in-core file system types // in-core file system types
......
...@@ -28,16 +28,20 @@ public: ...@@ -28,16 +28,20 @@ public:
destroylock(&lock_); destroylock(&lock_);
} }
file *getfile(int fd) { bool getfile(int fd, sref<file> *sf) {
file *f; file *f;
if (fd < 0 || fd >= NOFILE) if (fd < 0 || fd >= NOFILE)
return nullptr; return false;
acquire(&lock_); acquire(&lock_);
f = ofile_[fd]; f = ofile_[fd];
// XXX(sbw) f->inc(); if (!f) {
release(&lock_);
return false;
}
sf->init(f);
release(&lock_); release(&lock_);
return f; return true;
} }
int allocfd(struct file *f) { int allocfd(struct file *f) {
......
#include "atomic.hh"
template <class T>
class sref {
public:
sref(T* p = nullptr) : ptr_(p) {
if (ptr_)
ptr_->inc();
}
~sref() {
if (ptr_)
ptr_->dec();
}
void init(T* p) {
const T* save = ptr_;
ptr_ = p;
if (ptr_)
ptr_->inc();
if (save)
save->dec();
}
bool operator==(const sref<T>& pr) const { return ptr_ == pr.ptr_; }
bool operator!=(const sref<T>& pr) const { return ptr_ != pr.ptr_; }
bool operator==(T* p) const { return ptr_ == p; }
bool operator!=(T* p) const { return ptr_ != p; }
const T * operator->() const { return ptr_; }
T * operator->() { return ptr_; }
T * ptr() const { return ptr_; }
private:
sref<T>& operator=(sref<T>& mp);
sref<T>& operator=(T* p);
sref<T>& operator=(const sref<T>& pr);
sref(const sref<T>& pr);
T *ptr_;
};
template <class T>
class lref {
public:
lref(T* p = nullptr) : ptr_(p) {
if (ptr_)
ptr_->inc();
}
lref(const lref<T>& pr) : ptr_(pr.ptr_) {
if (ptr_)
ptr_->inc();
}
~lref() {
if (ptr_)
ptr_->dec();
}
bool operator==(const lref<T>& pr) const { return ptr_ == pr.ptr_; }
bool operator!=(const lref<T>& pr) const { return ptr_ != pr.ptr_; }
bool operator==(T* p) const { return ptr_ == p; }
bool operator!=(T* p) const { return ptr_ != p; }
const T * operator->() const { return ptr_; }
T * operator->() { return ptr_; }
T * ptr() const { return ptr_; }
lref<T>& operator=(const lref<T>& pr) {
const T* save = ptr_;
ptr_ = pr.ptr_;
if (ptr_)
ptr_->inc();
if (save)
save->dec();
return *this;
}
private:
lref<T>& operator=( lref<T>& mp );
lref<T>& operator=( T* p );
T *ptr_;
};
class referenced {
public:
referenced() : ref_(0) {}
u64 ref() const {
return ref_;
}
inline const referenced* inc() const {
++ref_;
return this;
}
inline void dec() const {
if (--ref_ == 0)
onzero();
}
NEW_DELETE_OPS(referenced);
protected:
virtual ~referenced() { }
virtual void onzero() const { delete this; }
private:
mutable std::atomic<u64> ref_;
};
...@@ -56,7 +56,7 @@ long ...@@ -56,7 +56,7 @@ long
sys_async(int fd, size_t count, off_t off, sys_async(int fd, size_t count, off_t off,
msgid_t msgid, pageid_t pageid) msgid_t msgid, pageid_t pageid)
{ {
struct file *f; sref<file> f;;
cwork *w; cwork *w;
char *kshared = myproc()->vmap->kshared; char *kshared = myproc()->vmap->kshared;
...@@ -72,7 +72,7 @@ sys_async(int fd, size_t count, off_t off, ...@@ -72,7 +72,7 @@ sys_async(int fd, size_t count, off_t off,
msg = &ipcctl->msg[msgid]; msg = &ipcctl->msg[msgid];
ubuf = (kshared+PGSIZE+(pageid*PGSIZE)); ubuf = (kshared+PGSIZE+(pageid*PGSIZE));
if ((f = myproc()->ftable->getfile(fd)) == nullptr) if (!myproc()->ftable->getfile(fd, &f))
return -1; return -1;
if (f->type != file::FD_INODE) if (f->type != file::FD_INODE)
return -1; return -1;
......
...@@ -10,11 +10,8 @@ ...@@ -10,11 +10,8 @@
struct devsw __mpalign__ devsw[NDEV]; struct devsw __mpalign__ devsw[NDEV];
void void
file::close(void) file::onzero() const
{ {
if (--ref_ > 0)
return;
if(type == file::FD_PIPE) if(type == file::FD_PIPE)
pipeclose(pipe, writable); pipeclose(pipe, writable);
else if(type == file::FD_INODE) else if(type == file::FD_INODE)
...@@ -26,11 +23,16 @@ file::close(void) ...@@ -26,11 +23,16 @@ file::close(void)
delete this; delete this;
} }
void
file::close(void)
{
dec();
}
file* file*
file::dup(void) file::dup(void)
{ {
if (ref_++ < 1) inc();
panic("file::dup");
return this; return this;
} }
......
...@@ -12,24 +12,16 @@ ...@@ -12,24 +12,16 @@
#include "cpu.hh" #include "cpu.hh"
#include "net.hh" #include "net.hh"
// Fetch the nth word-sized system call argument as a file descriptor static bool
// and return both the descriptor and the corresponding struct file. getfile(int fd, sref<file> *f)
static int
argfd(int fd, struct file **pf)
{ {
struct file *f; return myproc()->ftable->getfile(fd, f);
if((f = myproc()->ftable->getfile(fd)) == nullptr)
return -1;
if(pf)
*pf = f;
return 0;
} }
// Allocate a file descriptor for the given file. // Allocate a file descriptor for the given file.
// Takes over file reference from caller on success. // Takes over file reference from caller on success.
static int static int
fdalloc(struct file *f) fdalloc(file *f)
{ {
return myproc()->ftable->allocfd(f); return myproc()->ftable->allocfd(f);
} }
...@@ -37,35 +29,37 @@ fdalloc(struct file *f) ...@@ -37,35 +29,37 @@ fdalloc(struct file *f)
long long
sys_dup(int ofd) sys_dup(int ofd)
{ {
struct file *f; sref<file> f;
int fd; int fd;
if(argfd(ofd, &f) < 0) if (!getfile(ofd, &f))
return -1; return -1;
if((fd=fdalloc(f)) < 0) f->inc();
if ((fd = fdalloc(f.ptr())) < 0) {
f->dec();
return -1; return -1;
f->dup(); }
return fd; return fd;
} }
s64 s64
sys_read(int fd, char *p, int n) sys_read(int fd, char *p, int n)
{ {
struct file *f; sref<file> f;
if(argfd(fd, &f) < 0 || argcheckptr(p, n) < 0) if(!getfile(fd, &f) || argcheckptr(p, n) < 0)
return -1; return -1;
return fileread(f, p, n); return fileread(f.ptr(), p, n);
} }
ssize_t ssize_t
sys_pread(int fd, void *ubuf, size_t count, off_t offset) sys_pread(int fd, void *ubuf, size_t count, off_t offset)
{ {
struct file *f; sref<file> f;
uptr i = (uptr)ubuf; uptr i = (uptr)ubuf;
int r; int r;
if ((f = myproc()->ftable->getfile(fd)) == nullptr) if (!getfile(fd, &f))
return -1; return -1;
for(uptr va = PGROUNDDOWN(i); va < i+count; va = va + PGSIZE) for(uptr va = PGROUNDDOWN(i); va < i+count; va = va + PGSIZE)
...@@ -86,19 +80,19 @@ sys_pread(int fd, void *ubuf, size_t count, off_t offset) ...@@ -86,19 +80,19 @@ sys_pread(int fd, void *ubuf, size_t count, off_t offset)
long long
sys_write(int fd, char *p, int n) sys_write(int fd, char *p, int n)
{ {
struct file *f; sref<file> f;
if(argfd(fd, &f) < 0 || argcheckptr(p, n) < 0) if (!getfile(fd, &f) || argcheckptr(p, n) < 0)
return -1; return -1;
return filewrite(f, p, n); return filewrite(f.ptr(), p, n);
} }
long long
sys_close(int fd) sys_close(int fd)
{ {
struct file *f; sref<file> f;
if(argfd(fd, &f) < 0) if (!getfile(fd, &f))
return -1; return -1;
myproc()->ftable->close(fd); myproc()->ftable->close(fd);
return 0; return 0;
...@@ -107,11 +101,11 @@ sys_close(int fd) ...@@ -107,11 +101,11 @@ sys_close(int fd)
long long
sys_fstat(int fd, struct stat *st) sys_fstat(int fd, struct stat *st)
{ {
struct file *f; sref<file> f;
if(argfd(fd, &f) < 0 || argcheckptr(st, sizeof(*st)) < 0) if (!getfile(fd, &f) || argcheckptr(st, sizeof(*st)) < 0)
return -1; return -1;
return filestat(f, st); return filestat(f.ptr(), st);
} }
// Create the path new as a link to the same inode as old. // Create the path new as a link to the same inode as old.
...@@ -287,8 +281,8 @@ sys_openat(int dirfd, const char *path, int omode) ...@@ -287,8 +281,8 @@ sys_openat(int dirfd, const char *path, int omode)
} else if (dirfd < 0 || dirfd >= NOFILE) { } else if (dirfd < 0 || dirfd >= NOFILE) {
return -1; return -1;
} else { } else {
struct file *fdir = myproc()->ftable->getfile(dirfd); sref<file> fdir;
if (fdir == nullptr || fdir->type != file::FD_INODE) if (!getfile(dirfd, &fdir) || fdir->type != file::FD_INODE)
return -1; return -1;
cwd = fdir->ip; cwd = fdir->ip;
} }
...@@ -430,17 +424,16 @@ freesocket(int fd) ...@@ -430,17 +424,16 @@ freesocket(int fd)
myproc()->ftable->close(fd); myproc()->ftable->close(fd);
} }
static int static bool
getsocket(int fd, struct file **ret) getsocket(int fd, sref<file> *f)
{ {
struct file *f; if (!getfile(fd, f))
if ((f = myproc()->ftable->getfile(fd)) == nullptr) return false;
return -1; if ((*f)->type != file::FD_SOCKET) {
if (f->type != file::FD_SOCKET) f->init(nullptr);
return -1; return false;
}
*ret = f; return true;
return 0;
} }
static int static int
...@@ -494,9 +487,9 @@ long ...@@ -494,9 +487,9 @@ long
sys_bind(int xsock, void *xaddr, int xaddrlen) sys_bind(int xsock, void *xaddr, int xaddrlen)
{ {
extern long netbind(int, void*, int); extern long netbind(int, void*, int);
struct file *f; sref<file> f;
if (getsocket(xsock, &f)) if (!getsocket(xsock, &f))
return -1; return -1;
return netbind(f->socket, xaddr, xaddrlen); return netbind(f->socket, xaddr, xaddrlen);
...@@ -506,9 +499,9 @@ long ...@@ -506,9 +499,9 @@ long
sys_listen(int xsock, int backlog) sys_listen(int xsock, int backlog)
{ {
extern long netlisten(int, int); extern long netlisten(int, int);
struct file *f; sref<file> f;
if (getsocket(xsock, &f)) if (!getsocket(xsock, &f))
return -1; return -1;
return netlisten(f->socket, backlog); return netlisten(f->socket, backlog);
...@@ -518,11 +511,12 @@ long ...@@ -518,11 +511,12 @@ long
sys_accept(int xsock, void *xaddr, void *xaddrlen) sys_accept(int xsock, void *xaddr, void *xaddrlen)
{ {
extern long netaccept(int, void*, void*); extern long netaccept(int, void*, void*);
struct file *f, *cf; file *cf;
sref<file> f;
int cfd; int cfd;
int ss; int ss;
if (getsocket(xsock, &f)) if (!getsocket(xsock, &f))
return -1; return -1;
if (allocsocket(&cf, &cfd)) if (allocsocket(&cf, &cfd))
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论