summaryrefslogtreecommitdiff
path: root/src/runtime/sigqueue_plan9.go
blob: 575d26afb4e78664587fd97fc9c24f31d7938620 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This file implements runtime support for signal handling.

package runtime

import _ "unsafe"

const qsize = 64

var sig struct {
	q     noteQueue
	inuse bool

	lock     mutex
	note     note
	sleeping bool
}

type noteData struct {
	s [_ERRMAX]byte
	n int // n bytes of s are valid
}

type noteQueue struct {
	lock mutex
	data [qsize]noteData
	ri   int
	wi   int
	full bool
}

// It is not allowed to allocate memory in the signal handler.
func (q *noteQueue) push(item *byte) bool {
	lock(&q.lock)
	if q.full {
		unlock(&q.lock)
		return false
	}
	s := gostringnocopy(item)
	copy(q.data[q.wi].s[:], s)
	q.data[q.wi].n = len(s)
	q.wi++
	if q.wi == qsize {
		q.wi = 0
	}
	if q.wi == q.ri {
		q.full = true
	}
	unlock(&q.lock)
	return true
}

func (q *noteQueue) pop() string {
	lock(&q.lock)
	q.full = false
	if q.ri == q.wi {
		unlock(&q.lock)
		return ""
	}
	note := &q.data[q.ri]
	item := string(note.s[:note.n])
	q.ri++
	if q.ri == qsize {
		q.ri = 0
	}
	unlock(&q.lock)
	return item
}

// Called from sighandler to send a signal back out of the signal handling thread.
// Reports whether the signal was sent. If not, the caller typically crashes the program.
func sendNote(s *byte) bool {
	if !sig.inuse {
		return false
	}

	// Add signal to outgoing queue.
	if !sig.q.push(s) {
		return false
	}

	lock(&sig.lock)
	if sig.sleeping {
		sig.sleeping = false
		notewakeup(&sig.note)
	}
	unlock(&sig.lock)

	return true
}

// Called to receive the next queued signal.
// Must only be called from a single goroutine at a time.
//go:linkname signal_recv os/signal.signal_recv
func signal_recv() string {
	for {
		note := sig.q.pop()
		if note != "" {
			return note
		}

		lock(&sig.lock)
		sig.sleeping = true
		noteclear(&sig.note)
		unlock(&sig.lock)
		notetsleepg(&sig.note, -1)
	}
}

// Must only be called from a single goroutine at a time.
//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
	}
}

// Must only be called from a single goroutine at a time.
//go:linkname signal_disable os/signal.signal_disable
func signal_disable(s uint32) {
}

// Must only be called from a single goroutine at a time.
//go:linkname signal_ignore os/signal.signal_ignore
func signal_ignore(s uint32) {
}