blob: 81a900844c37d247d443a084266675a5df535c99 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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..
use sgx_libc::{c_int, c_void};
use sgx_libc::{
sigaction, sigaddset, sigdelset, sigemptyset, sigfillset, siginfo_t, sigismember, sigset_t,
};
use sgx_libc::{NSIG, SA_SIGINFO, SIGRTMAX};
use std::cell::Cell;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::mem;
use std::num::NonZeroU64;
use std::sync::Arc;
#[allow(deprecated)]
use std::sync::{SgxMutex, SgxThreadMutex};
use std::u64;
thread_local! { static SIGNAL_MASK: Cell<SigSet> = Cell::new(SigSet::new()) }
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SigNum(i32);
impl SigNum {
pub fn from_raw(signo: i32) -> Option<SigNum> {
if signo <= 0 || signo >= NSIG {
None
} else {
Some(SigNum(signo))
}
}
pub unsafe fn from_raw_uncheck(signo: i32) -> SigNum {
SigNum(signo)
}
pub fn raw(&self) -> i32 {
self.0
}
}
#[derive(Copy, Clone)]
pub struct SigSet(sigset_t);
impl SigSet {
pub fn new() -> SigSet {
let set = unsafe {
let mut set: sigset_t = mem::zeroed();
sigemptyset(&mut set as *mut sigset_t);
set
};
SigSet(set)
}
#[allow(dead_code)]
pub fn empty(&mut self) {
unsafe {
sigemptyset(&mut self.0 as *mut sigset_t);
}
}
pub fn add(&mut self, signo: SigNum) -> bool {
unsafe { sigaddset(&mut self.0 as *mut sigset_t, signo.raw()) == 0 }
}
pub fn delete(&mut self, signo: SigNum) -> bool {
unsafe { sigdelset(&mut self.0 as *mut sigset_t, signo.raw()) == 0 }
}
pub fn fill(&mut self) {
unsafe {
sigfillset(&mut self.0 as *mut sigset_t);
}
}
pub fn is_member(&self, signo: SigNum) -> bool {
unsafe { sigismember(&self.0 as *const sigset_t, signo.raw()) == 1 }
}
pub fn complement(&self) -> SigSet {
let mut set = SigSet::new();
for num in 0..=SIGRTMAX {
let signo = unsafe { SigNum::from_raw_uncheck(num) };
if !self.is_member(signo) {
set.add(signo);
}
}
set
}
pub unsafe fn from_raw(set: sigset_t) -> SigSet {
SigSet(set)
}
pub fn raw(&self) -> sigset_t {
self.0
}
}
pub fn block(set: &SigSet) {
let mut old_mask = get_block_mask();
for num in 0..SIGRTMAX {
let signo = unsafe { SigNum::from_raw_uncheck(num) };
if set.is_member(signo) {
old_mask.add(signo);
}
}
set_block_mask(old_mask);
}
pub fn unblock(set: &SigSet) {
let mut old_mask = get_block_mask();
for num in 0..=SIGRTMAX {
let signo = unsafe { SigNum::from_raw_uncheck(num) };
if set.is_member(signo) {
old_mask.delete(signo);
}
}
set_block_mask(old_mask);
}
#[inline]
pub fn get_block_mask() -> SigSet {
SIGNAL_MASK.with(|s| s.get())
}
#[inline]
pub fn set_block_mask(set: SigSet) {
SIGNAL_MASK.with(|s| s.set(set));
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ActionId(NonZeroU64);
impl ActionId {
fn new() -> Self {
static GUARD: SgxThreadMutex = SgxThreadMutex::new();
static mut COUNTER: u64 = 1;
unsafe {
let _guard = GUARD.lock();
if COUNTER == u64::MAX {
panic!("failed to generate unique ActionId : bitspace exhausted");
}
let id = COUNTER;
COUNTER += 1;
let _ = GUARD.unlock();
ActionId(NonZeroU64::new(id).unwrap())
}
}
}
pub type Action = dyn Fn(&siginfo_t) + Send + Sync;
#[derive(Clone)]
pub struct ActionSlot {
cur: sigaction,
actions: BTreeMap<ActionId, Arc<Action>>,
}
impl ActionSlot {
pub fn new(cur: &sigaction) -> Self {
ActionSlot {
cur: *cur,
actions: BTreeMap::new(),
}
}
pub fn set(&mut self, action: Arc<Action>) -> ActionId {
let id = ActionId::new();
self.actions.insert(id, action);
id
}
pub fn remove(&mut self, id: ActionId) -> bool {
self.actions.remove(&id).is_some()
}
pub fn get_act(&self) -> sigaction {
self.cur
}
}
pub struct SignalManager {
action_set: SgxMutex<HashMap<SigNum, ActionSlot>>,
reset_set: SgxMutex<HashSet<SigNum>>,
}
impl SignalManager {
pub fn new() -> Self {
SignalManager {
action_set: SgxMutex::new(HashMap::new()),
reset_set: SgxMutex::new(HashSet::new()),
}
}
pub fn set_action(&self, signo: SigNum, act: &sigaction) {
self.action_set
.lock()
.unwrap()
.insert(signo, ActionSlot::new(act));
}
pub fn set_action_impl<F>(&self, signo: SigNum, act: &sigaction, action: Arc<F>) -> ActionId
where
F: Fn(&siginfo_t) + Sync + Send + 'static,
{
let action_id = if !self.action_set.lock().unwrap().contains_key(&signo) {
let mut slot = ActionSlot::new(act);
let id = slot.set(action);
self.action_set.lock().unwrap().insert(signo, slot);
id
} else {
self.action_set
.lock()
.unwrap()
.get_mut(&signo)
.map(|slot| slot.set(action))
.unwrap()
};
action_id
}
pub fn get_action(&self, signo: SigNum) -> Option<ActionSlot> {
if let Some(slot) = self.action_set.lock().unwrap().get(&signo) {
Some(slot.clone())
} else {
None
}
}
pub fn remove_action(&self, signo: SigNum, id: ActionId) -> bool {
if let Some(ref mut slot) = self.action_set.lock().unwrap().get_mut(&signo) {
slot.remove(id)
} else {
false
}
}
pub fn clear_action(&self, signo: SigNum) -> bool {
self.action_set.lock().unwrap().remove(&signo).is_some()
}
pub fn is_action_empty(&self) -> bool {
self.action_set.lock().unwrap().is_empty()
}
pub fn set_reset_on_handle(&self, signo: SigNum) {
self.reset_set.lock().unwrap().insert(signo);
}
pub fn is_reset_on_handle(&self, signo: SigNum) -> bool {
self.reset_set.lock().unwrap().contains(&signo)
}
pub unsafe fn handler(&self, signum: i32, info: *const siginfo_t, context: *const c_void) {
type FnSaSigaction = extern "C" fn(c_int, *const siginfo_t, *const c_void);
type FnSaHandler = extern "C" fn(c_int);
let signo = match SigNum::from_raw(signum) {
Some(signo) => signo,
None => return,
};
let action_slot = match self.get_action(signo) {
Some(slot) => slot,
None => return,
};
let act = action_slot.get_act();
if self.is_reset_on_handle(signo) {
self.clear_action(signo);
}
let old_mask = get_block_mask();
block(&SigSet::from_raw(act.sa_mask));
let is_siginfo: bool = (act.sa_flags & SA_SIGINFO) != 0;
if is_siginfo && (act.sa_sigaction != 0) {
let fn_sa_sigaction =
mem::transmute::<*const (), FnSaSigaction>(act.sa_sigaction as *const ());
fn_sa_sigaction(signo.raw(), info, context);
} else if !is_siginfo && (act.sa_sigaction != 0) {
let fn_sa_handler =
mem::transmute::<*const (), FnSaHandler>(act.sa_sigaction as *const ());
fn_sa_handler(signo.raw());
}
let info = info.as_ref().unwrap();
for action in action_slot.actions.values() {
action(info);
}
set_block_mask(old_mask);
}
}