lib9p

Go 9P library.
Log | Files | Refs

commit 5b7c15103632e9d8c9e2fdd54fc9d678f05b9d6f
parent c897af242bb0e837ad551f4431bf268fbfeac9c1
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Sat, 16 Sep 2023 08:17:05 +0900

fix deadlock and rename some functions

Diffstat:
Mfid.go | 27++++++++++++++++++---------
Mreq.go | 33++++++++++++++++++---------------
Mserver.go | 45++++++++++++++++++++++++++-------------------
3 files changed, 62 insertions(+), 43 deletions(-)

diff --git a/fid.go b/fid.go @@ -2,6 +2,7 @@ package lib9p import ( "fmt" + "sync" ) type OpenMode int8 // defined by 9P @@ -43,20 +44,28 @@ func (f *Fid) String() string { type FidPool struct { m map[uint32]*Fid + lock *sync.Mutex } func allocFidPool() *FidPool { - f := new(FidPool) - f.m = make(map[uint32]*Fid) - return f + return &FidPool{ + m: make(map[uint32]*Fid), + lock: new(sync.Mutex), + } } func (pool *FidPool) lookup(fid uint32) (*Fid, bool) { + pool.lock.Lock() + defer pool.lock.Unlock() + f, ok := pool.m[fid] return f, ok } func (pool *FidPool) alloc(fid uint32) (*Fid, error) { + pool.lock.Lock() + defer pool.lock.Unlock() + if _, ok := pool.m[fid]; ok { return nil, fmt.Errorf("fid already in use.") } @@ -65,16 +74,16 @@ func (pool *FidPool) alloc(fid uint32) (*Fid, error) { return f, nil } -func (pool *FidPool) delete(fid uint32) *Fid { - f, ok := pool.lookup(fid) - if !ok { - return nil - } +func (pool *FidPool) delete(fid uint32) { + pool.lock.Lock() + defer pool.lock.Unlock() + delete(pool.m, fid) - return f } func (pool *FidPool) String() string { + pool.lock.Lock() // TODO: need? + defer pool.lock.Unlock() s := "{" for fnum, fstruct := range pool.m { s += fmt.Sprintf(" [%d]%v", fnum, fstruct) diff --git a/req.go b/req.go @@ -1,7 +1,7 @@ package lib9p import ( - "fmt" + "sync" ) type Req struct { @@ -12,32 +12,35 @@ type Req struct { } type ReqPool struct { - m map[uint16]*Req + m map[uint16]*Req + lock *sync.Mutex } func allocReqPool() *ReqPool { - rp := new(ReqPool) - rp.m = make(map[uint16]*Req) - return rp + return &ReqPool{ + m: make(map[uint16]*Req), + lock: new(sync.Mutex), + } } -// AddReq allocates a Req with the specified tag in ReqPool rp. +// Add allocates a Req with the specified tag in ReqPool rp. // It returns nil, ErrDupTag if there is already a Req with the specified tag. -func (rp *ReqPool) addReq(tag uint16) (*Req, error) { +func (rp *ReqPool) add(tag uint16) (*Req, error) { + rp.lock.Lock() + defer rp.lock.Unlock() + if _, ok := rp.m[tag]; ok { return nil, ErrDupTag } - req := new(Req) - req.pool = rp + req := &Req{ + pool: rp, + } rp.m[tag] = req return req, nil } -func (rp *ReqPool) deleteReq(tag uint16) error { - _, ok := rp.m[tag] - if !ok { - return fmt.Errorf("tag %d not found", tag) - } +func (rp *ReqPool) delete(tag uint16) { + rp.lock.Lock() + defer rp.lock.Unlock() delete(rp.m, tag) - return nil } diff --git a/server.go b/server.go @@ -7,6 +7,7 @@ import ( "log" "os" "strings" + "sync" ) var chatty9P = false @@ -16,7 +17,7 @@ func Chatty() { } var ( - ErrBotch = fmt.Errorf("botch the rock") + ErrBotch = fmt.Errorf("bocchi") ErrPerm = fmt.Errorf("permission denied") ErrOperation = fmt.Errorf("operation not supported") ErrDupTag = fmt.Errorf("duplicate tag") @@ -25,26 +26,32 @@ var ( type Server struct { fs FS - MSize uint32 + mSize uint32 fPool *FidPool rPool *ReqPool - Reader io.Reader - Writer io.Writer + reader io.Reader + rlock *sync.Mutex + writer io.Writer + wlock *sync.Mutex } func NewServer(fsys FS, mSize uint32, r io.Reader, w io.Writer) *Server { return &Server{ fs: fsys, - MSize: mSize, + mSize: mSize, fPool: allocFidPool(), rPool: allocReqPool(), - Reader: r, - Writer: w, + reader: r, + rlock: new(sync.Mutex), + writer: w, + wlock: new(sync.Mutex), } } func (s *Server) getReq() (*Req, error) { - buf, err := read9PMsg(s.Reader) + s.rlock.Lock() + buf, err := read9PMsg(s.reader) + s.rlock.Unlock() if err != nil { if err == io.EOF { return nil, err @@ -52,7 +59,7 @@ func (s *Server) getReq() (*Req, error) { return nil, fmt.Errorf("read9PMsg: %v", err) } - r, err := s.rPool.addReq(bufMsg(buf).Tag()) + r, err := s.rPool.add(bufMsg(buf).Tag()) if err != nil { log.Printf("addReq(%d): %v", bufMsg(buf).Tag(), err) // duplicate tag: cons up a fake Req @@ -95,10 +102,10 @@ func sVersion(s *Server, r *Req) { version = "9P2000" } msize := ifcall.MSize() - if msize < s.MSize { - s.MSize = msize + if msize < s.mSize { + s.mSize = msize } else { - msize = s.MSize + msize = s.mSize } ofcall := &RVersion{ @@ -283,7 +290,7 @@ func sOpen(s *Server, r *Req) { r.ofcall = &ROpen{ tag: ifcall.Tag(), qid: fid.Qid, - iounit: s.MSize - 23, + iounit: s.mSize - 23, } respond(r, nil) } @@ -347,7 +354,7 @@ func sCreate(s *Server, r *Req) { r.ofcall = &RCreate{ tag: ifcall.Tag(), qid: fi.Qid(), - iounit: s.MSize - 23, + iounit: s.mSize - 23, } respond(r, nil) } @@ -493,7 +500,6 @@ func sRemove(s *Server, r *Req) { return } - // TODO: need lock? defer s.fPool.delete(ifcall.Fid()) parent, err := fid.File.Parent() @@ -753,9 +759,10 @@ func respond(r *Req, err error) { panic("ReqPool is nil but err is not EDupTag") } if r.pool != nil { - if err := r.pool.deleteReq(r.ifcall.Tag()); err != nil { - panic(fmt.Errorf("deleteReq: %v", err)) - } + r.pool.delete(r.ifcall.Tag()) } - r.srv.Writer.Write(r.ofcall.marshal()) + + r.srv.wlock.Lock() + r.srv.writer.Write(r.ofcall.marshal()) + r.srv.wlock.Unlock() }