优化停止逻辑
This commit is contained in:
+39
-4
@@ -1,5 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::Ipv4Addr;
|
use std::net::Ipv4Addr;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@@ -33,6 +34,32 @@ use crate::{nat, VntCallback};
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Vnt {
|
pub struct Vnt {
|
||||||
|
inner: Arc<VntInner>,
|
||||||
|
}
|
||||||
|
impl Vnt {
|
||||||
|
#[cfg(feature = "integrated_tun")]
|
||||||
|
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
|
||||||
|
let inner = Arc::new(VntInner::new(config, callback)?);
|
||||||
|
Ok(Self { inner })
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "integrated_tun"))]
|
||||||
|
pub fn new_device<Call: VntCallback, Device: DeviceWrite>(
|
||||||
|
config: Config,
|
||||||
|
callback: Call,
|
||||||
|
device: Device,
|
||||||
|
) -> anyhow::Result<Self> {
|
||||||
|
let inner = Arc::new(VntInner::new_device(config, callback, device)?);
|
||||||
|
Ok(Self { inner })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Deref for Vnt {
|
||||||
|
type Target = VntInner;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub struct VntInner {
|
||||||
stop_manager: StopManager,
|
stop_manager: StopManager,
|
||||||
config: Config,
|
config: Config,
|
||||||
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
current_device: Arc<AtomicCell<CurrentDeviceInfo>>,
|
||||||
@@ -48,10 +75,10 @@ pub struct Vnt {
|
|||||||
external_route: ExternalRoute,
|
external_route: ExternalRoute,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vnt {
|
impl VntInner {
|
||||||
#[cfg(feature = "integrated_tun")]
|
#[cfg(feature = "integrated_tun")]
|
||||||
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
|
pub fn new<Call: VntCallback>(config: Config, callback: Call) -> anyhow::Result<Self> {
|
||||||
Vnt::new_device0(config, callback, DeviceAdapter::default())
|
VntInner::new_device0(config, callback, DeviceAdapter::default())
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "integrated_tun"))]
|
#[cfg(not(feature = "integrated_tun"))]
|
||||||
pub fn new_device<Call: VntCallback, Device: DeviceWrite>(
|
pub fn new_device<Call: VntCallback, Device: DeviceWrite>(
|
||||||
@@ -59,7 +86,7 @@ impl Vnt {
|
|||||||
callback: Call,
|
callback: Call,
|
||||||
device: Device,
|
device: Device,
|
||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
Vnt::new_device0(config, callback, device)
|
VntInner::new_device0(config, callback, device)
|
||||||
}
|
}
|
||||||
fn new_device0<Call: VntCallback, Device: DeviceWrite>(
|
fn new_device0<Call: VntCallback, Device: DeviceWrite>(
|
||||||
config: Config,
|
config: Config,
|
||||||
@@ -384,7 +411,7 @@ pub fn start<Call: VntCallback>(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vnt {
|
impl VntInner {
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.config.name
|
&self.config.name
|
||||||
}
|
}
|
||||||
@@ -449,6 +476,9 @@ impl Vnt {
|
|||||||
let _ = self.context.lock().take();
|
let _ = self.context.lock().take();
|
||||||
self.stop_manager.stop()
|
self.stop_manager.stop()
|
||||||
}
|
}
|
||||||
|
pub fn is_stopped(&self) -> bool {
|
||||||
|
self.stop_manager.is_stopped()
|
||||||
|
}
|
||||||
pub fn add_stop_listener<F>(&self, name: String, f: F) -> anyhow::Result<crate::util::Worker>
|
pub fn add_stop_listener<F>(&self, name: String, f: F) -> anyhow::Result<crate::util::Worker>
|
||||||
where
|
where
|
||||||
F: FnOnce() + Send + 'static,
|
F: FnOnce() + Send + 'static,
|
||||||
@@ -478,3 +508,8 @@ impl Vnt {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl Drop for VntInner {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ impl StopManager {
|
|||||||
pub fn wait_timeout(&self, dur: Duration) -> bool {
|
pub fn wait_timeout(&self, dur: Duration) -> bool {
|
||||||
self.inner.wait_timeout(dur)
|
self.inner.wait_timeout(dur)
|
||||||
}
|
}
|
||||||
pub fn is_stop(&self) -> bool {
|
pub fn is_stopped(&self) -> bool {
|
||||||
self.inner.state.load(Ordering::Acquire)
|
self.inner.is_stopped()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,6 +89,9 @@ impl StopManagerInner {
|
|||||||
listener();
|
listener();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn is_stopped(&self) -> bool {
|
||||||
|
self.worker_num.load(Ordering::Acquire) == 0
|
||||||
|
}
|
||||||
fn wait(&self) {
|
fn wait(&self) {
|
||||||
{
|
{
|
||||||
let mut guard = self.park_threads.lock();
|
let mut guard = self.park_threads.lock();
|
||||||
@@ -115,6 +118,7 @@ impl StopManagerInner {
|
|||||||
self.worker_num.load(Ordering::Acquire) == 0
|
self.worker_num.load(Ordering::Acquire) == 0
|
||||||
}
|
}
|
||||||
fn stop_call(&self) {
|
fn stop_call(&self) {
|
||||||
|
self.stop();
|
||||||
if let Some(call) = self.stop_call.lock().take() {
|
if let Some(call) = self.stop_call.lock().take() {
|
||||||
call();
|
call();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
use crate::util::StopManager;
|
use crate::util::StopManager;
|
||||||
|
use crossbeam_utils::atomic::AtomicCell;
|
||||||
use std::collections::BinaryHeap;
|
use std::collections::BinaryHeap;
|
||||||
|
use std::sync::mpsc::TrySendError;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Ordering,
|
cmp::Ordering,
|
||||||
sync::mpsc::{sync_channel, Receiver, SyncSender},
|
sync::mpsc::{sync_channel, Receiver, SyncSender},
|
||||||
@@ -10,45 +13,62 @@ struct DelayedTask {
|
|||||||
f: Box<dyn FnOnce(&Scheduler) + Send>,
|
f: Box<dyn FnOnce(&Scheduler) + Send>,
|
||||||
next: Instant,
|
next: Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for DelayedTask {}
|
impl Eq for DelayedTask {}
|
||||||
|
|
||||||
impl PartialEq for DelayedTask {
|
impl PartialEq for DelayedTask {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.next.eq(&other.next)
|
self.next.eq(&other.next)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for DelayedTask {
|
impl PartialOrd for DelayedTask {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
self.next.partial_cmp(&other.next).map(|ord| ord.reverse())
|
self.next.partial_cmp(&other.next).map(|ord| ord.reverse())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for DelayedTask {
|
impl Ord for DelayedTask {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
self.next.cmp(&other.next).reverse()
|
self.next.cmp(&other.next).reverse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Op {
|
enum Op {
|
||||||
Task(DelayedTask),
|
Task(DelayedTask),
|
||||||
Stop,
|
Stop,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Scheduler {
|
pub struct Scheduler {
|
||||||
sender: SyncSender<Op>,
|
sender: SyncSender<Op>,
|
||||||
|
state: Arc<AtomicCell<SchedulerState>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
|
enum SchedulerState {
|
||||||
|
Running,
|
||||||
|
ShutdownNow, // 立即停止任务执行,队列中剩余的任务不再执行
|
||||||
|
_Shutdown, //执行完队列中剩余的任务再停止
|
||||||
|
}
|
||||||
|
|
||||||
impl Scheduler {
|
impl Scheduler {
|
||||||
pub fn new(stop_manager: StopManager) -> anyhow::Result<Self> {
|
pub fn new(stop_manager: StopManager) -> anyhow::Result<Self> {
|
||||||
let (sender, receiver) = sync_channel::<Op>(32);
|
let (sender, receiver) = sync_channel::<Op>(32);
|
||||||
let s = Self { sender };
|
let state = Arc::new(AtomicCell::new(SchedulerState::Running));
|
||||||
|
let s = Self { sender, state };
|
||||||
let s_inner = s.clone();
|
let s_inner = s.clone();
|
||||||
let worker = {
|
let worker = {
|
||||||
let scheduler = s.clone();
|
let scheduler = s.clone();
|
||||||
stop_manager.add_listener("Scheduler".into(), move || {
|
stop_manager.add_listener("Scheduler".into(), move || {
|
||||||
scheduler.shutdown();
|
scheduler.shutdown_now();
|
||||||
})?
|
})?
|
||||||
};
|
};
|
||||||
std::thread::Builder::new()
|
std::thread::Builder::new()
|
||||||
.name("Scheduler".into())
|
.name("Scheduler".into())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
run(receiver, s_inner);
|
run(receiver, &s_inner);
|
||||||
|
s_inner.shutdown_now();
|
||||||
worker.stop_all();
|
worker.stop_all();
|
||||||
})
|
})
|
||||||
.expect("Scheduler");
|
.expect("Scheduler");
|
||||||
@@ -58,20 +78,44 @@ impl Scheduler {
|
|||||||
where
|
where
|
||||||
F: FnOnce(&Scheduler) + Send + 'static,
|
F: FnOnce(&Scheduler) + Send + 'static,
|
||||||
{
|
{
|
||||||
|
if self.state.load() != SchedulerState::Running {
|
||||||
|
log::error!("定时任务执行停止");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
let task = DelayedTask {
|
let task = DelayedTask {
|
||||||
f: Box::new(f),
|
f: Box::new(f),
|
||||||
next: Instant::now().checked_add(time).unwrap(),
|
next: Instant::now().checked_add(time).unwrap(),
|
||||||
};
|
};
|
||||||
self.sender.send(Op::Task(task)).is_ok()
|
// 如果是任务中调用此方法,那这里用send可能会导致整个定时任务阻塞
|
||||||
|
// 任务总数不能大于或等于通道长度,所以改成try_send快速失败
|
||||||
|
match self.sender.try_send(Op::Task(task)) {
|
||||||
|
Ok(_) => true,
|
||||||
|
Err(e) => {
|
||||||
|
match e {
|
||||||
|
TrySendError::Full(_) => {
|
||||||
|
log::error!("定时任务队列达到上限");
|
||||||
|
}
|
||||||
|
TrySendError::Disconnected(_) => {
|
||||||
|
log::error!("定时任务执行停止 通道关闭");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
pub fn shutdown(self) {
|
pub fn shutdown_now(&self) {
|
||||||
|
self.state.store(SchedulerState::ShutdownNow);
|
||||||
let _ = self.sender.send(Op::Stop);
|
let _ = self.sender.send(Op::Stop);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn run(receiver: Receiver<Op>, s_inner: Scheduler) {
|
|
||||||
|
fn run(receiver: Receiver<Op>, s_inner: &Scheduler) {
|
||||||
let mut binary_heap = BinaryHeap::<DelayedTask>::with_capacity(32);
|
let mut binary_heap = BinaryHeap::<DelayedTask>::with_capacity(32);
|
||||||
loop {
|
loop {
|
||||||
while let Some(task) = binary_heap.peek() {
|
while let Some(task) = binary_heap.peek() {
|
||||||
|
if s_inner.state.load() == SchedulerState::ShutdownNow {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
if now < task.next {
|
if now < task.next {
|
||||||
//需要等待对应时间
|
//需要等待对应时间
|
||||||
@@ -89,7 +133,7 @@ fn run(receiver: Receiver<Op>, s_inner: Scheduler) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if let Some(task) = binary_heap.pop() {
|
if let Some(task) = binary_heap.pop() {
|
||||||
(task.f)(&s_inner);
|
(task.f)(s_inner);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,6 +164,7 @@ fn run(receiver: Receiver<Op>, s_inner: Scheduler) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_task(op: Op, binary_heap: &mut BinaryHeap<DelayedTask>) -> bool {
|
fn add_task(op: Op, binary_heap: &mut BinaryHeap<DelayedTask>) -> bool {
|
||||||
return match op {
|
return match op {
|
||||||
Op::Task(task) => {
|
Op::Task(task) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user