Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/base/src/sys/linux/signal.rs
5394 views
1
// Copyright 2017 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use std::cmp::Ordering;
6
use std::convert::TryFrom;
7
use std::io;
8
use std::mem;
9
use std::os::unix::thread::JoinHandleExt;
10
use std::ptr::null;
11
use std::ptr::null_mut;
12
use std::result;
13
use std::thread::JoinHandle;
14
use std::time::Duration;
15
16
use libc::c_int;
17
use libc::pthread_kill;
18
use libc::pthread_sigmask;
19
use libc::pthread_t;
20
use libc::sigaction;
21
use libc::sigaddset;
22
use libc::sigemptyset;
23
use libc::siginfo_t;
24
use libc::sigismember;
25
use libc::sigpending;
26
use libc::sigset_t;
27
use libc::sigtimedwait;
28
use libc::sigwait;
29
use libc::timespec;
30
use libc::EAGAIN;
31
use libc::EINTR;
32
use libc::EINVAL;
33
use libc::SA_RESTART;
34
use libc::SIG_BLOCK;
35
use libc::SIG_DFL;
36
use libc::SIG_UNBLOCK;
37
use remain::sorted;
38
use thiserror::Error;
39
40
use super::errno_result;
41
use super::Error as ErrnoError;
42
use super::Pid;
43
use super::Result;
44
use crate::handle_eintr_errno;
45
use crate::handle_eintr_rc;
46
use crate::unix::duration_to_timespec;
47
48
#[sorted]
49
#[derive(Error, Debug)]
50
pub enum Error {
51
/// The signal could not be blocked.
52
#[error("signal could not be blocked: {0}")]
53
BlockSignal(ErrnoError),
54
/// Failed to check if given signal is in the set of pending signals.
55
#[error("failed to check whether given signal is in the pending set: {0}")]
56
ClearCheckPending(ErrnoError),
57
/// Failed to get pending signals.
58
#[error("failed to get pending signals: {0}")]
59
ClearGetPending(ErrnoError),
60
/// Failed to wait for given signal.
61
#[error("failed to wait for given signal: {0}")]
62
ClearWaitPending(ErrnoError),
63
/// Failed to check if the requested signal is in the blocked set already.
64
#[error("failed to check whether requested signal is in the blocked set: {0}")]
65
CompareBlockedSignals(ErrnoError),
66
/// Couldn't create a sigset.
67
#[error("couldn't create a sigset: {0}")]
68
CreateSigset(ErrnoError),
69
/// Failed to get session id.
70
#[error("failed to get session id: {0}")]
71
GetSid(ErrnoError),
72
/// Failed to send signal to pid.
73
#[error("failed to send signal: {0}")]
74
Kill(ErrnoError),
75
/// The signal mask could not be retrieved.
76
#[error("failed to retrieve signal mask: {}", io::Error::from_raw_os_error(*.0))]
77
RetrieveSignalMask(i32),
78
/// Converted signum greater than SIGRTMAX.
79
#[error("got RT signal greater than max: {0:?}")]
80
RtSignumGreaterThanMax(Signal),
81
/// The wrapped signal has already been blocked.
82
#[error("signal {0} already blocked")]
83
SignalAlreadyBlocked(c_int),
84
/// Timeout reached.
85
#[error("timeout reached.")]
86
TimedOut,
87
/// The signal could not be unblocked.
88
#[error("signal could not be unblocked: {0}")]
89
UnblockSignal(ErrnoError),
90
/// Failed to convert signum to Signal.
91
#[error("unrecoginized signal number: {0}")]
92
UnrecognizedSignum(i32),
93
/// Failed to wait for signal.
94
#[error("failed to wait for signal: {0}")]
95
WaitForSignal(ErrnoError),
96
/// Failed to wait for pid.
97
#[error("failed to wait for process: {0}")]
98
WaitPid(ErrnoError),
99
}
100
101
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
102
#[repr(i32)]
103
pub enum Signal {
104
Abort = libc::SIGABRT,
105
Alarm = libc::SIGALRM,
106
Bus = libc::SIGBUS,
107
Child = libc::SIGCHLD,
108
Continue = libc::SIGCONT,
109
ExceededFileSize = libc::SIGXFSZ,
110
FloatingPointException = libc::SIGFPE,
111
HangUp = libc::SIGHUP,
112
IllegalInstruction = libc::SIGILL,
113
Interrupt = libc::SIGINT,
114
Io = libc::SIGIO,
115
Kill = libc::SIGKILL,
116
Pipe = libc::SIGPIPE,
117
Power = libc::SIGPWR,
118
Profile = libc::SIGPROF,
119
Quit = libc::SIGQUIT,
120
SegmentationViolation = libc::SIGSEGV,
121
StackFault = libc::SIGSTKFLT,
122
Stop = libc::SIGSTOP,
123
Sys = libc::SIGSYS,
124
Trap = libc::SIGTRAP,
125
Terminate = libc::SIGTERM,
126
TtyIn = libc::SIGTTIN,
127
TtyOut = libc::SIGTTOU,
128
TtyStop = libc::SIGTSTP,
129
Urgent = libc::SIGURG,
130
User1 = libc::SIGUSR1,
131
User2 = libc::SIGUSR2,
132
VtAlarm = libc::SIGVTALRM,
133
Winch = libc::SIGWINCH,
134
Xcpu = libc::SIGXCPU,
135
// Rt signal numbers are be adjusted in the conversion to integer.
136
Rt0 = libc::SIGSYS + 1,
137
Rt1,
138
Rt2,
139
Rt3,
140
Rt4,
141
Rt5,
142
Rt6,
143
Rt7,
144
// Only 8 are guaranteed by POSIX, Linux has 32, but only 29 or 30 are usable.
145
Rt8,
146
Rt9,
147
Rt10,
148
Rt11,
149
Rt12,
150
Rt13,
151
Rt14,
152
Rt15,
153
Rt16,
154
Rt17,
155
Rt18,
156
Rt19,
157
Rt20,
158
Rt21,
159
Rt22,
160
Rt23,
161
Rt24,
162
Rt25,
163
Rt26,
164
Rt27,
165
Rt28,
166
Rt29,
167
Rt30,
168
Rt31,
169
}
170
171
impl std::fmt::Display for Signal {
172
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
173
let n = i32::from(*self);
174
// SAFETY: Trivially safe.
175
let ptr = unsafe { libc::strsignal(n) };
176
if ptr.is_null() {
177
f.write_str("[null]")
178
} else {
179
// SAFETY: `ptr` is a valid non-null c string returned by `strsignal`. It is only valid
180
// until the next call to `strsignal`, so we immediately make a copy. Technically
181
// `strsignal` is documented not threadsafe because the string becomes invalid when the
182
// locale changes in some implementations, but there doesn't seem to be a standard
183
// alternative.
184
let s = unsafe { std::ffi::CStr::from_ptr(ptr) }
185
.to_str()
186
.unwrap()
187
.to_string();
188
f.write_str(&s)
189
}
190
}
191
}
192
193
impl From<Signal> for c_int {
194
fn from(signal: Signal) -> c_int {
195
let num = signal as libc::c_int;
196
if num >= Signal::Rt0 as libc::c_int {
197
return num - (Signal::Rt0 as libc::c_int) + SIGRTMIN();
198
}
199
num
200
}
201
}
202
203
impl TryFrom<c_int> for Signal {
204
type Error = Error;
205
206
fn try_from(value: c_int) -> result::Result<Self, Self::Error> {
207
use Signal::*;
208
209
Ok(match value {
210
libc::SIGABRT => Abort,
211
libc::SIGALRM => Alarm,
212
libc::SIGBUS => Bus,
213
libc::SIGCHLD => Child,
214
libc::SIGCONT => Continue,
215
libc::SIGXFSZ => ExceededFileSize,
216
libc::SIGFPE => FloatingPointException,
217
libc::SIGHUP => HangUp,
218
libc::SIGILL => IllegalInstruction,
219
libc::SIGINT => Interrupt,
220
libc::SIGIO => Io,
221
libc::SIGKILL => Kill,
222
libc::SIGPIPE => Pipe,
223
libc::SIGPWR => Power,
224
libc::SIGPROF => Profile,
225
libc::SIGQUIT => Quit,
226
libc::SIGSEGV => SegmentationViolation,
227
libc::SIGSTKFLT => StackFault,
228
libc::SIGSTOP => Stop,
229
libc::SIGSYS => Sys,
230
libc::SIGTRAP => Trap,
231
libc::SIGTERM => Terminate,
232
libc::SIGTTIN => TtyIn,
233
libc::SIGTTOU => TtyOut,
234
libc::SIGTSTP => TtyStop,
235
libc::SIGURG => Urgent,
236
libc::SIGUSR1 => User1,
237
libc::SIGUSR2 => User2,
238
libc::SIGVTALRM => VtAlarm,
239
libc::SIGWINCH => Winch,
240
libc::SIGXCPU => Xcpu,
241
_ => {
242
if value < SIGRTMIN() {
243
return Err(Error::UnrecognizedSignum(value));
244
}
245
let signal = match value - SIGRTMIN() {
246
0 => Rt0,
247
1 => Rt1,
248
2 => Rt2,
249
3 => Rt3,
250
4 => Rt4,
251
5 => Rt5,
252
6 => Rt6,
253
7 => Rt7,
254
8 => Rt8,
255
9 => Rt9,
256
10 => Rt10,
257
11 => Rt11,
258
12 => Rt12,
259
13 => Rt13,
260
14 => Rt14,
261
15 => Rt15,
262
16 => Rt16,
263
17 => Rt17,
264
18 => Rt18,
265
19 => Rt19,
266
20 => Rt20,
267
21 => Rt21,
268
22 => Rt22,
269
23 => Rt23,
270
24 => Rt24,
271
25 => Rt25,
272
26 => Rt26,
273
27 => Rt27,
274
28 => Rt28,
275
29 => Rt29,
276
30 => Rt30,
277
31 => Rt31,
278
_ => {
279
return Err(Error::UnrecognizedSignum(value));
280
}
281
};
282
if value > SIGRTMAX() {
283
return Err(Error::RtSignumGreaterThanMax(signal));
284
}
285
signal
286
}
287
})
288
}
289
}
290
291
pub type SignalResult<T> = result::Result<T, Error>;
292
293
#[link(name = "c")]
294
extern "C" {
295
fn __libc_current_sigrtmin() -> c_int;
296
fn __libc_current_sigrtmax() -> c_int;
297
}
298
299
/// Returns the minimum (inclusive) real-time signal number.
300
#[allow(non_snake_case)]
301
pub fn SIGRTMIN() -> c_int {
302
// SAFETY: trivially safe
303
unsafe { __libc_current_sigrtmin() }
304
}
305
306
/// Returns the maximum (inclusive) real-time signal number.
307
#[allow(non_snake_case)]
308
pub fn SIGRTMAX() -> c_int {
309
// SAFETY: trivially safe
310
unsafe { __libc_current_sigrtmax() }
311
}
312
313
fn valid_rt_signal_num(num: c_int) -> bool {
314
num >= SIGRTMIN() && num <= SIGRTMAX()
315
}
316
317
/// Registers `handler` as the signal handler of signum `num`.
318
///
319
/// # Safety
320
///
321
/// This is considered unsafe because the given handler will be called asynchronously, interrupting
322
/// whatever the thread was doing and therefore must only do async-signal-safe operations.
323
pub unsafe fn register_signal_handler(num: c_int, handler: extern "C" fn(c_int)) -> Result<()> {
324
let mut sigact: sigaction = mem::zeroed();
325
sigact.sa_flags = SA_RESTART;
326
sigact.sa_sigaction = handler as *const () as usize;
327
328
let ret = sigaction(num, &sigact, null_mut());
329
if ret < 0 {
330
return errno_result();
331
}
332
333
Ok(())
334
}
335
336
/// Resets the signal handler of signum `num` back to the default.
337
pub fn clear_signal_handler(num: c_int) -> Result<()> {
338
// SAFETY:
339
// Safe because sigaction is owned and expected to be initialized ot zeros.
340
let mut sigact: sigaction = unsafe { mem::zeroed() };
341
sigact.sa_flags = SA_RESTART;
342
sigact.sa_sigaction = SIG_DFL;
343
344
// SAFETY:
345
// Safe because sigact is owned, and this is restoring the default signal handler.
346
let ret = unsafe { sigaction(num, &sigact, null_mut()) };
347
if ret < 0 {
348
return errno_result();
349
}
350
351
Ok(())
352
}
353
354
/// Registers `handler` as the signal handler for the real-time signal with signum `num`.
355
///
356
/// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
357
///
358
/// # Safety
359
///
360
/// This is considered unsafe because the given handler will be called asynchronously, interrupting
361
/// whatever the thread was doing and therefore must only do async-signal-safe operations.
362
pub unsafe fn register_rt_signal_handler(num: c_int, handler: extern "C" fn(c_int)) -> Result<()> {
363
if !valid_rt_signal_num(num) {
364
return Err(ErrnoError::new(EINVAL));
365
}
366
367
register_signal_handler(num, handler)
368
}
369
370
/// Creates `sigset` from an array of signal numbers.
371
///
372
/// This is a helper function used when we want to manipulate signals.
373
pub fn create_sigset(signals: &[c_int]) -> Result<sigset_t> {
374
// SAFETY:
375
// sigset will actually be initialized by sigemptyset below.
376
let mut sigset: sigset_t = unsafe { mem::zeroed() };
377
378
// SAFETY:
379
// Safe - return value is checked.
380
let ret = unsafe { sigemptyset(&mut sigset) };
381
if ret < 0 {
382
return errno_result();
383
}
384
385
for signal in signals {
386
// SAFETY:
387
// Safe - return value is checked.
388
let ret = unsafe { sigaddset(&mut sigset, *signal) };
389
if ret < 0 {
390
return errno_result();
391
}
392
}
393
394
Ok(sigset)
395
}
396
397
/// Wait for signal before continuing. The signal number of the consumed signal is returned on
398
/// success. EAGAIN means the timeout was reached.
399
pub fn wait_for_signal(signals: &[c_int], timeout: Option<Duration>) -> Result<c_int> {
400
let sigset = create_sigset(signals)?;
401
402
match timeout {
403
Some(timeout) => {
404
let ts = duration_to_timespec(timeout);
405
// SAFETY:
406
// Safe - return value is checked.
407
let ret = handle_eintr_errno!(unsafe { sigtimedwait(&sigset, null_mut(), &ts) });
408
if ret < 0 {
409
errno_result()
410
} else {
411
Ok(ret)
412
}
413
}
414
None => {
415
let mut ret: c_int = 0;
416
// SAFETY: Safe because args are valid and the return value is checked.
417
let err = handle_eintr_rc!(unsafe { sigwait(&sigset, &mut ret as *mut c_int) });
418
if err != 0 {
419
Err(ErrnoError::new(err))
420
} else {
421
Ok(ret)
422
}
423
}
424
}
425
}
426
427
/// Retrieves the signal mask of the current thread as a vector of c_ints.
428
pub fn get_blocked_signals() -> SignalResult<Vec<c_int>> {
429
let mut mask = Vec::new();
430
431
// SAFETY:
432
// Safe - return values are checked.
433
unsafe {
434
let mut old_sigset: sigset_t = mem::zeroed();
435
let ret = pthread_sigmask(SIG_BLOCK, null(), &mut old_sigset as *mut sigset_t);
436
if ret < 0 {
437
return Err(Error::RetrieveSignalMask(ret));
438
}
439
440
for num in 0..=SIGRTMAX() {
441
if sigismember(&old_sigset, num) > 0 {
442
mask.push(num);
443
}
444
}
445
}
446
447
Ok(mask)
448
}
449
450
/// Masks given signal.
451
///
452
/// If signal is already blocked the call will fail with Error::SignalAlreadyBlocked
453
/// result.
454
pub fn block_signal(num: c_int) -> SignalResult<()> {
455
let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
456
457
// SAFETY:
458
// Safe - return values are checked.
459
unsafe {
460
let mut old_sigset: sigset_t = mem::zeroed();
461
let ret = pthread_sigmask(SIG_BLOCK, &sigset, &mut old_sigset as *mut sigset_t);
462
if ret < 0 {
463
return Err(Error::BlockSignal(ErrnoError::last()));
464
}
465
let ret = sigismember(&old_sigset, num);
466
match ret.cmp(&0) {
467
Ordering::Less => {
468
return Err(Error::CompareBlockedSignals(ErrnoError::last()));
469
}
470
Ordering::Greater => {
471
return Err(Error::SignalAlreadyBlocked(num));
472
}
473
_ => (),
474
};
475
}
476
Ok(())
477
}
478
479
/// Unmasks given signal.
480
pub fn unblock_signal(num: c_int) -> SignalResult<()> {
481
let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
482
483
// SAFETY:
484
// Safe - return value is checked.
485
let ret = unsafe { pthread_sigmask(SIG_UNBLOCK, &sigset, null_mut()) };
486
if ret < 0 {
487
return Err(Error::UnblockSignal(ErrnoError::last()));
488
}
489
Ok(())
490
}
491
492
/// Clears pending signal.
493
pub fn clear_signal(num: c_int) -> SignalResult<()> {
494
let sigset = create_sigset(&[num]).map_err(Error::CreateSigset)?;
495
496
while {
497
// SAFETY:
498
// This is safe as we are rigorously checking return values
499
// of libc calls.
500
unsafe {
501
let mut siginfo: siginfo_t = mem::zeroed();
502
let ts = timespec {
503
tv_sec: 0,
504
tv_nsec: 0,
505
};
506
// Attempt to consume one instance of pending signal. If signal
507
// is not pending, the call will fail with EAGAIN or EINTR.
508
let ret = sigtimedwait(&sigset, &mut siginfo, &ts);
509
if ret < 0 {
510
let e = ErrnoError::last();
511
match e.errno() {
512
EAGAIN | EINTR => {}
513
_ => {
514
return Err(Error::ClearWaitPending(ErrnoError::last()));
515
}
516
}
517
}
518
519
// This sigset will be actually filled with `sigpending` call.
520
let mut chkset: sigset_t = mem::zeroed();
521
// See if more instances of the signal are pending.
522
let ret = sigpending(&mut chkset);
523
if ret < 0 {
524
return Err(Error::ClearGetPending(ErrnoError::last()));
525
}
526
527
let ret = sigismember(&chkset, num);
528
if ret < 0 {
529
return Err(Error::ClearCheckPending(ErrnoError::last()));
530
}
531
532
// This is do-while loop condition.
533
ret != 0
534
}
535
} {}
536
537
Ok(())
538
}
539
540
/// # Safety
541
/// This is marked unsafe because it allows signals to be sent to arbitrary PIDs. Sending some
542
/// signals may lead to undefined behavior. Also, the return codes of the child processes need to be
543
/// reaped to avoid leaking zombie processes.
544
pub unsafe fn kill(pid: Pid, signum: c_int) -> Result<()> {
545
let ret = libc::kill(pid, signum);
546
547
if ret != 0 {
548
errno_result()
549
} else {
550
Ok(())
551
}
552
}
553
554
/// Trait for threads that can be signalled via `pthread_kill`.
555
///
556
/// Note that this is only useful for signals between SIGRTMIN and SIGRTMAX because these are
557
/// guaranteed to not be used by the C runtime.
558
///
559
/// # Safety
560
/// This is marked unsafe because the implementation of this trait must guarantee that the returned
561
/// pthread_t is valid and has a lifetime at least that of the trait object.
562
pub unsafe trait Killable {
563
fn pthread_handle(&self) -> pthread_t;
564
565
/// Sends the signal `num` to this killable thread.
566
///
567
/// The value of `num` must be within [`SIGRTMIN`, `SIGRTMAX`] range.
568
fn kill(&self, num: c_int) -> Result<()> {
569
if !valid_rt_signal_num(num) {
570
return Err(ErrnoError::new(EINVAL));
571
}
572
573
// SAFETY:
574
// Safe because we ensure we are using a valid pthread handle, a valid signal number, and
575
// check the return result.
576
let ret = unsafe { pthread_kill(self.pthread_handle(), num) };
577
if ret < 0 {
578
return errno_result();
579
}
580
Ok(())
581
}
582
}
583
584
// SAFETY:
585
// Safe because we fulfill our contract of returning a genuine pthread handle.
586
unsafe impl<T> Killable for JoinHandle<T> {
587
fn pthread_handle(&self) -> pthread_t {
588
self.as_pthread_t() as _
589
}
590
}
591
592
// Represents a temporarily blocked signal. It will unblock the signal when dropped.
593
pub struct BlockedSignal {
594
signal_num: c_int,
595
}
596
597
impl BlockedSignal {
598
// Returns a `BlockedSignal` if the specified signal can be blocked, otherwise None.
599
pub fn new(signal_num: c_int) -> Option<BlockedSignal> {
600
if block_signal(signal_num).is_ok() {
601
Some(BlockedSignal { signal_num })
602
} else {
603
None
604
}
605
}
606
}
607
608
impl Drop for BlockedSignal {
609
fn drop(&mut self) {
610
unblock_signal(self.signal_num).expect("failed to restore signal mask");
611
}
612
}
613
614