From 2c6d13f3fac35b901b39a851eea2662ae6d02bf1 Mon Sep 17 00:00:00 2001
From: huyubiao <h13958451065@163.com>
Date: Thu, 29 Jun 2023 21:40:53 +0800
Subject: [PATCH] fix: init does not enter the freeze during normal running

---
 core/bin/unit/notify.rs          |   4 +-
 exts/init/src/main.rs            |  21 ++--
 exts/init/src/runtime/comm.rs    | 163 ++++++++++++++++++++-----------
 exts/init/src/runtime/epoll.rs   |  14 ++-
 exts/init/src/runtime/mod.rs     |  51 ++++------
 exts/init/src/runtime/signals.rs |  95 ++++++++----------
 exts/init/src/runtime/timer.rs   |  58 ++++++++---
 libs/constants/src/lib.rs        |   3 +
 8 files changed, 226 insertions(+), 183 deletions(-)

diff --git a/core/bin/unit/notify.rs b/core/bin/unit/notify.rs
index f824725..d23a725 100644
--- a/core/bin/unit/notify.rs
+++ b/core/bin/unit/notify.rs
@@ -109,7 +109,7 @@ impl NotifyManager {
     }
 }
 
-const NOTIFY_INVALID_FD: i32 = -1;
+use constants::INVALID_FD;
 const NOTIFY_INVALID_PID: libc::pid_t = -1;
 
 struct Notify {
@@ -135,7 +135,7 @@ impl Notify {
             rentry: Rc::clone(rentryr),
             db: Rc::clone(dbr),
             config: Rc::clone(configr),
-            fd: RefCell::new(NOTIFY_INVALID_FD),
+            fd: RefCell::new(INVALID_FD),
         }
     }
 
