diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a1acb9f91..4dd406206 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: - name: Checkout code uses: actions/checkout@v2 - name: Run unit tests for utils - run: go test -v ./... + run: go test $(go list ./... | tail -n +2) - name: Run unit tests for server run: go test -v -coverprofile=coverage -covermode=count -timeout 60s - name: Upload code coverage report to Codecov diff --git a/eventloop_unix.go b/eventloop_unix.go index 81e5252ff..a0f74fce9 100644 --- a/eventloop_unix.go +++ b/eventloop_unix.go @@ -169,6 +169,10 @@ func (el *eventloop) loopRead(c *conn) error { } func (el *eventloop) loopWrite(c *conn) error { + if c.outboundBuffer.IsEmpty() { + return nil + } + el.eventHandler.PreWrite() head, tail := c.outboundBuffer.LazyReadAll() diff --git a/loop_bsd.go b/loop_bsd.go index 84ca1d653..e3da3f1b1 100644 --- a/loop_bsd.go +++ b/loop_bsd.go @@ -24,26 +24,17 @@ package gnet import "github.com/panjf2000/gnet/internal/netpoll" -func (el *eventloop) handleEvent(fd int, filter int16) error { +func (el *eventloop) handleEvent(fd int, filter int16) (err error) { if c, ok := el.connections[fd]; ok { - if filter == netpoll.EVFilterSock { - return el.loopCloseConn(c, nil) + switch filter { + case netpoll.EVFilterSock: + err = el.loopCloseConn(c, nil) + case netpoll.EVFilterWrite: + err = el.loopWrite(c) + case netpoll.EVFilterRead: + err = el.loopRead(c) } - - switch c.outboundBuffer.IsEmpty() { - // Don't change the ordering of processing EVFILT_WRITE | EVFILT_READ | EV_ERROR/EV_EOF unless you're 100% - // sure what you're doing! - // Re-ordering can easily introduce bugs and bad side-effects, as I found out painfully in the past. - case false: - if filter == netpoll.EVFilterWrite { - return el.loopWrite(c) - } - case true: - if filter == netpoll.EVFilterRead { - return el.loopRead(c) - } - } - return nil + return } return el.loopAccept(fd) } diff --git a/loop_linux.go b/loop_linux.go index 2d84bbc36..eeba2fc1a 100644 --- a/loop_linux.go +++ b/loop_linux.go @@ -24,19 +24,18 @@ import "github.com/panjf2000/gnet/internal/netpoll" func (el *eventloop) handleEvent(fd int, ev uint32) error { if c, ok := el.connections[fd]; ok { - switch c.outboundBuffer.IsEmpty() { // Don't change the ordering of processing EPOLLOUT | EPOLLRDHUP / EPOLLIN unless you're 100% // sure what you're doing! // Re-ordering can easily introduce bugs and bad side-effects, as I found out painfully in the past. - case false: - if ev&netpoll.OutEvents != 0 { - return el.loopWrite(c) - } - case true: - if ev&netpoll.InEvents != 0 { - return el.loopRead(c) + if ev&netpoll.OutEvents != 0 { + if err := el.loopWrite(c); err != nil { + return err } } + + if ev&netpoll.InEvents != 0 { + return el.loopRead(c) + } return nil } return el.loopAccept(fd) diff --git a/reactor_bsd.go b/reactor_bsd.go index 62f1853b6..c987af209 100644 --- a/reactor_bsd.go +++ b/reactor_bsd.go @@ -58,27 +58,18 @@ func (svr *server) activateSubReactor(el *eventloop, lockOSThread bool) { go el.loopTicker() } - err := el.poller.Polling(func(fd int, filter int16) error { + err := el.poller.Polling(func(fd int, filter int16) (err error) { if c, ack := el.connections[fd]; ack { - if filter == netpoll.EVFilterSock { - return el.loopCloseConn(c, nil) - } - - switch c.outboundBuffer.IsEmpty() { - // Don't change the ordering of processing EVFILT_WRITE | EVFILT_READ | EV_ERROR/EV_EOF unless you're 100% - // sure what you're doing! - // Re-ordering can easily introduce bugs and bad side-effects, as I found out painfully in the past. - case false: - if filter == netpoll.EVFilterWrite { - return el.loopWrite(c) - } - case true: - if filter == netpoll.EVFilterRead { - return el.loopRead(c) - } + switch filter { + case netpoll.EVFilterSock: + err = el.loopCloseConn(c, nil) + case netpoll.EVFilterWrite: + err = el.loopWrite(c) + case netpoll.EVFilterRead: + err = el.loopRead(c) } } - return nil + return }) svr.logger.Infof("Event-loop(%d) is exiting normally on the signal error: %v", el.idx, err) } diff --git a/reactor_linux.go b/reactor_linux.go index 5c1a85ab0..f7fa5fa28 100644 --- a/reactor_linux.go +++ b/reactor_linux.go @@ -58,19 +58,18 @@ func (svr *server) activateSubReactor(el *eventloop, lockOSThread bool) { err := el.poller.Polling(func(fd int, ev uint32) error { if c, ack := el.connections[fd]; ack { - switch c.outboundBuffer.IsEmpty() { // Don't change the ordering of processing EPOLLOUT | EPOLLRDHUP / EPOLLIN unless you're 100% // sure what you're doing! // Re-ordering can easily introduce bugs and bad side-effects, as I found out painfully in the past. - case false: - if ev&netpoll.OutEvents != 0 { - return el.loopWrite(c) - } - case true: - if ev&netpoll.InEvents != 0 { - return el.loopRead(c) + if ev&netpoll.OutEvents != 0 { + if err := el.loopWrite(c); err != nil { + return err } } + + if ev&netpoll.InEvents != 0 { + return el.loopRead(c) + } } return nil })