提交 80920c8a 创建 作者: Nickolai Zeldovich's avatar Nickolai Zeldovich

Merge branch 'scale-amd64' of git+ssh://pdos.csail.mit.edu/home/am0/6.828/xv6 into scale-amd64

...@@ -8,9 +8,9 @@ ...@@ -8,9 +8,9 @@
u64 namehash(const strbuf<DIRSIZ>&); u64 namehash(const strbuf<DIRSIZ>&);
struct file : public referenced { struct file : public referenced, public rcu_freed {
static file *alloc(); static file* alloc();
file *dup(); file* dup();
int stat(struct stat*); int stat(struct stat*);
int read(char *addr, int n); int read(char *addr, int n);
ssize_t pread(char *addr, size_t n, off_t offset); ssize_t pread(char *addr, size_t n, off_t offset);
...@@ -25,10 +25,14 @@ struct file : public referenced { ...@@ -25,10 +25,14 @@ struct file : public referenced {
struct pipe *pipe; struct pipe *pipe;
struct inode *ip; struct inode *ip;
u32 off; u32 off;
NEW_DELETE_OPS(file);
virtual void do_gc(void);
private: private:
file(); file();
file& operator=(const file&);
file(const file& x);
NEW_DELETE_OPS(file);
protected: protected:
virtual void onzero() const; virtual void onzero() const;
......
...@@ -2,58 +2,40 @@ ...@@ -2,58 +2,40 @@
class filetable { class filetable {
public: public:
filetable() : ref_(1) { static filetable* alloc() {
for(int fd = 0; fd < NOFILE; fd++) return new filetable();
ofile_[fd] = nullptr;
initlock(&lock_, "filetable", 0);
} }
filetable(const filetable &f) : ref_(1) { filetable* copy() {
filetable* t = alloc();
if (t == nullptr)
return nullptr;
for(int fd = 0; fd < NOFILE; fd++) { for(int fd = 0; fd < NOFILE; fd++) {
if (f.ofile_[fd]) sref<file> f;
ofile_[fd] = f.ofile_[fd]->dup(); if (getfile(fd, &f))
t->ofile_[fd].store(f->dup());
else else
ofile_[fd] = nullptr; t->ofile_[fd] = nullptr;
} }
initlock(&lock_, "filetable", 0); return t;
}
~filetable() {
for(int fd = 0; fd < NOFILE; fd++){
if (ofile_[fd]){
ofile_[fd]->dec();
ofile_[fd] = 0;
}
}
destroylock(&lock_);
} }
bool getfile(int fd, sref<file> *sf) { bool getfile(int fd, sref<file> *sf) {
file *f;
if (fd < 0 || fd >= NOFILE) if (fd < 0 || fd >= NOFILE)
return false; return false;
acquire(&lock_);
f = ofile_[fd]; scoped_gc_epoch gc;
if (!f) { file* f = ofile_[fd];
release(&lock_); if (!f || !sf->init(f))
return false; return false;
}
sf->init(f);
release(&lock_);
return true; return true;
} }
int allocfd(struct file *f) { int allocfd(struct file *f) {
acquire(&lock_); for (int fd = 0; fd < NOFILE; fd++)
for (int fd = 0; fd < NOFILE; fd++) { if (ofile_[fd] == nullptr && cmpxch(&ofile_[fd], (file*)nullptr, f))
if (ofile_[fd] == nullptr){
ofile_[fd] = f;
release(&lock_);
return fd; return fd;
}
}
release(&lock_);
cprintf("filetable::allocfd: failed\n"); cprintf("filetable::allocfd: failed\n");
return -1; return -1;
} }
...@@ -61,15 +43,13 @@ public: ...@@ -61,15 +43,13 @@ public:
void close(int fd) { void close(int fd) {
// XXX(sbw) if f->ref_ > 1 the kernel will not actually close // XXX(sbw) if f->ref_ > 1 the kernel will not actually close
// the file when this function returns (i.e. sys_close can return // the file when this function returns (i.e. sys_close can return
// while the file/pipe/socket is still open). Maybe we should clear // while the file/pipe/socket is still open).
// ofile_[fd], wait until f.ref_ == 1, f->dec(), and then return.
acquire(&lock_); file* f = ofile_[fd].exchange(nullptr);
struct file *f = ofile_[fd]; if (f != nullptr)
ofile_[fd] = nullptr;
release(&lock_);
if (f)
f->dec(); f->dec();
else
cprintf("filetable::close: bad fd %u\n", fd);
} }
void decref() { void decref() {
...@@ -81,10 +61,25 @@ public: ...@@ -81,10 +61,25 @@ public:
ref_++; ref_++;
} }
NEW_DELETE_OPS(filetable)
private: private:
struct file *ofile_[NOFILE]; filetable() : ref_(1) {
for(int fd = 0; fd < NOFILE; fd++)
ofile_[fd] = nullptr;
}
~filetable() {
for(int fd = 0; fd < NOFILE; fd++){
if (ofile_[fd]){
ofile_[fd].load()->dec();
ofile_[fd] = nullptr;
}
}
}
filetable& operator=(const filetable&);
filetable(const filetable& x);
NEW_DELETE_OPS(filetable);
std::atomic<file*> ofile_[NOFILE];
std::atomic<u64> ref_; std::atomic<u64> ref_;
struct spinlock lock_;
}; };
#include "atomic.hh"
template <class T> template <class T>
class sref { class sref {
public: public:
...@@ -13,13 +11,11 @@ public: ...@@ -13,13 +11,11 @@ public:
ptr_->dec(); ptr_->dec();
} }
void init(T* p) { bool init(T* p) {
const T* save = ptr_; if (ptr_ || !p->tryinc())
return false;
ptr_ = p; ptr_ = p;
if (ptr_) return true;
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_; }
...@@ -40,65 +36,36 @@ private: ...@@ -40,65 +36,36 @@ private:
T *ptr_; T *ptr_;
}; };
template <class T> class referenced {
class lref {
public: public:
lref(T* p = nullptr) : ptr_(p) { // Start with 1 reference
if (ptr_) referenced() { ref_.v = 0; }
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_; } // The number of valid references is:
bool operator!=(const lref<T>& pr) const { return ptr_ != pr.ptr_; } // ref_.invalid ? 0 : ref_.count+1;
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) { inline bool valid() const {
const T* save = ptr_; return ref_.invalid == 0;
ptr_ = pr.ptr_;
if (ptr_)
ptr_->inc();
if (save)
save->dec();
return *this;
} }
private: inline void inc() const {
lref<T>& operator=( lref<T>& mp ); // If references is 0 (i.e. ref_.count is 0xffffffff) a 32-bit
lref<T>& operator=( T* p ); // increment will increases ref_.count to 0, but ref_.invalid
// will remain unchanged.
T *ptr_; asm volatile("lock; incl %0" : "+m" (ref_.count));
};
class referenced {
public:
referenced() : ref_(0) {}
u64 ref() const {
return ref_;
} }
inline const referenced* inc() const { inline bool tryinc() const {
++ref_; inc();
return this; return valid();
} }
inline void dec() const { inline void dec() const {
if (--ref_ == 0) unsigned char c;
// If references is 1 (i.e. ref_.v is 0), a 64-bit decrement will
// underflow ref_.invalid to 0xffffffff (and ref_.count to 0xffffffff).
asm volatile("lock; decq %0; sets %1" : "+m" (ref_.v), "=qm" (c));
if (c)
onzero(); onzero();
} }
...@@ -109,5 +76,11 @@ protected: ...@@ -109,5 +76,11 @@ protected:
virtual void onzero() const { delete this; } virtual void onzero() const { delete this; }
private: private:
mutable std::atomic<u64> ref_; mutable union {
volatile u64 v;
struct {
volatile u32 count;
volatile u32 invalid;
};
} ref_;
}; };
...@@ -16,10 +16,10 @@ file::alloc(void) ...@@ -16,10 +16,10 @@ file::alloc(void)
} }
file::file(void) file::file(void)
: type(file::FD_NONE), readable(0), writable(0), : rcu_freed("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)
{ {
inc();
} }
void void
...@@ -33,6 +33,12 @@ file::onzero(void) const ...@@ -33,6 +33,12 @@ file::onzero(void) const
netclose(socket); netclose(socket);
else if(type != file::FD_NONE) else if(type != file::FD_NONE)
panic("file::close bad type"); panic("file::close bad type");
gc_delayed((file*)this);
}
void
file::do_gc(void)
{
delete this; delete this;
} }
......
...@@ -377,7 +377,7 @@ fork(int flags) ...@@ -377,7 +377,7 @@ fork(int flags)
myproc()->ftable->incref(); myproc()->ftable->incref();
np->ftable = myproc()->ftable; np->ftable = myproc()->ftable;
} else { } else {
np->ftable = new filetable(*myproc()->ftable); np->ftable = myproc()->ftable->copy();
if (np->ftable == nullptr) { if (np->ftable == nullptr) {
// XXX(sbw) leaking? // XXX(sbw) leaking?
freeproc(np); freeproc(np);
......
...@@ -21,7 +21,7 @@ inituser(void) ...@@ -21,7 +21,7 @@ inituser(void)
extern u64 _initcode_size; extern u64 _initcode_size;
p = proc::alloc(); p = proc::alloc();
p->ftable = new filetable(); p->ftable = filetable::alloc();
if (p->ftable == nullptr) if (p->ftable == nullptr)
panic("userinit: new filetable"); panic("userinit: new filetable");
bootproc = p; bootproc = p;
......
...@@ -84,13 +84,13 @@ long ...@@ -84,13 +84,13 @@ long
uwq_worker::wait(void) uwq_worker::wait(void)
{ {
acquire(&lock_); acquire(&lock_);
if (uwq_->ref() == 0) if (!uwq_->valid())
this->exit(); this->exit();
running_ = false; running_ = false;
cv_sleep(&cv_, &lock_); cv_sleep(&cv_, &lock_);
if (uwq_->ref() == 0) if (!uwq_->valid())
this->exit(); this->exit();
release(&lock_); release(&lock_);
return 0; return 0;
...@@ -119,7 +119,6 @@ uwq::alloc(vmap* vmap, filetable *ftable) ...@@ -119,7 +119,6 @@ uwq::alloc(vmap* vmap, filetable *ftable)
ksfree(slab_userwq, len); ksfree(slab_userwq, len);
return nullptr; return nullptr;
} }
u->inc();
if (mapkva(vmap->pml4, (char*)len, USERWQ, USERWQSIZE)) { if (mapkva(vmap->pml4, (char*)len, USERWQ, USERWQSIZE)) {
ftable->decref(); ftable->decref();
...@@ -172,7 +171,7 @@ uwq::tryworker(void) ...@@ -172,7 +171,7 @@ uwq::tryworker(void)
// Try to start a worker thread // Try to start a worker thread
scoped_acquire lock0(&lock_); scoped_acquire lock0(&lock_);
if (ref() == 0) if (!valid())
return false; return false;
int slot = -1; int slot = -1;
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
#define PERFSIZE (1<<20ull) #define PERFSIZE (1<<20ull)
#elif defined(HW_qemu) #elif defined(HW_qemu)
#define NCPU 8 // maximum number of CPUs #define NCPU 8 // maximum number of CPUs
#define MTRACE 1 #define MTRACE 0
#define PERFSIZE (16<<20ull) #define PERFSIZE (16<<20ull)
#elif defined(HW_ud0) #elif defined(HW_ud0)
#define NCPU 4 // maximum number of CPUs #define NCPU 4 // maximum number of CPUs
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论