diff --git a/exts/init/src/main.rs b/exts/init/src/main.rs
index 587077e..fbd77b9 100644
--- a/exts/init/src/main.rs
+++ b/exts/init/src/main.rs
@@ -23,21 +23,14 @@ fn main() {
     // Run: Monitor the sysmaster's liveliness and acceptance of message.
     // Unrecover: On-site problem collection or recreate new sysmaster.
     match RunTime::new(cmd) {
-        Ok(mut run_time) => {
-            loop {
-                let state = run_time.state();
-                let ret = match state {
-                    InitState::Reexec => run_time.reexec(),
-                    InitState::Run => run_time.run(),
-                    InitState::Unrecover => run_time.unrecover(),
-                };
-                if let Err(err) = ret {
-                    eprintln!("Failed to {:?}:{:?} ", state, err);
-                    break;
-                }
+        Ok(mut run_time) => loop {
+            let state = run_time.state();
+            match state {
+                InitState::Reexec => run_time.reexec(),
+                InitState::Run => run_time.run(),
+                InitState::Unrecover => run_time.unrecover(),
             }
-            run_time.clear();
-        }
+        },
         Err(err) => eprintln!(
             "Failed to new init, it may be necessary to run it as root :{:?}",
             err
diff --git a/exts/init/src/runtime/comm.rs b/exts/init/src/runtime/comm.rs
index 1a0d0ca..8f71511 100644
--- a/exts/init/src/runtime/comm.rs
+++ b/exts/init/src/runtime/comm.rs
@@ -14,18 +14,18 @@ use super::epoll::Epoll;
 use super::timer::Timer;
 use nix::errno::Errno;
 use nix::sys::epoll::EpollEvent;
+use nix::sys::inotify::{AddWatchFlags, InitFlags, Inotify, WatchDescriptor};
 use nix::sys::socket::{self, AddressFamily, SockFlag, SockType, UnixAddr};
 use nix::unistd;
+use std::os::unix::io::AsRawFd;
 use std::os::unix::prelude::RawFd;
 use std::rc::Rc;
-use std::str;
-use std::{fs, path::PathBuf};
+use std::{fs, path::PathBuf, str};
 
 const LISTEN_BACKLOG: usize = 10;
-const INVALID_FD: i32 = -1;
 const ACCEPT_COUNT: i32 = 3;
 const BUF_SIZE: usize = 16; //The communication string length is fixed to 16 characters.
-use constants::{ALIVE, INIT_SOCKET};
+use constants::{ALIVE, INIT_SOCKET, INVALID_FD};
 
 pub struct Comm {
     epoll: Rc<Epoll>,
@@ -33,6 +33,8 @@ pub struct Comm {
     connect_fd: RawFd,
     online_fd: RawFd, // Specsify either listen_fd or connect_fd.
     timer: Timer,
+    inotify: Inotify,
+    wd: WatchDescriptor,
 }
 
 #[derive(PartialEq, Eq)]
@@ -47,28 +49,7 @@ impl Comm {
     pub fn new(epoll: &Rc<Epoll>, time_wait: i64, time_cnt: i64) -> Result<Comm, Errno> {
         let timer = Timer::new(epoll, time_wait, time_cnt)?;
 
-        let sock_path = PathBuf::from(INIT_SOCKET);
-        let listen_fd = socket::socket(
-            AddressFamily::Unix,
-            SockType::Stream,
-            SockFlag::SOCK_CLOEXEC,
-            None,
-        )?;
-
-        let parent_path = sock_path.as_path().parent();
-        match parent_path {
-            Some(path) => fs::create_dir_all(path)
-                .map_err(|e| Errno::from_i32(e.raw_os_error().unwrap_or(Errno::EINVAL as i32)))?,
-            None => return Err(Errno::EINVAL),
-        }
-
-        if let Err(e) = unistd::unlink(&sock_path) {
-            eprintln!("Failed to unlink path:{:?}, error:{}", sock_path, e);
-        }
-
-        let addr = UnixAddr::new(&sock_path)?;
-        socket::bind(listen_fd, &addr)?;
-        socket::listen(listen_fd, LISTEN_BACKLOG)?;
+        let (listen_fd, inotify, wd) = create_listen_fd(epoll)?;
 
         let mut comm = Comm {
             epoll: epoll.clone(),
@@ -76,51 +57,50 @@ impl Comm {
             connect_fd: INVALID_FD,
             online_fd: INVALID_FD,
             timer,
+            inotify,
+            wd,
         };
 
         comm.set_online_fd(comm.listen_fd)?;
-
         Ok(comm)
     }
 
     pub fn is_fd(&self, fd: RawFd) -> bool {
-        if fd == self.online_fd || fd == self.timer.fd() {
-            return true;
-        }
-        false
+        fd == self.online_fd || fd == self.timer.fd() || fd == self.inotify.as_raw_fd()
     }
 
-    pub fn proc(&mut self, event: EpollEvent) -> Result<CommType, Errno> {
+    pub fn proc(&mut self, event: EpollEvent) -> CommType {
         if self.timer.fd() as u64 == event.data() {
-            if self.timer.is_time_out(event)? {
-                return Ok(CommType::PipTMOUT);
+            if self.timer.is_time_out(event) {
+                return CommType::PipTMOUT;
             }
-            return Ok(CommType::Succeed);
+            return CommType::Succeed;
+        }
+
+        if self.inotify.as_raw_fd() as u64 == event.data() {
+            // Dont self.inotify.read_events(), because if recover fails, event can be retrieved to recover again.
+            return self.recover();
+        }
+
+        // When the program runs normally, listen_fd will not be closed,
+        // but connect_fd will be closed during listening.
+        if self.listen_fd as u64 == event.data() && self.epoll.is_err(event) {
+            return self.recover();
         }
 
-        // When online_fd fails, ensure that connect_fd is closed, and then execute again after timeout.
         if self.online_fd as u64 == event.data() {
             match self.online_fd {
-                x if x == self.listen_fd => return self.listen_proc(event),
+                x if x == self.listen_fd => return self.listen_proc(),
                 x if x == self.connect_fd => return self.connect_proc(event),
                 _ => {}
             }
         }
-        Ok(CommType::Succeed)
+        CommType::Succeed
     }
 
     pub fn finish(&mut self) {
         _ = self.set_online_fd(self.listen_fd);
-    }
-
-    pub fn clear(&mut self) {
-        self.epoll.safe_close(self.listen_fd);
-        self.listen_fd = INVALID_FD;
-
-        self.epoll.safe_close(self.connect_fd);
-        self.connect_fd = INVALID_FD;
-
-        self.timer.clear();
+        self.timer.reset();
     }
 
     fn connect(&mut self) -> Result<(), Errno> {
@@ -223,21 +203,18 @@ impl Comm {
         Ok(())
     }
 
-    fn listen_proc(&mut self, event: EpollEvent) -> Result<CommType, Errno> {
-        if self.epoll.is_err(event) {
-            return Err(Errno::EINVAL);
-        }
+    fn listen_proc(&mut self) -> CommType {
         if self.connect().is_err() {
-            return Ok(CommType::PipOFF);
+            return CommType::PipOFF;
         }
         self.timer.reset();
-        Ok(CommType::PipON)
+        CommType::PipON
     }
 
-    fn connect_proc(&mut self, event: EpollEvent) -> Result<CommType, Errno> {
+    fn connect_proc(&mut self, event: EpollEvent) -> CommType {
         if self.epoll.is_err(event) {
             _ = self.set_online_fd(self.listen_fd);
-            return Ok(CommType::PipOFF);
+            return CommType::PipOFF;
         }
         match self.recv_msg() {
             Ok(buf) => {
@@ -252,6 +229,78 @@ impl Comm {
                 unistd::sleep(1);
             }
         }
-        Ok(CommType::Succeed)
+        CommType::Succeed
     }
+
+    fn recover(&mut self) -> CommType {
+        match create_listen_fd(&self.epoll) {
+            Ok((listen_fd, inotify, wd)) => {
+                self.epoll.safe_close(self.listen_fd);
+                self.epoll.safe_close(self.inotify.as_raw_fd());
+                self.listen_fd = listen_fd;
+                self.inotify = inotify;
+                self.wd = wd;
+                eprintln!("comm recover");
+                if self.online_fd == self.connect_fd {
+                    // The socket file(INIT_SOCKET) cannot be used when connecting,
+                    // so recreate the socket file(INIT_SOCKET) and return success.
+                    return CommType::Succeed;
+                } else {
+                    // If init is in the listening state,
+                    // the sysmaster cannot be connected through the old socket file(INIT_SOCKET) at this time,
+                    // we must recreate the socket file and then reexec the sysmaster.
+                    return CommType::PipTMOUT;
+                }
+            }
+            Err(e) => {
+                eprintln!("Failed to create_listen_fd:{:?}", e);
+            }
+        }
+        CommType::Succeed
+    }
+}
+
+impl Drop for Comm {
+    fn drop(&mut self) {
+        self.epoll.safe_close(self.listen_fd);
+        self.listen_fd = INVALID_FD;
+
+        self.epoll.safe_close(self.connect_fd);
+        self.connect_fd = INVALID_FD;
+
+        let _ = self.inotify.rm_watch(self.wd);
+        self.epoll.safe_close(self.inotify.as_raw_fd());
+    }
+}
+
+fn create_listen_fd(epoll: &Rc<Epoll>) -> Result<(i32, Inotify, WatchDescriptor), Errno> {
+    let listen_fd = socket::socket(
+        AddressFamily::Unix,
+        SockType::Stream,
+        SockFlag::SOCK_CLOEXEC,
+        None,
+    )?;
+
+    let sock_path = PathBuf::from(INIT_SOCKET);
+    let parent_path = sock_path.as_path().parent();
+    match parent_path {
+        Some(path) => fs::create_dir_all(path)
+            .map_err(|e| Errno::from_i32(e.raw_os_error().unwrap_or(Errno::EINVAL as i32)))?,
+        None => return Err(Errno::EINVAL),
+    }
+
+    if let Err(e) = unistd::unlink(&sock_path) {
+        eprintln!("Failed to unlink path:{:?}, error:{}", sock_path, e);
+    }
+
+    let addr = UnixAddr::new(&sock_path)?;
+    socket::bind(listen_fd, &addr)?;
+    socket::listen(listen_fd, LISTEN_BACKLOG)?;
+
+    let inotify = Inotify::init(InitFlags::all())?;
+
+    let wd = inotify.add_watch(INIT_SOCKET, AddWatchFlags::IN_ALL_EVENTS)?;
+
+    epoll.register(inotify.as_raw_fd())?;
+    Ok((listen_fd, inotify, wd))
 }
diff --git a/exts/init/src/runtime/epoll.rs b/exts/init/src/runtime/epoll.rs
index ad7475f..6c21bbc 100644
--- a/exts/init/src/runtime/epoll.rs
+++ b/exts/init/src/runtime/epoll.rs
@@ -10,6 +10,7 @@
 // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 // See the Mulan PSL v2 for more details.
 
+use constants::INVALID_FD;
 use nix::errno::Errno;
 use nix::sys::epoll::{self, EpollEvent, EpollFlags, EpollOp};
 use nix::unistd;
@@ -21,7 +22,7 @@ pub struct Epoll {
 
 impl Epoll {
     pub(crate) fn new() -> Result<Epoll, Errno> {
-        let epoll_fd = epoll::epoll_create1(epoll::EpollCreateFlags::empty())?;
+        let epoll_fd = epoll::epoll_create1(epoll::EpollCreateFlags::EPOLL_CLOEXEC)?;
         Ok(Epoll { epoll_fd })
     }
 
@@ -61,10 +62,6 @@ impl Epoll {
         false
     }
 
-    pub(crate) fn clear(&self) {
-        self.safe_close(self.epoll_fd);
-    }
-
     pub(crate) fn safe_close(&self, fd: RawFd) {
         if fd <= 0 {
             return;
@@ -75,3 +72,10 @@ impl Epoll {
         };
     }
 }
+
+impl Drop for Epoll {
+    fn drop(&mut self) {
+        self.safe_close(self.epoll_fd);
+        self.epoll_fd = INVALID_FD;
+    }
+}
diff --git a/exts/init/src/runtime/mod.rs b/exts/init/src/runtime/mod.rs
index d11d8f2..e81a513 100644
--- a/exts/init/src/runtime/mod.rs
+++ b/exts/init/src/runtime/mod.rs
@@ -81,7 +81,7 @@ impl RunTime {
         self.state
     }
 
-    pub fn reexec(&mut self) -> Result<(), Errno> {
+    pub fn reexec(&mut self) {
         if self.need_reexec {
             self.reexec_manager();
         }
@@ -89,43 +89,33 @@ impl RunTime {
         let event = self.epoll.wait_one();
         let fd = event.data() as RawFd;
         match fd {
-            _x if self.comm.is_fd(fd) => self.reexec_comm_dispatch(event)?,
-            _x if self.signals.is_fd(fd) => self.reexec_signal_dispatch(event)?,
+            _x if self.comm.is_fd(fd) => self.reexec_comm_dispatch(event),
+            _x if self.signals.is_fd(fd) => self.reexec_signal_dispatch(event),
             _ => self.epoll.safe_close(fd),
         }
-        Ok(())
     }
 
-    pub fn run(&mut self) -> Result<(), Errno> {
+    pub fn run(&mut self) {
         let event = self.epoll.wait_one();
         let fd = event.data() as RawFd;
         match fd {
-            _x if self.comm.is_fd(fd) => self.run_comm_dispatch(event)?,
-            _x if self.signals.is_fd(fd) => self.run_signal_dispatch(event)?,
+            _x if self.comm.is_fd(fd) => self.run_comm_dispatch(event),
+            _x if self.signals.is_fd(fd) => self.run_signal_dispatch(event),
             _ => self.epoll.safe_close(fd),
         }
-        Ok(())
     }
 
-    pub fn unrecover(&mut self) -> Result<(), Errno> {
+    pub fn unrecover(&mut self) {
         let event = self.epoll.wait_one();
         let fd = event.data() as RawFd;
         match fd {
             _x if self.comm.is_fd(fd) => self.unrecover_comm_dispatch(event),
-            _x if self.signals.is_fd(fd) => self.unrecover_signal_dispatch(event)?,
+            _x if self.signals.is_fd(fd) => self.unrecover_signal_dispatch(event),
             _ => self.epoll.safe_close(fd),
         }
-        Ok(())
-    }
-
-    pub fn clear(&mut self) {
-        self.comm.clear();
-        self.signals.clear();
-        self.epoll.clear();
     }
 
     pub fn reexec_self(&mut self) {
-        self.clear();
         let mut args = Vec::new();
         let mut init_path = CString::new("/usr/bin/init").unwrap();
         if let Some(str) = std::env::args().next() {
@@ -154,17 +144,16 @@ impl RunTime {
         unsafe { libc::kill(self.sysmaster_pid.into(), libc::SIGABRT) };
     }
 
-    fn reexec_comm_dispatch(&mut self, event: EpollEvent) -> Result<(), Errno> {
-        match self.comm.proc(event)? {
+    fn reexec_comm_dispatch(&mut self, event: EpollEvent) {
+        match self.comm.proc(event) {
             CommType::PipON => self.state = InitState::Run,
             CommType::PipTMOUT => self.need_reexec = true,
             _ => {}
         }
-        Ok(())
     }
 
-    fn run_comm_dispatch(&mut self, event: EpollEvent) -> Result<(), Errno> {
-        match self.comm.proc(event)? {
+    fn run_comm_dispatch(&mut self, event: EpollEvent) {
+        match self.comm.proc(event) {
             CommType::PipOFF => self.state = InitState::Reexec,
             CommType::PipTMOUT => {
                 self.state = InitState::Reexec;
@@ -172,15 +161,14 @@ impl RunTime {
             }
             _ => {}
         }
-        Ok(())
     }
 
     fn unrecover_comm_dispatch(&mut self, event: EpollEvent) {
         _ = self.comm.proc(event);
     }
 
-    fn reexec_signal_dispatch(&mut self, event: EpollEvent) -> Result<(), Errno> {
-        if let Some(siginfo) = self.signals.read(event)? {
+    fn reexec_signal_dispatch(&mut self, event: EpollEvent) {
+        if let Some(siginfo) = self.signals.read(event) {
             match siginfo {
                 _x if self.signals.is_zombie(siginfo) => self.do_recycle(),
                 _x if self.signals.is_restart(siginfo) => self.do_reexec(),
@@ -188,11 +176,10 @@ impl RunTime {
                 _ => {}
             }
         }
-        Ok(())
     }
 
-    fn run_signal_dispatch(&mut self, event: EpollEvent) -> Result<(), Errno> {
-        if let Some(siginfo) = self.signals.read(event)? {
+    fn run_signal_dispatch(&mut self, event: EpollEvent) {
+        if let Some(siginfo) = self.signals.read(event) {
             match siginfo {
                 _x if self.signals.is_zombie(siginfo) => self.do_recycle(),
                 _x if self.signals.is_restart(siginfo) => self.do_reexec(),
@@ -200,11 +187,10 @@ impl RunTime {
                 _ => {}
             }
         }
-        Ok(())
     }
 
-    fn unrecover_signal_dispatch(&mut self, event: EpollEvent) -> Result<(), Errno> {
-        if let Some(siginfo) = self.signals.read(event)? {
+    fn unrecover_signal_dispatch(&mut self, event: EpollEvent) {
+        if let Some(siginfo) = self.signals.read(event) {
             match siginfo {
                 _x if self.signals.is_zombie(siginfo) => {
                     self.signals.recycle_zombie();
@@ -216,7 +202,6 @@ impl RunTime {
                 _ => {}
             }
         }
-        Ok(())
     }
 
     fn change_to_unrecover(&mut self) {
diff --git a/exts/init/src/runtime/signals.rs b/exts/init/src/runtime/signals.rs
index 1c3059c..327ff3e 100644
--- a/exts/init/src/runtime/signals.rs
+++ b/exts/init/src/runtime/signals.rs
@@ -13,7 +13,8 @@
 use super::epoll::Epoll;
 use nix::errno::Errno;
 use nix::sys::epoll::EpollEvent;
-use nix::sys::signal::{SigmaskHow, Signal};
+use nix::sys::signal::{self, SigSet, SigmaskHow, Signal};
+use nix::sys::signalfd::{self, SfdFlags};
 use nix::sys::wait::{self, Id, WaitPidFlag, WaitStatus};
 use nix::unistd;
 use std::mem;
@@ -21,42 +22,12 @@ use std::ops::Neg;
 use std::os::unix::io::RawFd;
 use std::rc::Rc;
 
+use constants::INVALID_FD;
 use constants::{SIG_RESTART_MANAGER_OFFSET, SIG_RUN_UNRECOVER_OFFSET, SIG_SWITCH_ROOT_OFFSET};
-const INVALID_FD: i32 = -1;
-
-pub(crate) struct SigSet {
-    sigset: libc::sigset_t,
-}
-
-impl SigSet {
-    /// Initialize to include nothing.
-    pub fn empty() -> SigSet {
-        let mut sigset = mem::MaybeUninit::zeroed();
-        let _ = unsafe { libc::sigemptyset(sigset.as_mut_ptr()) };
-
-        unsafe {
-            SigSet {
-                sigset: sigset.assume_init(),
-            }
-        }
-    }
-
-    /// Add the specified signal to the set.
-    pub fn add(&mut self, signal: libc::c_int) {
-        unsafe {
-            libc::sigaddset(
-                &mut self.sigset as *mut libc::sigset_t,
-                signal as libc::c_int,
-            )
-        };
-    }
-}
 
 pub struct Signals {
     epoll: Rc<Epoll>,
-    signal_fd: RawFd,
-    set: SigSet,
-    oldset: SigSet,
+    pub signal_fd: RawFd,
     signals: Vec<i32>,
     zombie_signal: i32,
     restart_signal: i32,
@@ -71,8 +42,6 @@ impl Signals {
         Signals {
             epoll: epoll.clone(),
             signal_fd: INVALID_FD,
-            set: SigSet::empty(),
-            oldset: SigSet::empty(),
             signals,
             zombie_signal: libc::SIGCHLD,
             unrecover_signal: libc::SIGRTMIN() + SIG_RUN_UNRECOVER_OFFSET,
@@ -101,29 +70,25 @@ impl Signals {
     }
 
     pub fn create_signals_epoll(&mut self) -> Result<(), Errno> {
-        self.reset_sigset();
+        self.signal_fd = self.reset_sigset()?;
         self.epoll.register(self.signal_fd)?;
         Ok(())
     }
 
-    pub fn reset_sigset(&mut self) {
+    pub fn reset_sigset(&mut self) -> Result<RawFd, Errno> {
+        let mut sigset = SigSet::empty();
         for sig in self.signals.clone() {
-            self.set.add(sig);
-        }
-
-        unsafe {
-            libc::pthread_sigmask(libc::SIG_BLOCK, &self.set.sigset, &mut self.oldset.sigset);
-            self.signal_fd = libc::signalfd(
-                -1,
-                &mut self.set.sigset as *const libc::sigset_t,
-                libc::SFD_NONBLOCK,
-            );
+            let signum: Signal = unsafe { std::mem::transmute(sig) };
+            sigset.add(signum);
         }
+        let mut oldset = SigSet::empty();
+        signal::pthread_sigmask(SigmaskHow::SIG_BLOCK, Some(&sigset), Some(&mut oldset))?;
+        signalfd::signalfd(-1, &sigset, SfdFlags::SFD_CLOEXEC | SfdFlags::SFD_NONBLOCK)
     }
 
-    pub fn read(&mut self, event: EpollEvent) -> Result<Option<libc::signalfd_siginfo>, Errno> {
+    pub fn read(&mut self, event: EpollEvent) -> Option<libc::signalfd_siginfo> {
         if self.epoll.is_err(event) {
-            return Err(Errno::EIO);
+            return self.recover();
         }
         let mut buffer = mem::MaybeUninit::<libc::signalfd_siginfo>::zeroed();
 
@@ -139,14 +104,14 @@ impl Signals {
         match res {
             x if x == size as isize => {
                 let info = unsafe { buffer.assume_init() };
-                Ok(Some(info))
+                Some(info)
             }
-            x if x >= 0 => Ok(None),
+            x if x >= 0 => None,
             x => {
                 let err = Errno::from_i32(x.neg() as i32);
                 eprintln!("read_signals failed err:{:?}", err);
                 unistd::sleep(1);
-                Ok(None)
+                None
             }
         }
     }
@@ -191,13 +156,31 @@ impl Signals {
     }
 
     pub fn is_fd(&self, fd: RawFd) -> bool {
-        if fd == self.signal_fd {
-            return true;
+        fd == self.signal_fd
+    }
+
+    fn recover(&mut self) -> Option<libc::signalfd_siginfo> {
+        match self.reset_sigset() {
+            Ok(signal_fd) => match self.epoll.register(signal_fd) {
+                Ok(_) => {
+                    self.epoll.safe_close(self.signal_fd);
+                    self.signal_fd = signal_fd;
+                    eprintln!("signals recover");
+                }
+                Err(e) => {
+                    eprintln!("Failed to register signal_fd:{:?}", e);
+                }
+            },
+            Err(e) => {
+                eprintln!("Failed to create_signals_epoll:{:?}", e);
+            }
         }
-        false
+        None
     }
+}
 
-    pub fn clear(&mut self) {
+impl Drop for Signals {
+    fn drop(&mut self) {
         self.epoll.safe_close(self.signal_fd);
         self.signal_fd = INVALID_FD;
         if let Err(e) = nix::sys::signal::pthread_sigmask(
diff --git a/exts/init/src/runtime/timer.rs b/exts/init/src/runtime/timer.rs
index f7b5f30..54fcc62 100644
--- a/exts/init/src/runtime/timer.rs
+++ b/exts/init/src/runtime/timer.rs
@@ -24,25 +24,18 @@ pub struct Timer {
     epoll: Rc<Epoll>,
     timer: TimerFd,
     current_cnt: i64,
+    time_wait: i64,
     time_cnt: i64,
 }
 
 impl Timer {
     pub fn new(epoll: &Rc<Epoll>, time_wait: i64, time_cnt: i64) -> Result<Timer, Errno> {
-        let timer = TimerFd::new(
-            ClockId::CLOCK_REALTIME,
-            TimerFlags::TFD_NONBLOCK | TimerFlags::TFD_CLOEXEC,
-        )?;
-        timer.set(
-            Expiration::Interval(TimeSpec::seconds(time_wait)),
-            TimerSetTimeFlags::empty(),
-        )?;
-
-        epoll.register(timer.as_raw_fd())?;
+        let timer = create_timer(epoll, time_wait)?;
         Ok(Timer {
             epoll: epoll.clone(),
             timer,
             current_cnt: 0,
+            time_wait,
             time_cnt,
         })
     }
@@ -56,18 +49,18 @@ impl Timer {
     }
 
     #[allow(clippy::wrong_self_convention)]
-    pub fn is_time_out(&mut self, event: EpollEvent) -> Result<bool, Errno> {
+    pub fn is_time_out(&mut self, event: EpollEvent) -> bool {
         if self.epoll.is_err(event) {
-            return Err(Errno::EIO);
+            return self.recover();
         }
         self.flush();
         self.current_cnt += 1;
         if self.time_cnt <= self.current_cnt {
             eprintln!("time out!");
             self.reset();
-            return Ok(true);
+            return true;
         }
-        Ok(false)
+        false
     }
 
     // reset timer.
@@ -79,7 +72,40 @@ impl Timer {
         self.timer.as_raw_fd()
     }
 
-    pub fn clear(&mut self) {
-        self.epoll.safe_close(self.timer.as_raw_fd());
+    fn recover(&mut self) -> bool {
+        match create_timer(&self.epoll, self.time_wait) {
+            Ok(timer) => {
+                // After successfully creating a new timer, recycle the old timer so that
+                // if create_timer fails, event can be retrieved to create_timer again.
+                // timer have drop, no need to manually close timer.
+                self.timer = timer;
+                eprintln!("timer recover");
+            }
+            Err(e) => {
+                eprintln!("Failed to create_timer:{:?}", e);
+            }
+        }
+        // Here we believe that the system has encountered an exception, set it to timeout
+        true
+    }
+}
+
+impl Drop for Timer {
+    fn drop(&mut self) {
+        // self.timer does not need to drop, because TimerFd have drop.
     }
 }
+
+fn create_timer(epoll: &Rc<Epoll>, time_wait: i64) -> Result<TimerFd, Errno> {
+    let timer = TimerFd::new(
+        ClockId::CLOCK_REALTIME,
+        TimerFlags::TFD_NONBLOCK | TimerFlags::TFD_CLOEXEC,
+    )?;
+    timer.set(
+        Expiration::Interval(TimeSpec::seconds(time_wait)),
+        TimerSetTimeFlags::empty(),
+    )?;
+
+    epoll.register(timer.as_raw_fd())?;
+    Ok(timer)
+}
diff --git a/libs/constants/src/lib.rs b/libs/constants/src/lib.rs
index 6005067..1f84b40 100644
--- a/libs/constants/src/lib.rs
+++ b/libs/constants/src/lib.rs
@@ -29,3 +29,6 @@ pub const SCTL_SOCKET: &str = "/run/sysmaster/sctl";
 
 /// Default log file path when LogTarget is configured to "file"
 pub const LOG_FILE_PATH: &str = "/var/log/sysmaster/sysmaster.log";
+
+/// invalid fd
+pub const INVALID_FD: i32 = -1;
-- 
2.33.0

