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