fossil: import from plan 9
R=rsc https://codereview.appspot.com/7988047
This commit is contained in:
parent
fea86f0639
commit
6f4d00ee45
50 changed files with 22325 additions and 0 deletions
304
src/cmd/fossil/9fid.c
Normal file
304
src/cmd/fossil/9fid.c
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
#include "stdinc.h"
|
||||
|
||||
#include "9.h"
|
||||
|
||||
static struct {
|
||||
VtLock* lock;
|
||||
|
||||
Fid* free;
|
||||
int nfree;
|
||||
int inuse;
|
||||
} fbox;
|
||||
|
||||
static void
|
||||
fidLock(Fid* fid, int flags)
|
||||
{
|
||||
if(flags & FidFWlock){
|
||||
vtLock(fid->lock);
|
||||
fid->flags = flags;
|
||||
}
|
||||
else
|
||||
vtRLock(fid->lock);
|
||||
|
||||
/*
|
||||
* Callers of file* routines are expected to lock fsys->fs->elk
|
||||
* before making any calls in order to make sure the epoch doesn't
|
||||
* change underfoot. With the exception of Tversion and Tattach,
|
||||
* that implies all 9P functions need to lock on entry and unlock
|
||||
* on exit. Fortunately, the general case is the 9P functions do
|
||||
* fidGet on entry and fidPut on exit, so this is a convenient place
|
||||
* to do the locking.
|
||||
* No fsys->fs->elk lock is required if the fid is being created
|
||||
* (Tauth, Tattach and Twalk). FidFCreate is always accompanied by
|
||||
* FidFWlock so the setting and testing of FidFCreate here and in
|
||||
* fidUnlock below is always done under fid->lock.
|
||||
* A side effect is that fidFree is called with the fid locked, and
|
||||
* must call fidUnlock only after it has disposed of any File
|
||||
* resources still held.
|
||||
*/
|
||||
if(!(flags & FidFCreate))
|
||||
fsysFsRlock(fid->fsys);
|
||||
}
|
||||
|
||||
static void
|
||||
fidUnlock(Fid* fid)
|
||||
{
|
||||
if(!(fid->flags & FidFCreate))
|
||||
fsysFsRUnlock(fid->fsys);
|
||||
if(fid->flags & FidFWlock){
|
||||
fid->flags = 0;
|
||||
vtUnlock(fid->lock);
|
||||
return;
|
||||
}
|
||||
vtRUnlock(fid->lock);
|
||||
}
|
||||
|
||||
static Fid*
|
||||
fidAlloc(void)
|
||||
{
|
||||
Fid *fid;
|
||||
|
||||
vtLock(fbox.lock);
|
||||
if(fbox.nfree > 0){
|
||||
fid = fbox.free;
|
||||
fbox.free = fid->hash;
|
||||
fbox.nfree--;
|
||||
}
|
||||
else{
|
||||
fid = vtMemAllocZ(sizeof(Fid));
|
||||
fid->lock = vtLockAlloc();
|
||||
fid->alock = vtLockAlloc();
|
||||
}
|
||||
fbox.inuse++;
|
||||
vtUnlock(fbox.lock);
|
||||
|
||||
fid->con = nil;
|
||||
fid->fidno = NOFID;
|
||||
fid->ref = 0;
|
||||
fid->flags = 0;
|
||||
fid->open = FidOCreate;
|
||||
assert(fid->fsys == nil);
|
||||
assert(fid->file == nil);
|
||||
fid->qid = (Qid){0, 0, 0};
|
||||
assert(fid->uid == nil);
|
||||
assert(fid->uname == nil);
|
||||
assert(fid->db == nil);
|
||||
assert(fid->excl == nil);
|
||||
assert(fid->rpc == nil);
|
||||
assert(fid->cuname == nil);
|
||||
fid->hash = fid->next = fid->prev = nil;
|
||||
|
||||
return fid;
|
||||
}
|
||||
|
||||
static void
|
||||
fidFree(Fid* fid)
|
||||
{
|
||||
if(fid->file != nil){
|
||||
fileDecRef(fid->file);
|
||||
fid->file = nil;
|
||||
}
|
||||
if(fid->db != nil){
|
||||
dirBufFree(fid->db);
|
||||
fid->db = nil;
|
||||
}
|
||||
fidUnlock(fid);
|
||||
|
||||
if(fid->uid != nil){
|
||||
vtMemFree(fid->uid);
|
||||
fid->uid = nil;
|
||||
}
|
||||
if(fid->uname != nil){
|
||||
vtMemFree(fid->uname);
|
||||
fid->uname = nil;
|
||||
}
|
||||
if(fid->excl != nil)
|
||||
exclFree(fid);
|
||||
if(fid->rpc != nil){
|
||||
close(fid->rpc->afd);
|
||||
auth_freerpc(fid->rpc);
|
||||
fid->rpc = nil;
|
||||
}
|
||||
if(fid->fsys != nil){
|
||||
fsysPut(fid->fsys);
|
||||
fid->fsys = nil;
|
||||
}
|
||||
if(fid->cuname != nil){
|
||||
vtMemFree(fid->cuname);
|
||||
fid->cuname = nil;
|
||||
}
|
||||
|
||||
vtLock(fbox.lock);
|
||||
fbox.inuse--;
|
||||
if(fbox.nfree < 10){
|
||||
fid->hash = fbox.free;
|
||||
fbox.free = fid;
|
||||
fbox.nfree++;
|
||||
}
|
||||
else{
|
||||
vtLockFree(fid->alock);
|
||||
vtLockFree(fid->lock);
|
||||
vtMemFree(fid);
|
||||
}
|
||||
vtUnlock(fbox.lock);
|
||||
}
|
||||
|
||||
static void
|
||||
fidUnHash(Fid* fid)
|
||||
{
|
||||
Fid *fp, **hash;
|
||||
|
||||
assert(fid->ref == 0);
|
||||
|
||||
hash = &fid->con->fidhash[fid->fidno % NFidHash];
|
||||
for(fp = *hash; fp != nil; fp = fp->hash){
|
||||
if(fp == fid){
|
||||
*hash = fp->hash;
|
||||
break;
|
||||
}
|
||||
hash = &fp->hash;
|
||||
}
|
||||
assert(fp == fid);
|
||||
|
||||
if(fid->prev != nil)
|
||||
fid->prev->next = fid->next;
|
||||
else
|
||||
fid->con->fhead = fid->next;
|
||||
if(fid->next != nil)
|
||||
fid->next->prev = fid->prev;
|
||||
else
|
||||
fid->con->ftail = fid->prev;
|
||||
fid->prev = fid->next = nil;
|
||||
|
||||
fid->con->nfid--;
|
||||
}
|
||||
|
||||
Fid*
|
||||
fidGet(Con* con, u32int fidno, int flags)
|
||||
{
|
||||
Fid *fid, **hash;
|
||||
|
||||
if(fidno == NOFID)
|
||||
return nil;
|
||||
|
||||
hash = &con->fidhash[fidno % NFidHash];
|
||||
vtLock(con->fidlock);
|
||||
for(fid = *hash; fid != nil; fid = fid->hash){
|
||||
if(fid->fidno != fidno)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Already in use is an error
|
||||
* when called from attach, clone or walk.
|
||||
*/
|
||||
if(flags & FidFCreate){
|
||||
vtUnlock(con->fidlock);
|
||||
vtSetError("%s: fid 0x%ud in use", argv0, fidno);
|
||||
return nil;
|
||||
}
|
||||
fid->ref++;
|
||||
vtUnlock(con->fidlock);
|
||||
|
||||
fidLock(fid, flags);
|
||||
if((fid->open & FidOCreate) || fid->fidno == NOFID){
|
||||
fidPut(fid);
|
||||
vtSetError("%s: fid invalid", argv0);
|
||||
return nil;
|
||||
}
|
||||
return fid;
|
||||
}
|
||||
|
||||
if((flags & FidFCreate) && (fid = fidAlloc()) != nil){
|
||||
assert(flags & FidFWlock);
|
||||
fid->con = con;
|
||||
fid->fidno = fidno;
|
||||
fid->ref = 1;
|
||||
|
||||
fid->hash = *hash;
|
||||
*hash = fid;
|
||||
if(con->ftail != nil){
|
||||
fid->prev = con->ftail;
|
||||
con->ftail->next = fid;
|
||||
}
|
||||
else{
|
||||
con->fhead = fid;
|
||||
fid->prev = nil;
|
||||
}
|
||||
con->ftail = fid;
|
||||
fid->next = nil;
|
||||
|
||||
con->nfid++;
|
||||
vtUnlock(con->fidlock);
|
||||
|
||||
/*
|
||||
* The FidOCreate flag is used to prevent any
|
||||
* accidental access to the Fid between unlocking the
|
||||
* hash and acquiring the Fid lock for return.
|
||||
*/
|
||||
fidLock(fid, flags);
|
||||
fid->open &= ~FidOCreate;
|
||||
return fid;
|
||||
}
|
||||
vtUnlock(con->fidlock);
|
||||
|
||||
vtSetError("%s: fid not found", argv0);
|
||||
return nil;
|
||||
}
|
||||
|
||||
void
|
||||
fidPut(Fid* fid)
|
||||
{
|
||||
vtLock(fid->con->fidlock);
|
||||
assert(fid->ref > 0);
|
||||
fid->ref--;
|
||||
vtUnlock(fid->con->fidlock);
|
||||
|
||||
if(fid->ref == 0 && fid->fidno == NOFID){
|
||||
fidFree(fid);
|
||||
return;
|
||||
}
|
||||
fidUnlock(fid);
|
||||
}
|
||||
|
||||
void
|
||||
fidClunk(Fid* fid)
|
||||
{
|
||||
assert(fid->flags & FidFWlock);
|
||||
|
||||
vtLock(fid->con->fidlock);
|
||||
assert(fid->ref > 0);
|
||||
fid->ref--;
|
||||
fidUnHash(fid);
|
||||
fid->fidno = NOFID;
|
||||
vtUnlock(fid->con->fidlock);
|
||||
|
||||
if(fid->ref > 0){
|
||||
/* not reached - fidUnHash requires ref == 0 */
|
||||
fidUnlock(fid);
|
||||
return;
|
||||
}
|
||||
fidFree(fid);
|
||||
}
|
||||
|
||||
void
|
||||
fidClunkAll(Con* con)
|
||||
{
|
||||
Fid *fid;
|
||||
u32int fidno;
|
||||
|
||||
vtLock(con->fidlock);
|
||||
while(con->fhead != nil){
|
||||
fidno = con->fhead->fidno;
|
||||
vtUnlock(con->fidlock);
|
||||
if((fid = fidGet(con, fidno, FidFWlock)) != nil)
|
||||
fidClunk(fid);
|
||||
vtLock(con->fidlock);
|
||||
}
|
||||
vtUnlock(con->fidlock);
|
||||
}
|
||||
|
||||
void
|
||||
fidInit(void)
|
||||
{
|
||||
fbox.lock = vtLockAlloc();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue