Skip to content

Latest commit

 

History

History
177 lines (148 loc) · 3.36 KB

File metadata and controls

177 lines (148 loc) · 3.36 KB

os/signal.*

[TOC]

调度器: 信号处理中, 我们已经看到了用户注册的信号会被 sigsend 进行发送,这就是我们使用 os/signal 包的核心。

在使用 os/signal 后,会调用 signal.init 函数,注册一个用户端的信号处理循环:

func init() {
	signal_enable(0) // first call - initialize
	go loop()
}

func loop() {
	for {
		process(syscall.Signal(signal_recv()))
	}
}

这个 signal_enablesignal_recv 用于激活运行时的信号队列,并从中接受信号:

// 启用运行时信号队列
//go:linkname signal_enable os/signal.signal_enable
func signal_enable(s uint32) {
	if !sig.inuse {
		// The first call to signal_enable is for us
		// to use for initialization. It does not pass
		// signal information in m.
		sig.inuse = true // enable reception of signals; cannot disable
		noteclear(&sig.note)
		return
	}

	if s >= uint32(len(sig.wanted)*32) {
		return
	}

	w := sig.wanted[s/32]
	w |= 1 << (s & 31)
	atomic.Store(&sig.wanted[s/32], w)

	i := sig.ignored[s/32]
	i &^= 1 << (s & 31)
	atomic.Store(&sig.ignored[s/32], i)

	sigenable(s)
}
// 从信号队列中接受信号
//go:linkname signal_recv os/signal.signal_recv
func signal_recv() uint32 {
	for {
		// Serve any signals from local copy.
		for i := uint32(0); i < _NSIG; i++ {
			if sig.recv[i/32]&(1<<(i&31)) != 0 {
				sig.recv[i/32] &^= 1 << (i & 31)
				return i
			}
		}

		// Wait for updates to be available from signal sender.
	Receive:
		for {
			switch atomic.Load(&sig.state) {
			default:
				throw("signal_recv: inconsistent state")
			case sigIdle:
				if atomic.Cas(&sig.state, sigIdle, sigReceiving) {
					notetsleepg(&sig.note, -1)
					noteclear(&sig.note)
					break Receive
				}
			case sigSending:
				if atomic.Cas(&sig.state, sigSending, sigIdle) {
					break Receive
				}
			}
		}

		// Incorporate updates from sender into local copy.
		for i := range sig.mask {
			sig.recv[i] = atomic.Xchg(&sig.mask[i], 0)
		}
	}
}

当接受到信号后,信号 sig 会被发送到用户在 Ignore/Notify/Stop 上所注册的 channel 上:

func process(sig os.Signal) {
	n := signum(sig)
	if n < 0 {
		return
	}

	handlers.Lock()
	defer handlers.Unlock()

	for c, h := range handlers.m {
		if h.want(n) {
			// 发送
			select {
			case c <- sig:
			default:
			}
		}
	}

	(...) // Stop 的处理
}

例如 signal.Notify,将信号 channel 注册到 handler 全局变量中:

var handlers struct {
	sync.Mutex
	m map[chan<- os.Signal]*handler
	ref [numSig]int64
	stopping []stopping
}
func Notify(c chan<- os.Signal, sig ...os.Signal) {
	if c == nil {
		panic("os/signal: Notify using nil channel")
	}

	handlers.Lock()
	defer handlers.Unlock()

	h := handlers.m[c]
	if h == nil {
		if handlers.m == nil {
			handlers.m = make(map[chan<- os.Signal]*handler)
		}
		h = new(handler)
		handlers.m[c] = h // 保存到 handler 中
	}

	add := func(n int) {
		if n < 0 {
			return
		}
		if !h.want(n) {
			h.set(n)
			if handlers.ref[n] == 0 {
				enableSignal(n)
			}
			handlers.ref[n]++
		}
	}

	if len(sig) == 0 {
		for n := 0; n < numSig; n++ {
			add(n)
		}
	} else {
		for _, s := range sig {
			add(signum(s))
		}
	}
}

许可

Go under the hood | CC-BY-NC-ND 4.0 & MIT © changkun