Skip to content

Commit d6a196d

Browse files
committed
add accept 流程
1 parent 695e7d8 commit d6a196d

File tree

1 file changed

+139
-4
lines changed

1 file changed

+139
-4
lines changed

netpoll.md

Lines changed: 139 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,142 @@ pollDesc 初始化好之后,会当作 epoll event 的数据存储到 ev.data
407407

408408
TODO,conn 是什么时候赋值给 Conn 类型的?
409409

410-
#### Read 流程
410+
### accept 流程
411+
412+
```go
413+
// Accept implements the Accept method in the Listener interface; it
414+
// waits for the next call and returns a generic Conn.
415+
func (l *TCPListener) Accept() (Conn, error) {
416+
if !l.ok() {
417+
return nil, syscall.EINVAL
418+
}
419+
c, err := l.accept()
420+
if err != nil {
421+
return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
422+
}
423+
return c, nil
424+
}
425+
```
426+
427+
```go
428+
func (ln *TCPListener) accept() (*TCPConn, error) {
429+
fd, err := ln.fd.accept()
430+
if err != nil {
431+
return nil, err
432+
}
433+
return newTCPConn(fd), nil
434+
}
435+
436+
```
437+
438+
```go
439+
func newTCPConn(fd *netFD) *TCPConn {
440+
c := &TCPConn{conn{fd}}
441+
setNoDelay(c.fd, true)
442+
return c
443+
}
444+
```
445+
446+
```go
447+
func (fd *netFD) accept() (netfd *netFD, err error) {
448+
d, rsa, errcall, err := fd.pfd.Accept()
449+
if err != nil {
450+
if errcall != "" {
451+
err = wrapSyscallError(errcall, err)
452+
}
453+
return nil, err
454+
}
455+
456+
if netfd, err = newFD(d, fd.family, fd.sotype, fd.net); err != nil {
457+
poll.CloseFunc(d)
458+
return nil, err
459+
}
460+
if err = netfd.init(); err != nil {
461+
fd.Close()
462+
return nil, err
463+
}
464+
lsa, _ := syscall.Getsockname(netfd.pfd.Sysfd)
465+
netfd.setAddr(netfd.addrFunc()(lsa), netfd.addrFunc()(rsa))
466+
return netfd, nil
467+
}
468+
```
469+
470+
```go
471+
// Accept wraps the accept network call.
472+
func (fd *FD) Accept() (int, syscall.Sockaddr, string, error) {
473+
if err := fd.readLock(); err != nil {
474+
return -1, nil, "", err
475+
}
476+
defer fd.readUnlock()
477+
478+
if err := fd.pd.prepareRead(fd.isFile); err != nil {
479+
return -1, nil, "", err
480+
}
481+
for {
482+
s, rsa, errcall, err := accept(fd.Sysfd)
483+
if err == nil {
484+
return s, rsa, "", err
485+
}
486+
switch err {
487+
case syscall.EAGAIN:
488+
if fd.pd.pollable() {
489+
if err = fd.pd.waitRead(fd.isFile); err == nil {
490+
continue
491+
}
492+
}
493+
case syscall.ECONNABORTED:
494+
// This means that a socket on the listen
495+
// queue was closed before we Accept()ed it;
496+
// it's a silly error, so try again.
497+
continue
498+
}
499+
return -1, nil, errcall, err
500+
}
501+
}
502+
```
503+
504+
```go
505+
// Wrapper around the accept system call that marks the returned file
506+
// descriptor as nonblocking and close-on-exec.
507+
func accept(s int) (int, syscall.Sockaddr, string, error) {
508+
ns, sa, err := Accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC)
509+
// On Linux the accept4 system call was introduced in 2.6.28
510+
// kernel and on FreeBSD it was introduced in 10 kernel. If we
511+
// get an ENOSYS error on both Linux and FreeBSD, or EINVAL
512+
// error on Linux, fall back to using accept.
513+
switch err {
514+
case nil:
515+
return ns, sa, "", nil
516+
default: // errors other than the ones listed
517+
return -1, sa, "accept4", err
518+
case syscall.ENOSYS: // syscall missing
519+
case syscall.EINVAL: // some Linux use this instead of ENOSYS
520+
case syscall.EACCES: // some Linux use this instead of ENOSYS
521+
case syscall.EFAULT: // some Linux use this instead of ENOSYS
522+
}
523+
524+
// See ../syscall/exec_unix.go for description of ForkLock.
525+
// It is probably okay to hold the lock across syscall.Accept
526+
// because we have put fd.sysfd into non-blocking mode.
527+
// However, a call to the File method will put it back into
528+
// blocking mode. We can't take that risk, so no use of ForkLock here.
529+
ns, sa, err = AcceptFunc(s)
530+
if err == nil {
531+
syscall.CloseOnExec(ns)
532+
}
533+
if err != nil {
534+
return -1, nil, "accept", err
535+
}
536+
if err = syscall.SetNonblock(ns, true); err != nil {
537+
CloseFunc(ns)
538+
return -1, nil, "setnonblock", err
539+
}
540+
return ns, sa, "", nil
541+
}
542+
543+
```
544+
545+
### Read 流程
411546

412547
```go
413548
func (c *conn) ok() bool { return c != nil && c.fd != nil }
@@ -554,7 +689,7 @@ func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
554689

555690
gopark 将当前 g 挂起,等待就绪事件到达之后再继续执行。
556691

557-
#### Write 流程
692+
### Write 流程
558693

559694
```go
560695
// Write implements the Conn Write method.
@@ -635,7 +770,7 @@ func (pd *pollDesc) wait(mode int, isFile bool) error {
635770

636771
后面的流程就和 Read 完全一致了。
637772

638-
#### 就续通知
773+
### 就续通知
639774

640775
```go
641776
// poll 已经就绪的网络连接
@@ -739,7 +874,7 @@ func netpollunblock(pd *pollDesc, mode int32, ioready bool) *g {
739874

740875
netpoll 这个函数是平台相关的,实现在对应的 netpoll_epoll、netpoll_kqueue 文件中。
741876

742-
#### 读写 g 的挂起和恢复
877+
### 读写 g 的挂起和恢复
743878

744879
在上面读写流程,syscall.Read 或者 syscall.Write 返回 EAGAIN 时,会挂起当前正在进行这个读/写操作的 g,具体是调用 gopark,并执行 netpollblockcommit,并将 gpp 挂起,netpollblockcommit 比较简单:
745880

0 commit comments

Comments
 (0)