lib9p

Go 9P library.
Log | Files | Refs | LICENSE

commit 1579f3bf347e9b217b1f310a885bc7443491122a
parent 813e7119de7a4a2864c487c87b59eec939c366da
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Sun, 21 Jan 2024 08:25:02 +0900

delete client's listener goroutine

Diffstat:
Mclient/client.go | 109+++++++++++++++++++++----------------------------------------------------------
Mclient/client_test.go | 61+++++++++++++++++++++++++++++++------------------------------
2 files changed, 59 insertions(+), 111 deletions(-)

diff --git a/client/client.go b/client/client.go @@ -61,8 +61,7 @@ func NewClient(ctx context.Context, mSize uint32, uname string, r io.Reader, w i done: ctx.Done(), } tmsgc := c.runSpeaker(ctx, w) - rmsgc := c.runListener(ctx, r) - c.txc = c.runMultiplexer(ctx, tmsgc, rmsgc) + c.txc = c.runMultiplexer(ctx, tmsgc, r) c.runErrorReporter(ctx) return c } @@ -103,57 +102,6 @@ func (c *Client) runErrorReporter(ctx context.Context) { }() } -// RunListener runs listener goroutine. -// Listener reads byte array of 9P messages from r and make each of them into -// corresponding struct that implements lib9p.Msg, -// and sends it to the returned channel. -// Listener goroutine returns when ctx is canceled. -// Listener goroutine reports errors to the client's errc channel. -func (c *Client) runListener(ctx context.Context, r io.Reader) <-chan lib9p.Msg { - c.wg.Add(1) - rmsgc := make(chan lib9p.Msg, 3) - go func() { - defer func() { - close(rmsgc) - c.wg.Done() - }() - for { - select { - case <-ctx.Done(): - return - default: - done := make(chan struct{}) - var ( - msg lib9p.Msg - err error - ) - go func() { - defer close(done) - msg, err = lib9p.RecvMsg(r) - }() - select { - case <-done: - case <-ctx.Done(): - return - } - if err != nil { - if err == io.EOF { - c.errc <- err - } else { - c.errc <- fmt.Errorf("recv: %v", err) - } - continue - } - select { - case rmsgc <- msg: - case <-ctx.Done(): - } - } - } - }() - return rmsgc -} - // RunSpeaker runs speaker goroutine. // Speaker goroutine recieves 9P lib9p.Msgs from the returned channel, // marshal them into byte arrays and sends them to w. @@ -190,44 +138,43 @@ func (c *Client) runSpeaker(ctx context.Context, w io.Writer) chan<- lib9p.Msg { // After recieving the reply, it sets the *req.rmsg and sends it to the // *req.rxc. // It reports any errors to the client's errc channel. -func (c *Client) runMultiplexer(ctx context.Context, tmsgc chan<- lib9p.Msg, rmsgc <-chan lib9p.Msg) chan<- *req { +func (c *Client) runMultiplexer(ctx context.Context, tmsgc chan<- lib9p.Msg, r io.Reader) chan<- *req { c.wg.Add(2) txc := make(chan *req) rPool := newReqPool() // Rmsg go func() { - defer func() { - c.wg.Done() - }() + defer c.wg.Done() for { - select { - case <-ctx.Done(): - return - case msg, ok := <-rmsgc: - if !ok { - return + msg, err := lib9p.RecvMsg(r) + if err != nil { + if err == io.EOF { + c.errc <- err + } else { + c.errc <- fmt.Errorf("recv: %v", err) } - r, ok := rPool.lookup(msg.GetTag()) - if !ok { - c.errc <- fmt.Errorf("mux: unknown tag for msg: %v", msg) - continue - } - rPool.delete(msg.GetTag()) - if tflush, ok := r.tmsg.(*lib9p.TFlush); ok { - if _, ok := msg.(*lib9p.RFlush); !ok { - r.errc <- fmt.Errorf("mux: response to Tflush is not Rflush") - } - if oldreq, ok := rPool.lookup(tflush.Oldtag); ok { - oldreq.errc <- errors.New("request flushed") - rPool.delete(tflush.Oldtag) - } + continue + } + rq, ok := rPool.lookup(msg.GetTag()) + if !ok { + c.errc <- fmt.Errorf("mux: unknown tag for msg: %v", msg) + continue + } + rPool.delete(msg.GetTag()) + if tflush, ok := rq.tmsg.(*lib9p.TFlush); ok { + if _, ok := msg.(*lib9p.RFlush); !ok { + rq.errc <- fmt.Errorf("mux: response to Tflush is not Rflush") } - r.rmsg = msg - select { - case <-ctx.Done(): - case r.rxc <- r: + if oldreq, ok := rPool.lookup(tflush.Oldtag); ok { + oldreq.errc <- errors.New("request flushed") + rPool.delete(tflush.Oldtag) } } + rq.rmsg = msg + select { + case <-ctx.Done(): + case rq.rxc <- rq: + } } }() // Tmsg diff --git a/client/client_test.go b/client/client_test.go @@ -50,7 +50,7 @@ func TestDupTag(t *testing.T) { } } -func newClientForTest(ctx context.Context, msize uint32, uname string) (*Client, <-chan lib9p.Msg, chan<- lib9p.Msg) { +func newClientForTest(ctx context.Context, msize uint32, uname string) (*Client, <-chan lib9p.Msg, io.Writer) { c := &Client{ msize: msize, mSizeLock: new(sync.Mutex), @@ -59,9 +59,10 @@ func newClientForTest(ctx context.Context, msize uint32, uname string) (*Client, errc: make(chan error), wg: new(sync.WaitGroup), } - tmsgc, rmsgc := make(chan lib9p.Msg), make(chan lib9p.Msg) - c.txc = c.runMultiplexer(ctx, tmsgc, rmsgc) - return c, tmsgc, rmsgc + tmsgc := make(chan lib9p.Msg) + r, w := io.Pipe() + c.txc = c.runMultiplexer(ctx, tmsgc, r) + return c, tmsgc, w } func TestVersion(t *testing.T) { @@ -80,7 +81,7 @@ func TestVersion(t *testing.T) { for _, test := range tests { func() { ctx, cancel := context.WithCancel(context.Background()) - c, tmsgc, rmsgc := newClientForTest(ctx, 1024, "glenda") + c, tmsgc, w := newClientForTest(ctx, 1024, "glenda") defer cancel() var ( gotmsize uint32 @@ -100,7 +101,7 @@ func TestVersion(t *testing.T) { test.name, test.tmsg, gottmsg) return } - rmsgc <- test.rmsg + lib9p.SendMsg(test.rmsg, w) select { case err := <-c.errc: t.Errorf("client error: %v", err) @@ -145,7 +146,7 @@ func TestAuth(t *testing.T) { for _, test := range tests { func() { ctx, cancel := context.WithCancel(context.Background()) - c, tmsgc, rmsgc := newClientForTest(ctx, 1024, "glenda") + c, tmsgc, w := newClientForTest(ctx, 1024, "glenda") defer cancel() var ( gotaqid lib9p.Qid @@ -164,7 +165,7 @@ func TestAuth(t *testing.T) { test.name, test.tmsg, gottmsg) return } - rmsgc <- test.rmsg + lib9p.SendMsg(test.rmsg, w) select { case err := <-c.errc: t.Errorf("client error: %v", err) @@ -208,7 +209,7 @@ func TestAttach(t *testing.T) { for _, test := range tests { func() { ctx, cancel := context.WithCancel(context.Background()) - c, tmsgc, rmsgc := newClientForTest(ctx, 1024, "glenda") + c, tmsgc, w := newClientForTest(ctx, 1024, "glenda") defer cancel() var ( gotqid lib9p.Qid @@ -227,7 +228,7 @@ func TestAttach(t *testing.T) { test.name, test.tmsg, gottmsg) return } - rmsgc <- test.rmsg + lib9p.SendMsg(test.rmsg, w) select { case err := <-c.errc: t.Errorf("client error: %v", err) @@ -268,7 +269,7 @@ func TestFlush(t *testing.T) { for _, test := range tests { func() { ctx, cancel := context.WithCancel(context.Background()) - c, tmsgc, rmsgc := newClientForTest(ctx, 1024, "glenda") + c, tmsgc, w := newClientForTest(ctx, 1024, "glenda") defer cancel() var ( goterr error @@ -286,7 +287,7 @@ func TestFlush(t *testing.T) { test.name, test.tmsg, gottmsg) return } - rmsgc <- test.rmsg + lib9p.SendMsg(test.rmsg, w) select { case err := <-c.errc: t.Errorf("client error: %v", err) @@ -326,7 +327,7 @@ func TestWalk(t *testing.T) { for _, test := range tests { func() { ctx, cancel := context.WithCancel(context.Background()) - c, tmsgc, rmsgc := newClientForTest(ctx, 1024, "glenda") + c, tmsgc, w := newClientForTest(ctx, 1024, "glenda") defer cancel() var ( gotqids []lib9p.Qid @@ -345,7 +346,7 @@ func TestWalk(t *testing.T) { test.name, test.tmsg, gottmsg) return } - rmsgc <- test.rmsg + lib9p.SendMsg(test.rmsg, w) select { case err := <-c.errc: t.Errorf("client error: %v", err) @@ -389,7 +390,7 @@ func TestOpen(t *testing.T) { for _, test := range tests { func() { ctx, cancel := context.WithCancel(context.Background()) - c, tmsgc, rmsgc := newClientForTest(ctx, 1024, "glenda") + c, tmsgc, w := newClientForTest(ctx, 1024, "glenda") defer cancel() var ( gotqid lib9p.Qid @@ -409,7 +410,7 @@ func TestOpen(t *testing.T) { test.name, test.tmsg, gottmsg) return } - rmsgc <- test.rmsg + lib9p.SendMsg(test.rmsg, w) select { case err := <-c.errc: t.Errorf("client error: %v", err) @@ -453,7 +454,7 @@ func TestCreate(t *testing.T) { for _, test := range tests { func() { ctx, cancel := context.WithCancel(context.Background()) - c, tmsgc, rmsgc := newClientForTest(ctx, 1024, "glenda") + c, tmsgc, w := newClientForTest(ctx, 1024, "glenda") defer cancel() var ( gotqid lib9p.Qid @@ -473,7 +474,7 @@ func TestCreate(t *testing.T) { test.name, test.tmsg, gottmsg) return } - rmsgc <- test.rmsg + lib9p.SendMsg(test.rmsg, w) select { case err := <-c.errc: t.Errorf("client error: %v", err) @@ -517,7 +518,7 @@ func TestRead(t *testing.T) { for _, test := range tests { func() { ctx, cancel := context.WithCancel(context.Background()) - c, tmsgc, rmsgc := newClientForTest(ctx, 1024, "glenda") + c, tmsgc, w := newClientForTest(ctx, 1024, "glenda") defer cancel() var ( gotdata []byte @@ -536,7 +537,7 @@ func TestRead(t *testing.T) { test.name, test.tmsg, gottmsg) return } - rmsgc <- test.rmsg + lib9p.SendMsg(test.rmsg, w) select { case err := <-c.errc: t.Errorf("client error: %v", err) @@ -580,7 +581,7 @@ func TestWrite(t *testing.T) { for _, test := range tests { func() { ctx, cancel := context.WithCancel(context.Background()) - c, tmsgc, rmsgc := newClientForTest(ctx, 1024, "glenda") + c, tmsgc, w := newClientForTest(ctx, 1024, "glenda") defer cancel() var ( gotcount uint32 @@ -599,7 +600,7 @@ func TestWrite(t *testing.T) { test.name, test.tmsg, gottmsg) return } - rmsgc <- test.rmsg + lib9p.SendMsg(test.rmsg, w) select { case err := <-c.errc: t.Errorf("client error: %v", err) @@ -643,7 +644,7 @@ func TestClunk(t *testing.T) { for _, test := range tests { func() { ctx, cancel := context.WithCancel(context.Background()) - c, tmsgc, rmsgc := newClientForTest(ctx, 1024, "glenda") + c, tmsgc, w := newClientForTest(ctx, 1024, "glenda") defer cancel() var ( goterr error @@ -661,7 +662,7 @@ func TestClunk(t *testing.T) { test.name, test.tmsg, gottmsg) return } - rmsgc <- test.rmsg + lib9p.SendMsg(test.rmsg, w) select { case err := <-c.errc: t.Errorf("client error: %v", err) @@ -701,7 +702,7 @@ func TestRemove(t *testing.T) { for _, test := range tests { func() { ctx, cancel := context.WithCancel(context.Background()) - c, tmsgc, rmsgc := newClientForTest(ctx, 1024, "glenda") + c, tmsgc, w := newClientForTest(ctx, 1024, "glenda") defer cancel() var ( goterr error @@ -719,7 +720,7 @@ func TestRemove(t *testing.T) { test.name, test.tmsg, gottmsg) return } - rmsgc <- test.rmsg + lib9p.SendMsg(test.rmsg, w) select { case err := <-c.errc: t.Errorf("client error: %v", err) @@ -756,7 +757,7 @@ func TestStat(t *testing.T) { for _, test := range tests { func() { ctx, cancel := context.WithCancel(context.Background()) - c, tmsgc, rmsgc := newClientForTest(ctx, 1024, "glenda") + c, tmsgc, w := newClientForTest(ctx, 1024, "glenda") defer cancel() var ( gotstat *lib9p.Stat @@ -775,7 +776,7 @@ func TestStat(t *testing.T) { test.name, test.tmsg, gottmsg) return } - rmsgc <- test.rmsg + lib9p.SendMsg(test.rmsg, w) select { case err := <-c.errc: t.Errorf("client error: %v", err) @@ -819,7 +820,7 @@ func TestWstat(t *testing.T) { for _, test := range tests { func() { ctx, cancel := context.WithCancel(context.Background()) - c, tmsgc, rmsgc := newClientForTest(ctx, 1024, "glenda") + c, tmsgc, w := newClientForTest(ctx, 1024, "glenda") defer cancel() var ( goterr error @@ -837,7 +838,7 @@ func TestWstat(t *testing.T) { test.name, test.tmsg, gottmsg) return } - rmsgc <- test.rmsg + lib9p.SendMsg(test.rmsg, w) select { case err := <-c.errc: t.Errorf("client error: %v", err)