-
Notifications
You must be signed in to change notification settings - Fork 480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: feat: io_uring for netpoll I/O poller #197
Open
Jacob953
wants to merge
67
commits into
cloudwego:develop
Choose a base branch
from
Jacob953:feat/io_uring
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+2,801
−25
Open
Changes from all commits
Commits
Show all changes
67 commits
Select commit
Hold shift + click to select a range
d766619
feat: add variable parameters to manager.Run() for PollType of manage…
0227947
feat: re-design openPoll() to select one PollType
bb5ef53
feat: add IOURingPoll (WIP)
16074e4
feat: add sysMmap & sysMunmap
00ee563
fix: rename io_uring to uring
04cd494
fix: uniform variable r to u
a940bfa
feat: add const for mmap
a375d8c
feat: add setup, enter & register for system call
3e90d2b
feat: add setup options
8db732f
feat: add SQEntry & CQEvent
ea33f82
feat: add atomic operation for barrier
fda4b12
feat: add probe supported capability
7f9768b
feat: add advance usage for register
fdc0e5b
feat: add uring for low-level interface
4c5b712
feat: add submission operations
641d782
feat: add completion operations
8e81931
fix: restructure URingSQE & URingCQE
1057583
fix: wrap mmap & unmmap, recovery syscall.MAP_POPULATE
a02b287
faet: public getOp by Op
58d195d
fix: update sysRegister to SysRegister
4fab811
feat: public syscall
e3f4b83
feat: restructure uring methord
392c003
fix: remove sys_barrier.go
5ad8bd6
fix: Copyright 2022 CloudWeGo Authors
61f407b
fix: rollback poll_default_* & poll_manager
c82d419
feat: restructure URingCQE, Error & rename setData to setUserData
6e445f8
fix: cal size
2e064d6
feat: add sys_operation
18aac13
feat: const _size* & fix Sys*
546b5cd
fix: correct methods
4386f8c
fix: restructure submit*
28cc8eb
feat: add Queue & fix others
a4ffc46
feat: add test-coverage at 65.6% with bad TestTimeoutWait
3816272
fix: correct import
dbdf554
fix: add timeout check for WaitCQEs
f95b7f6
fix: simplify Syscall6 for SysEnter
b6334f4
feat: add acceptOp
72137f0
fix: rename OpCode to OpFlag
32a14c0
feat: add cat example
53df5fc
feat: add server example
f86c99a
Merge branch 'cloudwego:develop' into feat/io_uring
cdbc94f
fix: rename cq.kRingMsk to cq.kRingMask, add annotation
c1ec061
feat: update peekBatchCQE & peekCQE, and add getEvents
6a4d7e2
fix: rename cq.kRingMsk to cq.kRingMask
e9ff6a3
feat: add benckmark for uring & epoll
7c65c95
Merge branch 'feat/io_uring' of github.com:Jacob953/netpoll into feat…
46ca4cf
feat: add memory_barrier
83cc3e2
fix: TestTimeoutWait not supported
93dda0b
fix: update SMP_MEMORY_BARRIER
625c0c4
feat: implement netpoll poller register
0013936
fix: rm poll_io_uring.go for restructuring
302e5be
fix: rm SMP_SQRING.Store() at SysSetup
03248a3
fix: openPoll segmentation violation
5e0b446
fix: simplify
4d8abb9
feat: modify OpFlag
ac1a9d8
feat: add RegisterURingPoll
e1a8711
feat: update pollRegister
9dbdc9d
feat: update go version to 1.17 for unsafe.Add
d2b3966
feat: add register for event, rm opflag
5a6033f
feat: add PollAdd & PollRemove
4608460
feat: add uring poller
0737179
fix: rm fmt(for test)
ef05b54
feat: add URingEpollCtl
326225e
fix: restructure uringpoll
861cfa8
fix: check trig and exit first
dbd117a
fix: add PollAdd for listen
cfc5b9a
feat: restructure Control
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
module github.com/cloudwego/netpoll | ||
|
||
go 1.15 | ||
go 1.17 | ||
|
||
require github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 | ||
require ( | ||
github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7 | ||
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright 2022 CloudWeGo Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
//go:build !windows | ||
// +build !windows | ||
|
||
package netpoll | ||
|
||
// registerPoll is the func of openning Poller | ||
var pollRegister = openDefaultPoll | ||
|
||
// RegisterEpoll implement Epoll | ||
func RegisterEpoll() { | ||
pollRegister = openDefaultPoll | ||
} | ||
|
||
// RegisterURingPoll implement URing Poller | ||
func RegisterURingPoll() { | ||
pollRegister = openURingPoll | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
// Copyright 2022 CloudWeGo Authors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
//go:build !race | ||
// +build !race | ||
|
||
package netpoll | ||
|
||
import ( | ||
"log" | ||
"sync/atomic" | ||
"syscall" | ||
"unsafe" | ||
|
||
. "github.com/cloudwego/netpoll/uring" | ||
) | ||
|
||
func openURingPoll() Poll { | ||
poll := &uringPoll{} | ||
uring, err := IOURing(128) | ||
if err != nil { | ||
panic(err) | ||
} | ||
poll.uring = uring | ||
return poll | ||
} | ||
|
||
type uringPoll struct { | ||
size int | ||
caps int | ||
trigger uint32 | ||
|
||
uring *URing | ||
cqes []*URingCQE | ||
barriers []barrier | ||
hups []func(p Poll) error | ||
} | ||
|
||
// Wait implements Poll. | ||
func (p *uringPoll) Wait() error { | ||
// init | ||
var caps, n = barriercap, 0 | ||
p.reset(128, caps) | ||
// wait | ||
for { | ||
if n == p.size && p.size < 128*1024 { | ||
p.reset(p.size<<1, caps) | ||
} | ||
n = p.uring.PeekBatchCQE(p.cqes) | ||
if n == 0 { | ||
continue | ||
} | ||
p.uring.Advance(uint32(n)) | ||
if p.handler(p.cqes[:n]) { | ||
return nil | ||
} | ||
} | ||
} | ||
|
||
// Close implements Poll. | ||
func (p *uringPoll) Close() error { | ||
var userData uint64 | ||
*(**FDOperator)(unsafe.Pointer(&userData)) = &FDOperator{FD: p.uring.Fd(), state: -1} | ||
err := p.trig(userData) | ||
return err | ||
} | ||
|
||
// Trigger implements Poll. | ||
func (p *uringPoll) Trigger() error { | ||
if atomic.AddUint32(&p.trigger, 1) > 1 { | ||
return nil | ||
} | ||
var userData uint64 | ||
*(**FDOperator)(unsafe.Pointer(&userData)) = &FDOperator{FD: p.uring.Fd()} | ||
err := p.trig(userData) | ||
return err | ||
} | ||
|
||
// Control implements Poll. | ||
func (p *uringPoll) Control(operator *FDOperator, event PollEvent) (err error) { | ||
var pollOp Op | ||
var mask uint32 | ||
switch event { | ||
case PollReadable: | ||
operator.inuse() | ||
mask = syscall.EPOLLIN | syscall.EPOLLRDHUP | syscall.EPOLLERR | ||
pollOp = PollAdd(uintptr(operator.FD), mask) | ||
case PollModReadable: | ||
operator.inuse() | ||
mask = syscall.EPOLLIN | syscall.EPOLLRDHUP | syscall.EPOLLERR | ||
pollOp = PollAdd(uintptr(operator.FD), mask) | ||
case PollDetach: | ||
pollOp = PollRemove(uint64(uintptr(unsafe.Pointer(operator)))) | ||
case PollWritable: | ||
operator.inuse() | ||
mask = EPOLLET | syscall.EPOLLOUT | syscall.EPOLLRDHUP | syscall.EPOLLERR | ||
pollOp = PollAdd(uintptr(operator.FD), mask) | ||
case PollR2RW: | ||
mask = syscall.EPOLLIN | syscall.EPOLLOUT | syscall.EPOLLRDHUP | syscall.EPOLLERR | ||
pollOp = PollAdd(uintptr(operator.FD), mask) | ||
case PollRW2R: | ||
mask = syscall.EPOLLIN | syscall.EPOLLRDHUP | syscall.EPOLLERR | ||
pollOp = PollAdd(uintptr(operator.FD), mask) | ||
} | ||
|
||
var userData uint64 | ||
*(**FDOperator)(unsafe.Pointer(&userData)) = operator | ||
|
||
err = p.uring.Queue(pollOp, 0, userData) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
_, err = p.uring.Submit() | ||
return err | ||
} | ||
|
||
func (p *uringPoll) reset(size, caps int) { | ||
p.size, p.caps = size, caps | ||
p.cqes, p.barriers = make([]*URingCQE, size), make([]barrier, size) | ||
for i := range p.barriers { | ||
p.barriers[i].bs = make([][]byte, caps) | ||
p.barriers[i].ivs = make([]syscall.Iovec, caps) | ||
} | ||
} | ||
|
||
func (p *uringPoll) handler(cqes []*URingCQE) (closed bool) { | ||
for i := range cqes { | ||
var operator = *(**FDOperator)(unsafe.Pointer(&cqes[i].UserData)) | ||
// trigger or exit gracefully | ||
if operator.FD == p.uring.Fd() { | ||
// must clean trigger first | ||
atomic.StoreUint32(&p.trigger, 0) | ||
// if closed & exit | ||
if operator.state == -1 { | ||
p.uring.Close() | ||
return true | ||
} | ||
operator.done() | ||
continue | ||
} | ||
|
||
if !operator.do() { | ||
continue | ||
} | ||
|
||
var events = cqes[i].Res | ||
// check poll in | ||
if events&syscall.EPOLLIN != 0 { | ||
if operator.OnRead != nil { | ||
// for non-connection | ||
operator.OnRead(p) | ||
} else { | ||
// only for connection | ||
var bs = operator.Inputs(p.barriers[i].bs) | ||
if len(bs) > 0 { | ||
var n, err = readv(operator.FD, bs, p.barriers[i].ivs) | ||
operator.InputAck(n) | ||
if err != nil && err != syscall.EAGAIN && err != syscall.EINTR { | ||
log.Printf("readv(fd=%d) failed: %s", operator.FD, err.Error()) | ||
p.appendHup(operator) | ||
continue | ||
} | ||
} | ||
} | ||
} | ||
|
||
// check hup | ||
if events&(syscall.EPOLLHUP|syscall.EPOLLRDHUP) != 0 { | ||
p.appendHup(operator) | ||
continue | ||
} | ||
if events&syscall.EPOLLERR != 0 { | ||
// Under block-zerocopy, the kernel may give an error callback, which is not a real error, just an EAGAIN. | ||
// So here we need to check this error, if it is EAGAIN then do nothing, otherwise still mark as hup. | ||
if _, _, _, _, err := syscall.Recvmsg(operator.FD, nil, nil, syscall.MSG_ERRQUEUE); err != syscall.EAGAIN { | ||
p.appendHup(operator) | ||
} else { | ||
operator.done() | ||
} | ||
continue | ||
} | ||
|
||
// check poll out | ||
if events&syscall.EPOLLOUT != 0 { | ||
if operator.OnWrite != nil { | ||
// for non-connection | ||
operator.OnWrite(p) | ||
} else { | ||
// only for connection | ||
var bs, supportZeroCopy = operator.Outputs(p.barriers[i].bs) | ||
if len(bs) > 0 { | ||
// TODO: Let the upper layer pass in whether to use ZeroCopy. | ||
var n, err = sendmsg(operator.FD, bs, p.barriers[i].ivs, false && supportZeroCopy) | ||
operator.OutputAck(n) | ||
if err != nil && err != syscall.EAGAIN { | ||
log.Printf("sendmsg(fd=%d) failed: %s", operator.FD, err.Error()) | ||
p.appendHup(operator) | ||
continue | ||
} | ||
} | ||
} | ||
} | ||
operator.done() | ||
} | ||
// hup conns together to avoid blocking the poll. | ||
p.detaches() | ||
return false | ||
} | ||
|
||
func (p *uringPoll) trig(userData uint64) error { | ||
err := p.uring.Queue(Nop(), 0, userData) | ||
if err != nil { | ||
return err | ||
} | ||
_, err = p.uring.Submit() | ||
return err | ||
} | ||
|
||
func (p *uringPoll) appendHup(operator *FDOperator) { | ||
p.hups = append(p.hups, operator.OnHup) | ||
operator.Control(PollDetach) | ||
operator.done() | ||
} | ||
|
||
func (p *uringPoll) detaches() { | ||
if len(p.hups) == 0 { | ||
return | ||
} | ||
hups := p.hups | ||
p.hups = nil | ||
go func(onhups []func(p Poll) error) { | ||
for i := range onhups { | ||
if onhups[i] != nil { | ||
onhups[i](p) | ||
} | ||
} | ||
}(hups) | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
poll_xxx 这些先删掉吧,这里需要开发注册机制,不通过 type 区分