Home | History | Annotate | Download | only in runtime
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // This file implements runtime support for signal handling.
      6 
      7 package runtime
      8 
      9 import _ "unsafe"
     10 
     11 const qsize = 64
     12 
     13 var sig struct {
     14 	q     noteQueue
     15 	inuse bool
     16 
     17 	lock     mutex
     18 	note     note
     19 	sleeping bool
     20 }
     21 
     22 type noteData struct {
     23 	s [_ERRMAX]byte
     24 	n int // n bytes of s are valid
     25 }
     26 
     27 type noteQueue struct {
     28 	lock mutex
     29 	data [qsize]noteData
     30 	ri   int
     31 	wi   int
     32 	full bool
     33 }
     34 
     35 // It is not allowed to allocate memory in the signal handler.
     36 func (q *noteQueue) push(item *byte) bool {
     37 	lock(&q.lock)
     38 	if q.full {
     39 		unlock(&q.lock)
     40 		return false
     41 	}
     42 	s := gostringnocopy(item)
     43 	copy(q.data[q.wi].s[:], s)
     44 	q.data[q.wi].n = len(s)
     45 	q.wi++
     46 	if q.wi == qsize {
     47 		q.wi = 0
     48 	}
     49 	if q.wi == q.ri {
     50 		q.full = true
     51 	}
     52 	unlock(&q.lock)
     53 	return true
     54 }
     55 
     56 func (q *noteQueue) pop() string {
     57 	lock(&q.lock)
     58 	q.full = false
     59 	if q.ri == q.wi {
     60 		unlock(&q.lock)
     61 		return ""
     62 	}
     63 	note := &q.data[q.ri]
     64 	item := string(note.s[:note.n])
     65 	q.ri++
     66 	if q.ri == qsize {
     67 		q.ri = 0
     68 	}
     69 	unlock(&q.lock)
     70 	return item
     71 }
     72 
     73 // Called from sighandler to send a signal back out of the signal handling thread.
     74 // Reports whether the signal was sent. If not, the caller typically crashes the program.
     75 func sendNote(s *byte) bool {
     76 	if !sig.inuse {
     77 		return false
     78 	}
     79 
     80 	// Add signal to outgoing queue.
     81 	if !sig.q.push(s) {
     82 		return false
     83 	}
     84 
     85 	lock(&sig.lock)
     86 	if sig.sleeping {
     87 		sig.sleeping = false
     88 		notewakeup(&sig.note)
     89 	}
     90 	unlock(&sig.lock)
     91 
     92 	return true
     93 }
     94 
     95 // Called to receive the next queued signal.
     96 // Must only be called from a single goroutine at a time.
     97 //go:linkname signal_recv os/signal.signal_recv
     98 func signal_recv() string {
     99 	for {
    100 		note := sig.q.pop()
    101 		if note != "" {
    102 			return note
    103 		}
    104 
    105 		lock(&sig.lock)
    106 		sig.sleeping = true
    107 		noteclear(&sig.note)
    108 		unlock(&sig.lock)
    109 		notetsleepg(&sig.note, -1)
    110 	}
    111 }
    112 
    113 // signalWaitUntilIdle waits until the signal delivery mechanism is idle.
    114 // This is used to ensure that we do not drop a signal notification due
    115 // to a race between disabling a signal and receiving a signal.
    116 // This assumes that signal delivery has already been disabled for
    117 // the signal(s) in question, and here we are just waiting to make sure
    118 // that all the signals have been delivered to the user channels
    119 // by the os/signal package.
    120 //go:linkname signalWaitUntilIdle os/signal.signalWaitUntilIdle
    121 func signalWaitUntilIdle() {
    122 	for {
    123 		lock(&sig.lock)
    124 		sleeping := sig.sleeping
    125 		unlock(&sig.lock)
    126 		if sleeping {
    127 			return
    128 		}
    129 		Gosched()
    130 	}
    131 }
    132 
    133 // Must only be called from a single goroutine at a time.
    134 //go:linkname signal_enable os/signal.signal_enable
    135 func signal_enable(s uint32) {
    136 	if !sig.inuse {
    137 		// The first call to signal_enable is for us
    138 		// to use for initialization. It does not pass
    139 		// signal information in m.
    140 		sig.inuse = true // enable reception of signals; cannot disable
    141 		noteclear(&sig.note)
    142 		return
    143 	}
    144 }
    145 
    146 // Must only be called from a single goroutine at a time.
    147 //go:linkname signal_disable os/signal.signal_disable
    148 func signal_disable(s uint32) {
    149 }
    150 
    151 // Must only be called from a single goroutine at a time.
    152 //go:linkname signal_ignore os/signal.signal_ignore
    153 func signal_ignore(s uint32) {
    154 }
    155