1use super::errors;
2use super::nr;
3use errno;
4#[cfg(feature = "async")]
5use futures::prelude::*;
6use libc;
7#[cfg(feature = "async")]
8use tokio::timer;
9
10#[derive(Clone, Debug)]
14pub struct ModUnloader {
15 force: bool,
16}
17
18impl Default for ModUnloader {
19 fn default() -> Self {
20 Self { force: false }
21 }
22}
23
24impl ModUnloader {
25 pub fn new() -> Self {
27 Self::default()
28 }
29
30 pub fn forced(mut self, force_unload: bool) -> Self {
35 self.force = force_unload;
36 self
37 }
38
39 pub fn unload_sync<S: AsRef<str>>(&self, modname: S, blocking: bool) -> errors::Result<()> {
49 let flags = match (self.force, blocking) {
50 (false, false) => 0,
51 (true, false) => libc::O_TRUNC,
52 (true, true) => libc::O_TRUNC | libc::O_NONBLOCK,
53 (false, true) => libc::O_NONBLOCK,
54 };
55 let r = unsafe { libc::syscall(nr::DELETE_MODULE, modname.as_ref().as_ptr(), flags) };
57 match r {
58 0 => Ok(()),
59 _ => Err(
60 errors::Error::from_kind(errors::ErrorKind::Sys(errno::errno()))
61 .chain_err(|| "blocking delete_module error"),
62 ),
63 }
64 }
65
66 #[cfg(feature = "async")]
73 pub fn unload_async<S: AsRef<str>>(
74 &self,
75 modname: S,
76 pause_millis: ::std::num::NonZeroU64,
77 ) -> Box<Future<Item = (), Error = errors::Error>> {
78 let flags = {
79 let ff = if self.force { libc::O_TRUNC } else { 0 };
80 ff | libc::O_NONBLOCK
81 };
82 let pause = ::std::time::Duration::from_millis(pause_millis.get());
83 let unloader = UnloadTask {
84 flags,
85 interval: timer::Interval::new_interval(pause),
86 modname: modname.as_ref().to_string(),
87 };
88 Box::new(unloader)
89 }
90}
91
92#[cfg(feature = "async")]
93pub(crate) struct UnloadTask {
94 flags: libc::c_int,
95 interval: timer::Interval,
96 modname: String,
97}
98
99#[cfg(feature = "async")]
100impl Future for UnloadTask {
101 type Item = ();
102 type Error = errors::Error;
103 fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
104 use futures::task;
105
106 match self.interval.poll() {
109 Ok(Async::Ready(_)) => {}
110 Ok(Async::NotReady) => {
111 task::current().notify();
112 return Ok(Async::NotReady);
113 }
114 Err(e) => bail!("failed rate-limiting interval: {}", e),
115 };
116
117 let r = unsafe { libc::syscall(nr::DELETE_MODULE, self.modname.as_ptr(), self.flags) };
119
120 if r == 0 {
122 return Ok(Async::Ready(()));
123 }
124
125 let num = errno::errno();
127 if num.0 == libc::EWOULDBLOCK {
128 task::current().notify();
129 return Ok(Async::NotReady);
130 }
131
132 Err(errors::Error::from_kind(errors::ErrorKind::Sys(num))
134 .chain_err(|| "async delete_module error"))
135 }
136}