xref: /cloud-hypervisor/virtio-devices/src/thread_helper.rs (revision 61e57e1cb149de03ae1e0b799b9e5ba9a4a63ace)
1 // Copyright © 2021 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0
4 //
5 
6 use std::panic::AssertUnwindSafe;
7 use std::thread::{self, JoinHandle};
8 
9 use seccompiler::{apply_filter, SeccompAction};
10 use vmm_sys_util::eventfd::EventFd;
11 
12 use crate::epoll_helper::EpollHelperError;
13 use crate::seccomp_filters::{get_seccomp_filter, Thread};
14 use crate::ActivateError;
15 
spawn_virtio_thread<F>( name: &str, seccomp_action: &SeccompAction, thread_type: Thread, epoll_threads: &mut Vec<JoinHandle<()>>, exit_evt: &EventFd, f: F, ) -> Result<(), ActivateError> where F: FnOnce() -> std::result::Result<(), EpollHelperError>, F: Send + 'static,16 pub(crate) fn spawn_virtio_thread<F>(
17     name: &str,
18     seccomp_action: &SeccompAction,
19     thread_type: Thread,
20     epoll_threads: &mut Vec<JoinHandle<()>>,
21     exit_evt: &EventFd,
22     f: F,
23 ) -> Result<(), ActivateError>
24 where
25     F: FnOnce() -> std::result::Result<(), EpollHelperError>,
26     F: Send + 'static,
27 {
28     let seccomp_filter = get_seccomp_filter(seccomp_action, thread_type)
29         .map_err(ActivateError::CreateSeccompFilter)?;
30 
31     let thread_exit_evt = exit_evt
32         .try_clone()
33         .map_err(ActivateError::CloneExitEventFd)?;
34     let thread_name = name.to_string();
35 
36     thread::Builder::new()
37         .name(name.to_string())
38         .spawn(move || {
39             if !seccomp_filter.is_empty() {
40                 if let Err(e) = apply_filter(&seccomp_filter) {
41                     error!("Error applying seccomp filter: {:?}", e);
42                     thread_exit_evt.write(1).ok();
43                     return;
44                 }
45             }
46             match std::panic::catch_unwind(AssertUnwindSafe(f)) {
47                 Err(_) => {
48                     error!("{} thread panicked", thread_name);
49                     thread_exit_evt.write(1).ok();
50                 }
51                 Ok(r) => {
52                     if let Err(e) = r {
53                         error!("Error running worker: {:?}", e);
54                         thread_exit_evt.write(1).ok();
55                     }
56                 }
57             };
58         })
59         .map(|thread| epoll_threads.push(thread))
60         .map_err(|e| {
61             error!("Failed to spawn thread for {}: {}", name, e);
62             ActivateError::ThreadSpawn(e)
63         })
64 }
65