Skip to content

Commit

Permalink
opt: improve the I/O in event-loop
Browse files Browse the repository at this point in the history
  • Loading branch information
panjf2000 committed Feb 2, 2021
1 parent 2aee5a9 commit c554f4e
Show file tree
Hide file tree
Showing 6 changed files with 37 additions and 53 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions eventloop_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
27 changes: 9 additions & 18 deletions loop_bsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
15 changes: 7 additions & 8 deletions loop_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
27 changes: 9 additions & 18 deletions reactor_bsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
15 changes: 7 additions & 8 deletions reactor_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
})
Expand Down

0 comments on commit c554f4e

Please sign in to comment.