diff options
author | Zach Reizner <zachr@google.com> | 2017-05-23 11:16:24 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-06-30 12:51:24 -0700 |
commit | 422e6502dee4c63d0cf742cdb17c922d2864ca08 (patch) | |
tree | d6a6bfa5c226bc2858ab04b44edd4f796933502c /sys_util/src/signal.rs | |
parent | 8266b87e0eec1fa5a7c6719f4614d2ef99be51f9 (diff) | |
download | crosvm-422e6502dee4c63d0cf742cdb17c922d2864ca08.tar crosvm-422e6502dee4c63d0cf742cdb17c922d2864ca08.tar.gz crosvm-422e6502dee4c63d0cf742cdb17c922d2864ca08.tar.bz2 crosvm-422e6502dee4c63d0cf742cdb17c922d2864ca08.tar.lz crosvm-422e6502dee4c63d0cf742cdb17c922d2864ca08.tar.xz crosvm-422e6502dee4c63d0cf742cdb17c922d2864ca08.tar.zst crosvm-422e6502dee4c63d0cf742cdb17c922d2864ca08.zip |
sys_util: add signal module for killing threads
The signal module is used for registering signal handlers and for signalling threads. Normally signals would be a method of last resort, but in this case it's the only possible way to trigger a VM exit on a thread currently inside of a KVM_RUN call. BUG=None TEST=None Change-Id: If1db1e17937d1af08fc24b422c460be754cf9d22 Reviewed-on: https://chromium-review.googlesource.com/514415 Commit-Ready: Zach Reizner <zachr@chromium.org> Tested-by: Zach Reizner <zachr@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org>
Diffstat (limited to 'sys_util/src/signal.rs')
-rw-r--r-- | sys_util/src/signal.rs | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/sys_util/src/signal.rs b/sys_util/src/signal.rs new file mode 100644 index 0000000..0fc4612 --- /dev/null +++ b/sys_util/src/signal.rs @@ -0,0 +1,85 @@ +// Copyright 2017 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use libc::{c_int, pthread_t, signal, pthread_kill, SIG_ERR, EINVAL}; + +use std::thread::JoinHandle; +use std::os::unix::thread::JoinHandleExt; + +use {Error, Result, errno_result}; + +#[link(name = "c")] +extern "C" { + fn __libc_current_sigrtmin() -> c_int; + fn __libc_current_sigrtmax() -> c_int; +} + +/// Returns the minimum (inclusive) real-time signal number. +#[allow(non_snake_case)] +pub fn SIGRTMIN() -> c_int { + unsafe { __libc_current_sigrtmin() } +} + +/// Returns the maximum (inclusive) real-time signal number. +#[allow(non_snake_case)] +pub fn SIGRTMAX() -> c_int { + unsafe { __libc_current_sigrtmax() } +} + +fn valid_signal_num(num: u8) -> bool { + (num as c_int) + SIGRTMIN() <= SIGRTMAX() +} + +/// Registers `handler` as the signal handler of signum `num + SIGRTMIN`. +/// +/// The value of `num + SIGRTMIN` must not exceed `SIGRTMAX`. +/// +/// This is considered unsafe because the given handler will be called asynchronously, interrupting +/// whatever the thread was doing and therefore must only do async-signal-safe operations. +pub unsafe fn register_signal_handler(num: u8, handler: extern "C" fn() -> ()) -> Result<()> { + if !valid_signal_num(num) { + return Err(Error::new(EINVAL)); + } + let ret = signal((num as i32) + SIGRTMIN(), handler as *const () as usize); + if ret == SIG_ERR { + return errno_result(); + } + + Ok(()) +} + +/// Trait for threads that can be signalled via `pthread_kill`. +/// +/// Note that this is only useful for signals between SIGRTMIN and SIGRTMAX because these are +/// guaranteed to not be used by the C runtime. +/// +/// This is marked unsafe because the implementation of this trait must guarantee that the returned +/// pthread_t is valid and has a lifetime at least that of the trait object. +pub unsafe trait Killable { + fn pthread_handle(&self) -> pthread_t; + + /// Sends the signal `num + SIGRTMIN` to this killable thread. + /// + /// The value of `num + SIGRTMIN` must not exceed `SIGRTMAX`. + fn kill(&self, num: u8) -> Result<()> { + if !valid_signal_num(num) { + return Err(Error::new(EINVAL)); + } + + // Safe because we ensure we are using a valid pthread handle, a valid signal number, and + // check the return result. + let ret = unsafe { pthread_kill(self.pthread_handle(), (num as i32) + SIGRTMIN()) }; + if ret < 0 { + return errno_result(); + } + Ok(()) + } +} + +// Safe because we fulfill our contract of returning a genuine pthread handle. +unsafe impl<T> Killable for JoinHandle<T> { + fn pthread_handle(&self) -> pthread_t { + self.as_pthread_t() + } +} |