Use Unix timer_* API instead of setitimer (#510)
* fix linter errors for armv7 (docs) * introduce HasOnCrashReset trait; use timer_* API instead of setitimer for unix TimeoutExecutor * fixes: PR #469 annotations and CI issues * reintroduce setitimer for apple as macOS does not feature the POSIX timer API * more macos and windows CI fixes * more macos and windows CI fixes cont. * HasOnCrashReset -> HasPostRunReset * remove drop impl for Windows TimeoutExecutor * adjust target cfgs for timeout stuff (android also did not work) * add call to inner post_run_reset * remove HasPostRunReset in favor of making it a trait fn of Executor * add post_run_reset's to CombinedExecutor * clippy: addr_of! instead of raw pointer casts * link librt in libafl_cc (required by timer_* API) * minor fixes and cleanup * remove unused import for targets other than linux * fix win * merge * fix Co-authored-by: pr0me <g33sus@gmail.com>
This commit is contained in:
parent
9dfc6aa404
commit
c61fed6ca9
@ -17,42 +17,72 @@ use std::ffi::CString;
|
||||
#[cfg(target_arch = "arm")]
|
||||
pub use libc::c_ulong;
|
||||
|
||||
/// ARMv7-specific representation of a saved context
|
||||
#[cfg(target_arch = "arm")]
|
||||
#[derive(Debug)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(C)]
|
||||
pub struct mcontext_t {
|
||||
/// Signal Number
|
||||
pub trap_no: c_ulong,
|
||||
/// Error Code
|
||||
pub error_code: c_ulong,
|
||||
/// Old signal mask
|
||||
pub oldmask: c_ulong,
|
||||
/// GPR R0
|
||||
pub arm_r0: c_ulong,
|
||||
/// GPR R1
|
||||
pub arm_r1: c_ulong,
|
||||
/// GPR R2
|
||||
pub arm_r2: c_ulong,
|
||||
/// GPR R3
|
||||
pub arm_r3: c_ulong,
|
||||
/// GPR R4
|
||||
pub arm_r4: c_ulong,
|
||||
/// GPR R5
|
||||
pub arm_r5: c_ulong,
|
||||
/// GPR R6
|
||||
pub arm_r6: c_ulong,
|
||||
/// GPR R7
|
||||
pub arm_r7: c_ulong,
|
||||
/// GPR R8
|
||||
pub arm_r8: c_ulong,
|
||||
/// GPR R9
|
||||
pub arm_r9: c_ulong,
|
||||
/// GPR R10
|
||||
pub arm_r10: c_ulong,
|
||||
/// Frame Pointer
|
||||
pub arm_fp: c_ulong,
|
||||
/// Intra-Procedure Scratch Register
|
||||
pub arm_ip: c_ulong,
|
||||
/// Stack Pointer
|
||||
pub arm_sp: c_ulong,
|
||||
/// Link Register
|
||||
pub arm_lr: c_ulong,
|
||||
/// Program Counter
|
||||
pub arm_pc: c_ulong,
|
||||
/// Current Program Status Register
|
||||
pub arm_cpsr: c_ulong,
|
||||
/// Fault Address
|
||||
pub fault_address: c_ulong,
|
||||
}
|
||||
|
||||
/// User Context Struct
|
||||
#[cfg(target_arch = "arm")]
|
||||
#[derive(Debug)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[repr(C)]
|
||||
pub struct ucontext_t {
|
||||
/// Flags
|
||||
pub uc_flags: u32,
|
||||
/// Pointer to the context that will be resumed when this context returns
|
||||
pub uc_link: *mut ucontext_t,
|
||||
/// Stack used by this context
|
||||
pub uc_stack: stack_t,
|
||||
/// Machine-specific representation of the saved context
|
||||
pub uc_mcontext: mcontext_t,
|
||||
pub uc_sigmask: nix::sys::signal::SigSet,
|
||||
/// Set of signals that are blocked when this context is active
|
||||
pub uc_sigmask: libc::sigset_t,
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "arm"))]
|
||||
|
@ -1118,7 +1118,6 @@ pub mod win32_shmem {
|
||||
fmt::{self, Debug, Formatter},
|
||||
ptr, slice,
|
||||
};
|
||||
use std::convert::TryInto;
|
||||
use uuid::Uuid;
|
||||
|
||||
const INVALID_HANDLE_VALUE: isize = -1;
|
||||
|
@ -50,7 +50,10 @@ where
|
||||
mgr: &mut EM,
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
self.primary.run_target(fuzzer, state, mgr, input)
|
||||
let ret = self.primary.run_target(fuzzer, state, mgr, input);
|
||||
self.primary.post_run_reset();
|
||||
self.secondary.post_run_reset();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,7 +305,7 @@ impl InProcessHandlers {
|
||||
pub fn new<E, EM, I, OF, OT, S, Z, H>() -> Result<Self, Error>
|
||||
where
|
||||
I: Input,
|
||||
E: HasObservers<I, OT, S>,
|
||||
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
EM: EventFirer<I> + EventRestarter<S>,
|
||||
OF: Feedback<I, S>,
|
||||
@ -628,8 +628,7 @@ mod unix_signal_handler {
|
||||
events::{Event, EventFirer, EventRestarter},
|
||||
executors::{
|
||||
inprocess::{InProcessExecutorHandlerData, GLOBAL_STATE},
|
||||
timeout::unix_remove_timeout,
|
||||
ExitKind, HasObservers,
|
||||
Executor, ExitKind, HasObservers,
|
||||
},
|
||||
feedbacks::Feedback,
|
||||
fuzzer::HasObjective,
|
||||
@ -775,7 +774,7 @@ mod unix_signal_handler {
|
||||
_context: &mut ucontext_t,
|
||||
data: &mut InProcessExecutorHandlerData,
|
||||
) where
|
||||
E: HasObservers<I, OT, S>,
|
||||
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
||||
EM: EventFirer<I> + EventRestarter<S>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
OF: Feedback<I, S>,
|
||||
@ -783,8 +782,6 @@ mod unix_signal_handler {
|
||||
I: Input,
|
||||
Z: HasObjective<I, OF, S>,
|
||||
{
|
||||
unix_remove_timeout();
|
||||
|
||||
#[cfg(all(target_os = "android", target_arch = "aarch64"))]
|
||||
let _context = &mut *(((_context as *mut _ as *mut libc::c_void as usize) + 128)
|
||||
as *mut libc::c_void as *mut ucontext_t);
|
||||
@ -825,11 +822,14 @@ mod unix_signal_handler {
|
||||
|
||||
// TODO tell the parent to not restart
|
||||
} else {
|
||||
let executor = (data.executor_ptr as *mut E).as_mut().unwrap();
|
||||
// disarms timeout in case of TimeoutExecutor
|
||||
executor.post_run_reset();
|
||||
let state = (data.state_ptr as *mut S).as_mut().unwrap();
|
||||
let event_mgr = (data.event_mgr_ptr as *mut EM).as_mut().unwrap();
|
||||
let fuzzer = (data.fuzzer_ptr as *mut Z).as_mut().unwrap();
|
||||
let executor = (data.executor_ptr as *mut E).as_mut().unwrap();
|
||||
let observers = executor.observers_mut();
|
||||
|
||||
let input = (data.current_input_ptr as *const I).as_ref().unwrap();
|
||||
data.current_input_ptr = ptr::null();
|
||||
|
||||
@ -908,8 +908,7 @@ mod windows_exception_handler {
|
||||
events::{Event, EventFirer, EventRestarter},
|
||||
executors::{
|
||||
inprocess::{InProcessExecutorHandlerData, GLOBAL_STATE},
|
||||
timeout::windows_delete_timer_queue,
|
||||
ExitKind, HasObservers,
|
||||
Executor, ExitKind, HasObservers,
|
||||
},
|
||||
feedbacks::Feedback,
|
||||
fuzzer::HasObjective,
|
||||
@ -1053,7 +1052,7 @@ mod windows_exception_handler {
|
||||
exception_pointers: *mut EXCEPTION_POINTERS,
|
||||
data: &mut InProcessExecutorHandlerData,
|
||||
) where
|
||||
E: HasObservers<I, OT, S>,
|
||||
E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
|
||||
EM: EventFirer<I> + EventRestarter<S>,
|
||||
OT: ObserversTuple<I, S>,
|
||||
OF: Feedback<I, S>,
|
||||
@ -1062,7 +1061,7 @@ mod windows_exception_handler {
|
||||
Z: HasObjective<I, OF, S>,
|
||||
{
|
||||
// Have we set a timer_before?
|
||||
if let Some(x) =
|
||||
if let Some(_) =
|
||||
(data.tp_timer as *mut windows::Win32::System::Threading::TP_TIMER).as_mut()
|
||||
{
|
||||
/*
|
||||
@ -1077,9 +1076,6 @@ mod windows_exception_handler {
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
LeaveCriticalSection(data.critical as *mut RTL_CRITICAL_SECTION);
|
||||
compiler_fence(Ordering::SeqCst);
|
||||
|
||||
windows_delete_timer_queue(x);
|
||||
data.tp_timer = ptr::null_mut();
|
||||
}
|
||||
|
||||
let code = ExceptionCode::try_from(
|
||||
@ -1124,10 +1120,16 @@ mod windows_exception_handler {
|
||||
|
||||
// TODO tell the parent to not restart
|
||||
} else {
|
||||
let executor = (data.executor_ptr as *mut E).as_mut().unwrap();
|
||||
// reset timer
|
||||
if !data.tp_timer.is_null() {
|
||||
executor.post_run_reset();
|
||||
data.tp_timer = ptr::null_mut();
|
||||
}
|
||||
|
||||
let state = (data.state_ptr as *mut S).as_mut().unwrap();
|
||||
let event_mgr = (data.event_mgr_ptr as *mut EM).as_mut().unwrap();
|
||||
let fuzzer = (data.fuzzer_ptr as *mut Z).as_mut().unwrap();
|
||||
let executor = (data.executor_ptr as *const E).as_ref().unwrap();
|
||||
let observers = executor.observers();
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
|
@ -95,6 +95,10 @@ where
|
||||
{
|
||||
WithObservers::new(self, observers)
|
||||
}
|
||||
|
||||
/// Custom Reset Handler, e.g., to reset timers
|
||||
#[inline]
|
||||
fn post_run_reset(&mut self) {}
|
||||
}
|
||||
|
||||
/// A simple executor that does nothing.
|
||||
|
@ -18,16 +18,20 @@ use crate::executors::inprocess::{HasInProcessHandlers, GLOBAL_STATE};
|
||||
|
||||
#[cfg(unix)]
|
||||
use core::{mem::zeroed, ptr::null_mut};
|
||||
#[cfg(unix)]
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use core::ptr::{addr_of, addr_of_mut};
|
||||
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
use libc::c_int;
|
||||
|
||||
#[cfg(all(windows, feature = "std"))]
|
||||
use windows::Win32::{
|
||||
Foundation::FILETIME,
|
||||
System::Threading::{
|
||||
CloseThreadpoolTimer, CreateThreadpoolTimer, EnterCriticalSection,
|
||||
InitializeCriticalSection, LeaveCriticalSection, SetThreadpoolTimer, RTL_CRITICAL_SECTION,
|
||||
TP_CALLBACK_ENVIRON_V3, TP_CALLBACK_INSTANCE, TP_TIMER,
|
||||
CreateThreadpoolTimer, EnterCriticalSection, InitializeCriticalSection,
|
||||
LeaveCriticalSection, SetThreadpoolTimer, RTL_CRITICAL_SECTION, TP_CALLBACK_ENVIRON_V3,
|
||||
TP_CALLBACK_INSTANCE, TP_TIMER,
|
||||
},
|
||||
};
|
||||
|
||||
@ -38,13 +42,13 @@ use core::{ffi::c_void, ptr::write_volatile};
|
||||
use core::sync::atomic::{compiler_fence, Ordering};
|
||||
|
||||
#[repr(C)]
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
struct Timeval {
|
||||
pub tv_sec: i64,
|
||||
pub tv_usec: i64,
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
impl Debug for Timeval {
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
@ -59,42 +63,29 @@ impl Debug for Timeval {
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
#[derive(Debug)]
|
||||
struct Itimerval {
|
||||
pub it_interval: Timeval,
|
||||
pub it_value: Timeval,
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
extern "C" {
|
||||
fn setitimer(which: c_int, new_value: *mut Itimerval, old_value: *mut Itimerval) -> c_int;
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
const ITIMER_REAL: c_int = 0;
|
||||
|
||||
/// Reset and remove the timeout
|
||||
#[cfg(unix)]
|
||||
pub(crate) fn unix_remove_timeout() {
|
||||
unsafe {
|
||||
let mut itimerval_zero: Itimerval = zeroed();
|
||||
setitimer(ITIMER_REAL, &mut itimerval_zero, null_mut());
|
||||
}
|
||||
}
|
||||
|
||||
/// Deletes this timer queue
|
||||
/// # Safety
|
||||
/// Will dereference the given `tp_timer` pointer, unchecked.
|
||||
#[cfg(all(windows, feature = "std"))]
|
||||
pub(crate) unsafe fn windows_delete_timer_queue(tp_timer: *mut TP_TIMER) {
|
||||
CloseThreadpoolTimer(tp_timer);
|
||||
}
|
||||
|
||||
/// The timeout excutor is a wrapper that sets a timeout before each run
|
||||
pub struct TimeoutExecutor<E> {
|
||||
executor: E,
|
||||
#[cfg(unix)]
|
||||
#[cfg(target_os = "linux")]
|
||||
itimerspec: libc::itimerspec,
|
||||
#[cfg(target_os = "linux")]
|
||||
timerid: libc::timer_t,
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
itimerval: Itimerval,
|
||||
#[cfg(windows)]
|
||||
milli_sec: i64,
|
||||
@ -113,7 +104,19 @@ impl<E: Debug> Debug for TimeoutExecutor<E> {
|
||||
.finish_non_exhaustive()
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("TimeoutExecutor")
|
||||
.field("executor", &self.executor)
|
||||
.field(
|
||||
"milli_sec",
|
||||
&(&self.itimerspec.it_value.tv_sec * 1000
|
||||
+ &self.itimerspec.it_value.tv_nsec / 1000 / 1000),
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("TimeoutExecutor")
|
||||
.field("executor", &self.executor)
|
||||
@ -130,7 +133,56 @@ type PTP_TIMER_CALLBACK = unsafe extern "system" fn(
|
||||
param2: *mut TP_TIMER,
|
||||
);
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(target_os = "linux")]
|
||||
impl<E> TimeoutExecutor<E> {
|
||||
/// Create a new [`TimeoutExecutor`], wrapping the given `executor` and checking for timeouts.
|
||||
/// This should usually be used for `InProcess` fuzzing.
|
||||
pub fn new(executor: E, exec_tmout: Duration) -> Self {
|
||||
let milli_sec = exec_tmout.as_millis();
|
||||
let it_value = libc::timespec {
|
||||
tv_sec: (milli_sec / 1000) as _,
|
||||
tv_nsec: ((milli_sec % 1000) * 1000 * 1000) as _,
|
||||
};
|
||||
let it_interval = libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
let itimerspec = libc::itimerspec {
|
||||
it_interval,
|
||||
it_value,
|
||||
};
|
||||
let mut timerid: libc::timer_t = null_mut();
|
||||
unsafe {
|
||||
// creates a new per-process interval timer
|
||||
libc::timer_create(libc::CLOCK_MONOTONIC, null_mut(), addr_of_mut!(timerid));
|
||||
}
|
||||
Self {
|
||||
executor,
|
||||
itimerspec,
|
||||
timerid,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the timeout for this executor
|
||||
pub fn set_timeout(&mut self, exec_tmout: Duration) {
|
||||
let milli_sec = exec_tmout.as_millis();
|
||||
let it_value = libc::timespec {
|
||||
tv_sec: (milli_sec / 1000) as _,
|
||||
tv_nsec: ((milli_sec % 1000) * 1000 * 1000) as _,
|
||||
};
|
||||
let it_interval = libc::timespec {
|
||||
tv_sec: 0,
|
||||
tv_nsec: 0,
|
||||
};
|
||||
let itimerspec = libc::itimerspec {
|
||||
it_interval,
|
||||
it_value,
|
||||
};
|
||||
self.itimerspec = itimerspec;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
impl<E> TimeoutExecutor<E> {
|
||||
/// Create a new [`TimeoutExecutor`], wrapping the given `executor` and checking for timeouts.
|
||||
/// This should usually be used for `InProcess` fuzzing.
|
||||
@ -153,6 +205,24 @@ impl<E> TimeoutExecutor<E> {
|
||||
itimerval,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the timeout for this executor
|
||||
pub fn set_timeout(&mut self, exec_tmout: Duration) {
|
||||
let milli_sec = exec_tmout.as_millis();
|
||||
let it_value = Timeval {
|
||||
tv_sec: (milli_sec / 1000) as i64,
|
||||
tv_usec: (milli_sec % 1000) as i64,
|
||||
};
|
||||
let it_interval = Timeval {
|
||||
tv_sec: 0,
|
||||
tv_usec: 0,
|
||||
};
|
||||
let itimerval = Itimerval {
|
||||
it_interval,
|
||||
it_value,
|
||||
};
|
||||
self.itimerval = itimerval;
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@ -183,25 +253,6 @@ impl<E: HasInProcessHandlers> TimeoutExecutor<E> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the timeout for this executor
|
||||
#[cfg(unix)]
|
||||
pub fn set_timeout(&mut self, exec_tmout: Duration) {
|
||||
let milli_sec = exec_tmout.as_millis();
|
||||
let it_value = Timeval {
|
||||
tv_sec: (milli_sec / 1000) as i64,
|
||||
tv_usec: (milli_sec % 1000) as i64,
|
||||
};
|
||||
let it_interval = Timeval {
|
||||
tv_sec: 0,
|
||||
tv_usec: 0,
|
||||
};
|
||||
let itimerval = Itimerval {
|
||||
it_interval,
|
||||
it_value,
|
||||
};
|
||||
self.itimerval = itimerval;
|
||||
}
|
||||
|
||||
/// Set the timeout for this executor
|
||||
#[cfg(windows)]
|
||||
pub fn set_timeout(&mut self, exec_tmout: Duration) {
|
||||
@ -212,15 +263,6 @@ impl<E: HasInProcessHandlers> TimeoutExecutor<E> {
|
||||
pub fn inner(&mut self) -> &mut E {
|
||||
&mut self.executor
|
||||
}
|
||||
|
||||
/// Reset the timeout for this executor
|
||||
#[cfg(windows)]
|
||||
pub fn windows_reset_timeout(&self) -> Result<(), Error> {
|
||||
unsafe {
|
||||
SetThreadpoolTimer(self.tp_timer, core::ptr::null(), 0, 0);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@ -277,13 +319,54 @@ where
|
||||
|
||||
write_volatile(&mut data.timeout_input_ptr, core::ptr::null_mut());
|
||||
|
||||
self.windows_reset_timeout()?;
|
||||
self.post_run_reset();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
/// Deletes this timer queue
|
||||
/// # Safety
|
||||
/// Will dereference the given `tp_timer` pointer, unchecked.
|
||||
fn post_run_reset(&mut self) {
|
||||
unsafe {
|
||||
SetThreadpoolTimer(self.tp_timer, core::ptr::null(), 0, 0);
|
||||
}
|
||||
self.executor.post_run_reset();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(target_os = "linux")]
|
||||
impl<E, EM, I, S, Z> Executor<EM, I, S, Z> for TimeoutExecutor<E>
|
||||
where
|
||||
E: Executor<EM, I, S, Z>,
|
||||
I: Input,
|
||||
{
|
||||
fn run_target(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
state: &mut S,
|
||||
mgr: &mut EM,
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
unsafe {
|
||||
libc::timer_settime(self.timerid, 0, addr_of_mut!(self.itimerspec), null_mut());
|
||||
let ret = self.executor.run_target(fuzzer, state, mgr, input);
|
||||
// reset timer
|
||||
self.post_run_reset();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn post_run_reset(&mut self) {
|
||||
unsafe {
|
||||
let disarmed: libc::itimerspec = zeroed();
|
||||
libc::timer_settime(self.timerid, 0, addr_of!(disarmed), null_mut());
|
||||
}
|
||||
self.executor.post_run_reset();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "linux")))]
|
||||
impl<E, EM, I, S, Z> Executor<EM, I, S, Z> for TimeoutExecutor<E>
|
||||
where
|
||||
E: Executor<EM, I, S, Z>,
|
||||
@ -296,14 +379,21 @@ where
|
||||
mgr: &mut EM,
|
||||
input: &I,
|
||||
) -> Result<ExitKind, Error> {
|
||||
#[cfg(unix)]
|
||||
unsafe {
|
||||
setitimer(ITIMER_REAL, &mut self.itimerval, null_mut());
|
||||
let ret = self.executor.run_target(fuzzer, state, mgr, input);
|
||||
unix_remove_timeout();
|
||||
self.post_run_reset();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
fn post_run_reset(&mut self) {
|
||||
unsafe {
|
||||
let mut itimerval_zero: Itimerval = zeroed();
|
||||
setitimer(ITIMER_REAL, &mut itimerval_zero, null_mut());
|
||||
}
|
||||
self.executor.post_run_reset();
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, I, OT, S> HasObservers<I, OT, S> for TimeoutExecutor<E>
|
||||
@ -321,12 +411,3 @@ where
|
||||
self.executor.observers_mut()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl<E> Drop for TimeoutExecutor<E> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
windows_delete_timer_queue(self.tp_timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -154,6 +154,11 @@ impl CompilerWrapper for ClangWrapper {
|
||||
new_args.push("-lBcrypt".into());
|
||||
new_args.push("-lAdvapi32".into());
|
||||
}
|
||||
// required by timer API (timer_create, timer_settime)
|
||||
#[cfg(target_os = "linux")]
|
||||
if linking {
|
||||
new_args.push("-lrt".into());
|
||||
}
|
||||
// MacOS has odd linker behavior sometimes
|
||||
#[cfg(target_vendor = "apple")]
|
||||
if linking {
|
||||
|
Loading…
x
Reference in New Issue
Block a user