zoukankan      html  css  js  c++  java
  • defer

    defer

    定义

    type _defer struct {
        siz     int32 
        started bool
        sp      uintptr // sp at time of defer
        pc      uintptr
        fn      *funcval
        _panic  *_panic // panic that is running defer
        link    *_defer
    }
    

    相关字段解释:

    • sp 指向了栈指针
    • pc 指向了调用方的程序计数器
    • fn是向 defer 关键字中传入的函数
    • _panic是导致运行defer的panic
    • _ link是defer的链表,指向下一个defer结构

    defer实现

    func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
      sp := getcallersp()
      argp := uintptr(unsafe.Pointer(&fn)) + unsafe.Sizeof(fn)
      callerpc := getcallerpc()
    
      d := newdefer(siz)
      if d._panic != nil {
              throw("deferproc: d.panic != nil after newdefer")
      }
      d.fn = fn
      d.pc = callerpc
      d.sp = sp
      switch siz {
      case 0:
              // Do nothing.
      case sys.PtrSize:
              *(*uintptr)(deferArgs(d)) = *(*uintptr)(unsafe.Pointer(argp))
      default:
              memmove(deferArgs(d), unsafe.Pointer(argp), uintptr(siz))
      }
      return0()
    }
    
    func newdefer(siz int32) *_defer {
        var d *_defer
        sc := deferclass(uintptr(siz))
        gp := getg()
        if sc < uintptr(len(p{}.deferpool)) {
                pp := gp.m.p.ptr()
                if len(pp.deferpool[sc]) == 0 && sched.deferpool[sc] != nil {
                        // Take the slow path on the system stack so
                        // we don't grow newdefer's stack.
                        systemstack(func() {
                                lock(&sched.deferlock)
                                for len(pp.deferpool[sc]) < cap(pp.deferpool[sc])/2 && sched.deferpool[sc] != nil {
                                        d := sched.deferpool[sc]
                                        sched.deferpool[sc] = d.link
                                        d.link = nil
                                        pp.deferpool[sc] = append(pp.deferpool[sc], d)
                                }
                                unlock(&sched.deferlock)
                        })
                }
                if n := len(pp.deferpool[sc]); n > 0 {
                        d = pp.deferpool[sc][n-1]
                        pp.deferpool[sc][n-1] = nil
                        pp.deferpool[sc] = pp.deferpool[sc][:n-1]
                }
        }
        if d == nil {
                // Allocate new defer+args.
                systemstack(func() {
                        total := roundupsize(totaldefersize(uintptr(siz)))
                        d = (*_defer)(mallocgc(total, deferType, true))
                })
                if debugCachedWork {
                        // Duplicate the tail below so if there's a
                        // crash in checkPut we can tell if d was just
                        // allocated or came from the pool.
                        d.siz = siz
                        d.link = gp._defer
                        gp._defer = d
                        return d
                }
        }
        d.siz = siz
        d.link = gp._defer
        gp._defer = d //用链表连接当前g的所有defer,头插法,所以defer调用的顺序是先入后出的
        return d
    }
    
    • 每遇到一个defer关键字,defer函数都会被转换成runtime.deferproc

    • deferproc通过newdefer创建一个延迟函数,并将这个新建的延迟函数挂在当前goroutine的_defer的链表上

    • newdefer会先从sched和当前p的deferpool取出一个_defer结构体,如果deferpool没有_defer,则初始化一个新的_defer

    • _defer是关联到当前的G,所以defer只对当前G有效。

    • deferreturn从当前G取出_defer链表执行,每个_defer调用freedefer释放_defer结构体,并将该_defer结构体放入当前P的deferpool中。

    参考

  • 相关阅读:
    深度学习之 TensorFlow(一):基础库包的安装
    爬取网易云音乐评论并使用词云展示
    MySQL学习笔记(一):查询
    【linux】查看linux系统版本信息(Oracle Linux、Centos Linux、Redhat Linux、Debian、Ubuntu)
    【php】PHP中Session ID的实现原理
    VMware安装VMwareTolls
    退耦、旁路电容
    SPI笔记
    旧板与IO板之间的连接
    S3C2440启动方式
  • 原文地址:https://www.cnblogs.com/weiweng/p/13282735.html
Copyright © 2011-2022 走看看