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