summaryrefslogtreecommitdiffhomepage
path: root/pkg/abi/linux/wait.go
blob: 7107291385495b052bb11d6990b6192afb8a0dad (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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Copyright 2019 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package linux

import (
	"fmt"
)

// Options for waitpid(2), wait4(2), and/or waitid(2), from
// include/uapi/linux/wait.h.
const (
	WNOHANG    = 0x00000001
	WUNTRACED  = 0x00000002
	WSTOPPED   = WUNTRACED
	WEXITED    = 0x00000004
	WCONTINUED = 0x00000008
	WNOWAIT    = 0x01000000
	WNOTHREAD  = 0x20000000
	WALL       = 0x40000000
	WCLONE     = 0x80000000
)

// ID types for waitid(2), from include/uapi/linux/wait.h.
const (
	P_ALL  = 0x0
	P_PID  = 0x1
	P_PGID = 0x2
)

// WaitStatus represents a thread status, as returned by the wait* family of
// syscalls.
type WaitStatus uint32

// WaitStatusExit returns a WaitStatus representing the given exit status.
func WaitStatusExit(status int32) WaitStatus {
	return WaitStatus(uint32(status) << 8)
}

// WaitStatusTerminationSignal returns a WaitStatus representing termination by
// the given signal.
func WaitStatusTerminationSignal(sig Signal) WaitStatus {
	return WaitStatus(uint32(sig))
}

// WaitStatusStopped returns a WaitStatus representing stoppage by the given
// signal or ptrace trap code.
func WaitStatusStopped(code uint32) WaitStatus {
	return WaitStatus(code<<8 | 0x7f)
}

// WaitStatusContinued returns a WaitStatus representing continuation by
// SIGCONT.
func WaitStatusContinued() WaitStatus {
	return WaitStatus(0xffff)
}

// WithCoreDump returns a copy of ws that indicates that a core dump was
// generated.
//
// Preconditions: ws.Signaled().
func (ws WaitStatus) WithCoreDump() WaitStatus {
	return ws | 0x80
}

// Exited returns true if ws represents an exit status, consistent with
// WIFEXITED.
func (ws WaitStatus) Exited() bool {
	return ws&0x7f == 0
}

// Signaled returns true if ws represents a termination by signal, consistent
// with WIFSIGNALED.
func (ws WaitStatus) Signaled() bool {
	// ws&0x7f != 0 (exited) and ws&0x7f != 0x7f (stopped or continued)
	return ((ws&0x7f)+1)>>1 != 0
}

// CoreDumped returns true if ws indicates that a core dump was produced,
// consistent with WCOREDUMP.
//
// Preconditions: ws.Signaled().
func (ws WaitStatus) CoreDumped() bool {
	return ws&0x80 != 0
}

// Stopped returns true if ws represents a stoppage, consistent with
// WIFSTOPPED.
func (ws WaitStatus) Stopped() bool {
	return ws&0xff == 0x7f
}

// Continued returns true if ws represents a continuation by SIGCONT,
// consistent with WIFCONTINUED.
func (ws WaitStatus) Continued() bool {
	return ws == 0xffff
}

// ExitStatus returns the lower 8 bits of the exit status represented by ws,
// consistent with WEXITSTATUS.
//
// Preconditions: ws.Exited().
func (ws WaitStatus) ExitStatus() uint32 {
	return uint32((ws & 0xff00) >> 8)
}

// TerminationSignal returns the termination signal represented by ws,
// consistent with WTERMSIG.
//
// Preconditions: ws.Signaled().
func (ws WaitStatus) TerminationSignal() Signal {
	return Signal(ws & 0x7f)
}

// StopSignal returns the stop signal represented by ws, consistent with
// WSTOPSIG.
//
// Preconditions: ws.Stopped().
func (ws WaitStatus) StopSignal() Signal {
	return Signal((ws & 0xff00) >> 8)
}

// PtraceEvent returns the PTRACE_EVENT_* field in ws.
//
// Preconditions: ws.Stopped().
func (ws WaitStatus) PtraceEvent() uint32 {
	return uint32(ws >> 16)
}

// String implements fmt.Stringer.String.
func (ws WaitStatus) String() string {
	switch {
	case ws.Exited():
		return fmt.Sprintf("exit status %d", ws.ExitStatus())
	case ws.Signaled():
		if ws.CoreDumped() {
			return fmt.Sprintf("killed by signal %d (core dumped)", ws.TerminationSignal())
		}
		return fmt.Sprintf("killed by signal %d", ws.TerminationSignal())
	case ws.Stopped():
		if ev := ws.PtraceEvent(); ev != 0 {
			return fmt.Sprintf("stopped by signal %d (PTRACE_EVENT %d)", ws.StopSignal(), ev)
		}
		return fmt.Sprintf("stopped by signal %d", ws.StopSignal())
	case ws.Continued():
		return "continued"
	default:
		return fmt.Sprintf("unknown status %#x", uint32(ws))
	}
}