@@ -407,7 +407,142 @@ pollDesc 初始化好之后,会当作 epoll event 的数据存储到 ev.data
407
407
408
408
TODO,conn 是什么时候赋值给 Conn 类型的?
409
409
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 流程
411
546
412
547
``` go
413
548
func (c *conn ) ok () bool { return c != nil && c.fd != nil }
@@ -554,7 +689,7 @@ func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
554
689
555
690
gopark 将当前 g 挂起,等待就绪事件到达之后再继续执行。
556
691
557
- #### Write 流程
692
+ ### Write 流程
558
693
559
694
``` go
560
695
// Write implements the Conn Write method.
@@ -635,7 +770,7 @@ func (pd *pollDesc) wait(mode int, isFile bool) error {
635
770
636
771
后面的流程就和 Read 完全一致了。
637
772
638
- #### 就续通知
773
+ ### 就续通知
639
774
640
775
``` go
641
776
// poll 已经就绪的网络连接
@@ -739,7 +874,7 @@ func netpollunblock(pd *pollDesc, mode int32, ioready bool) *g {
739
874
740
875
netpoll 这个函数是平台相关的,实现在对应的 netpoll_epoll、netpoll_kqueue 文件中。
741
876
742
- #### 读写 g 的挂起和恢复
877
+ ### 读写 g 的挂起和恢复
743
878
744
879
在上面读写流程,syscall.Read 或者 syscall.Write 返回 EAGAIN 时,会挂起当前正在进行这个读/写操作的 g,具体是调用 gopark,并执行 netpollblockcommit,并将 gpp 挂起,netpollblockcommit 比较简单:
745
880
0 commit comments