Skip to content

Commit

Permalink
feat(unit/timer_unit) :First step implementation of timer unit #41 (#44)
Browse files Browse the repository at this point in the history
实现timer类型的unit

Co-authored-by: BrahmaMantra <2033552517.qq.com>
  • Loading branch information
BrahmaMantra authored May 20, 2024
1 parent 01cdc56 commit 2069cc0
Show file tree
Hide file tree
Showing 20 changed files with 900 additions and 46 deletions.
16 changes: 16 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/<executable file>",
"args": [],
"cwd": "${workspaceFolder}"
}
]
}
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ hashbrown = "0.11"
cfg-if = { version = "1.0" }
lazy_static = { version = "1.4.0" }
libc = "0.2"
humantime = "2.1"

[profile.release]
panic = 'abort'
Expand Down
7 changes: 7 additions & 0 deletions parse_test/test_timer_unit.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[Unit]
Description=a test for timer_unit

[Service]
Type=simple
ExecStart=-/bin/about.elf
ExecStartPre=-/bin/clear
7 changes: 7 additions & 0 deletions parse_test/test_timer_unit.timer
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[Unit]
Description=a timer for the same_name.service

[Timer]
OnActiveSec=3s
OnUnitActiveSec=5s
Unit=test_timer_unit.service
6 changes: 3 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ mod time;
mod unit;

use error::ErrorFormat;
use executor::Executor;
use manager::{timer_manager::TimerManager, Manager};
use parse::UnitParser;
use systemctl::listener::Systemctl;

use crate::executor::Executor;

pub struct FileDescriptor(usize);

const DRAGON_REACH_UNIT_DIR: &'static str = "/etc/reach/system/";

fn main() {
// 初始化
Systemctl::init();
Expand Down Expand Up @@ -46,12 +46,12 @@ fn main() {
0
}
};

if id != 0 {
if let Err(e) = Executor::exec(id) {
eprintln!("Err:{}", e.error_format());
}
}
println!("Parse {} success!", path);
}

// 启动完服务后进入主循环
Expand Down
9 changes: 8 additions & 1 deletion src/manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ impl Manager {
match proc.try_wait() {
//进程正常退出
Ok(Some(status)) => {
//TODO:交付给相应类型的Unit类型去执行退出后的逻辑
exited_unit.push((
*unit.0,
ExitStatus::from_exit_code(status.code().unwrap_or(0)),
Expand Down Expand Up @@ -49,6 +48,14 @@ impl Manager {
// 取消该任务的定时器任务
TimerManager::cancel_timer(tmp.0);

let _ = UnitManager::get_unit_with_id(&tmp.0)
.unwrap()
.lock()
.unwrap()
.exit(); //交付给相应类型的Unit类型去执行退出后的逻辑

TimerManager::update_next_trigger(tmp.0, false); //更新所有归属于此unit的计时器

// 交付处理子进程退出逻辑
let unit = UnitManager::get_unit_with_id(&tmp.0).unwrap();
unit.lock().unwrap().after_exit(tmp.1);
Expand Down
137 changes: 131 additions & 6 deletions src/manager/timer_manager/mod.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
use std::{sync::RwLock, time::Duration};
use std::{
sync::{Arc, Mutex, RwLock},
time::Duration,
};

use crate::{error::runtime_error::RuntimeError, time::timer::Timer};
use crate::{
error::runtime_error::RuntimeError, time::timer::Timer, unit::timer::TimerUnit, unit::Unit,
};
use hashbrown::HashMap;
use lazy_static::lazy_static;

lazy_static! {
// 管理全局计时器任务
static ref TIMER_TASK_MANAGER: RwLock<TimerManager> = RwLock::new(TimerManager {
inner_timers: Vec::new()
static ref TIMER_TASK_MANAGER:RwLock<TimerManager> = RwLock::new(TimerManager {
inner_timers: Vec::new(),
timer_unit_map: RwLock::new(HashMap::new()),

id_table:RwLock::new(Vec::new())
});
}

pub struct TimerManager {
inner_timers: Vec<Timer>,
timer_unit_map: RwLock<HashMap<usize, Arc<Mutex<TimerUnit>>>>, //id->TimerUnit
id_table: RwLock<Vec<(usize, usize)>>, //.0是TimerUnit的id,.1是父Unit的id
}

impl<'a> IntoIterator for &'a mut TimerManager {
Expand All @@ -27,7 +37,7 @@ impl<'a> IntoIterator for &'a mut TimerManager {
impl TimerManager {
/// ## 添加定时器任务
///
/// 只有通过这个方式创建的Timer对象才会真正的实现计时
/// 只有通过两这个方式载入的Timer或Timer_unit对象才会真正的实现计时
pub fn push_timer<F>(duration: Duration, callback: F, parent: usize)
where
F: FnMut() -> Result<(), RuntimeError> + Send + Sync + 'static,
Expand All @@ -39,13 +49,57 @@ impl TimerManager {
.push(Timer::new(duration, Box::new(callback), parent));
}

pub fn push_timer_unit(unit: Arc<Mutex<TimerUnit>>) {
let timemanager = TIMER_TASK_MANAGER.write().unwrap();
let mut unit_guard = unit.lock().unwrap();
let unit_id = unit_guard.unit_id();
timemanager
.id_table
.write()
.unwrap()
.push((unit_id, unit_guard.get_parent_unit()));
drop(unit_guard);
timemanager
.timer_unit_map
.write()
.unwrap()
.insert(unit_id, unit); //加入到inner_timers_map
}

/// ## 检测定时器是否到时,到时则触发
///
/// 该方法在主循环中每循环一次检测一次,是伪计时器的主运行函数
pub fn check_timer() {
let mut writer = TIMER_TASK_MANAGER.write().unwrap();
//此处触发定时器,若定时器被触发,则移除
writer.inner_timers.retain_mut(|x| !x.check());
drop(writer);
//此处触发Timer_unit,不移除
let reader = TIMER_TASK_MANAGER.read().unwrap();
let timer_unit_map = reader.timer_unit_map.read().unwrap();
let mut inactive_unit: Vec<usize> = Vec::new();
for (_, timer_unit) in timer_unit_map.iter() {
let mut unit_guard = timer_unit.lock().unwrap();
if unit_guard.enter_inactive() {
inactive_unit.push(unit_guard.unit_id());
continue;
}
if unit_guard.check() {
//println!("unit id : {} , parent id : {} ",timer_unit.unit_id(),timer_unit.get_parent_unit());
let _ = unit_guard._run(); //运行作出相应操作
let id = unit_guard.get_parent_unit();
drop(unit_guard);
TimerManager::update_next_trigger(id, true); //更新触发时间
}
}

for id in inactive_unit {
//处理Inactive需要退出的计时器
//println!("Prepared to exit...");
timer_unit_map.get(&id).unwrap().lock().unwrap().exit();

TimerManager::remove_timer_unit(id);
}
}

/// ## 取消掉一个unit的所有定时任务,
Expand All @@ -58,4 +112,75 @@ impl TimerManager {
.inner_timers
.retain(|x| x.parent() == unit_id)
}

pub fn is_timer(id: &usize) -> bool {
let id_table = &TIMER_TASK_MANAGER.read().unwrap().id_table;
for iter in id_table.read().unwrap().iter() {
if iter.0 == *id {
return true;
}
}
false
}
/// unit_id:父unit的id flag:1为exec 0为exit
fn adjust_timevalue(unit_id: &usize, flag: bool /*1为启动0为退出 */) -> Vec<usize> {
let mut result = Vec::new();
let manager = TIMER_TASK_MANAGER.read().unwrap();
for (self_id, parent_id) in manager.id_table.read().unwrap().iter() {
if unit_id == parent_id {
let timer_unit_map = manager.timer_unit_map.read().unwrap();
let mut timer_unit = timer_unit_map.get(self_id).unwrap().lock().unwrap();
timer_unit.change_stage(flag);
result.push(*self_id);
}
}
result
}

/// 从Timer表中删除该Unit
pub fn remove_timer_unit(unit_id: usize) {
let manager = TIMER_TASK_MANAGER.read().unwrap();

manager.timer_unit_map.write().unwrap().remove(&unit_id);
let mut index: usize = 0;
let mut id_table = manager.id_table.write().unwrap();
for (self_id, _) in id_table.iter() {
//因为id是递增的,后续可优化为二分查找
if unit_id == *self_id {
id_table.remove(index);
println!("remove id:{}", unit_id);
return;
}
index = index + 1
}
}

/// 获得该id下的所有计时器
pub fn get_timer(parent_id: usize) -> Vec<usize> {
let mut result = Vec::new();
let timer_manager = TIMER_TASK_MANAGER.read().unwrap();
let reader = timer_manager.id_table.read().unwrap();
for (timer_id, id) in reader.iter() {
if *id == parent_id {
result.push(*timer_id);
}
}
result
}
///此时传入的是parent_id
pub fn update_next_trigger(unit_id: usize, flag: bool) {
let timer_vec = Self::adjust_timevalue(&unit_id, flag);

let timer_manager = TIMER_TASK_MANAGER.read().unwrap();
let timer_unit_map = timer_manager.timer_unit_map.read().unwrap();
timer_vec.iter().for_each(|id| {
timer_unit_map
.get(id)
.unwrap()
.lock()
.unwrap()
.mut_timer_part()
.update_next_trigger();
});
}
}
13 changes: 7 additions & 6 deletions src/manager/unit_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@ use hashbrown::HashMap;
use lazy_static::lazy_static;

lazy_static! {
// 对于启动后即使退出亦认为其为运行状态的特殊注册类Service,对于这类进程做一个标记
/// 对于启动后即使退出亦认为其为运行状态的特殊注册类Service,对于这类进程做一个标记
static ref FLAG_RUNNING: RwLock<Vec<usize>> = RwLock::new(Vec::new());

// 任务等待队列,IDLE类型的service入队等待其它任务完成再执行
/// 任务等待队列,IDLE类型的service入队等待其它任务完成再执行
static ref IDLE_SERVIEC_DEQUE: Mutex<VecDeque<usize>> = Mutex::new(VecDeque::new());

// id到unit的映射表,全局的Unit管理表
/// id到unit的映射表,全局的Unit管理表
pub(super) static ref ID_TO_UNIT_MAP: RwLock<HashMap<usize,Arc<Mutex<dyn Unit>>>> = RwLock::new(HashMap::new());

// 辅助表,通过服务名映射其id
/// 辅助表,通过服务名映射其id
static ref NAME_TO_UNIT_MAP: RwLock<HashMap<u64,usize>> = RwLock::new(HashMap::new());

// 全局运行中的Unit表
/// 全局运行中的Unit表
pub(super) static ref RUNNING_TABLE: RwLock<RunningTableManager> = RwLock::new(RunningTableManager { running_table: HashMap::new() });

// CMD进程表,用于处理Unit的CMD派生进程(ExecStartPre等命令派生进程)
/// CMD进程表,用于处理Unit的CMD派生进程(ExecStartPre等命令派生进程)
pub(super) static ref CMD_PROCESS_TABLE: RwLock<HashMap<u32,Mutex<Child>>> = RwLock::new(HashMap::new());
}

Expand Down Expand Up @@ -92,6 +92,7 @@ impl UnitManager {
}

// 通过id获取到path
// ↑感觉是笔误,应该是通过path获取到id
pub fn get_id_with_path(path: &str) -> Option<usize> {
let mut hasher = DefaultHasher::new();
path.hash(&mut hasher);
Expand Down
16 changes: 13 additions & 3 deletions src/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ use lazy_static::lazy_static;

use self::parse_service::ServiceParser;
use self::parse_target::TargetParser;
use self::parse_timer::TimerParser;
use self::parse_util::UnitParseUtil;

pub mod graph;
pub mod parse_service;
pub mod parse_target;
pub mod parse_timer;
pub mod parse_util;

//对应Unit段类型
Expand All @@ -31,6 +33,7 @@ pub enum Segment {
Unit,
Install,
Service,
Timer,
}

lazy_static! {
Expand All @@ -42,8 +45,8 @@ lazy_static! {
table.insert("path", UnitType::Path);
table.insert("scope", UnitType::Scope);
table.insert("service", UnitType::Service);
table.insert("slice", UnitType::Automount);
table.insert("automount", UnitType::Slice);
table.insert("slice", UnitType::Automount);//疑似copy错了,稍后修改
table.insert("automount", UnitType::Slice);//
table.insert("socket", UnitType::Socket);
table.insert("swap", UnitType::Swap);
table.insert("target", UnitType::Target);
Expand All @@ -55,6 +58,8 @@ lazy_static! {
table.insert("[Unit]", Segment::Unit);
table.insert("[Install]", Segment::Install);
table.insert("[Service]", Segment::Service);
table.insert("[Timer]", Segment::Timer);
// 后续再添加需求的具体字段
table
};
pub static ref INSTALL_UNIT_ATTR_TABLE: HashMap<&'static str, InstallUnitAttr> = {
Expand Down Expand Up @@ -147,10 +152,12 @@ lazy_static! {
};
pub static ref TIMER_UNIT_ATTR_TABLE: HashMap<&'static str, TimerUnitAttr> = {
let mut map = HashMap::new();
// map.insert("State", TimerUnitAttr::State);
// map.insert("Result", TimerUnitAttr::Result);
map.insert("OnActiveSec", TimerUnitAttr::OnActiveSec);
map.insert("OnBootSec", TimerUnitAttr::OnBootSec);
map.insert("OnStartupSec", TimerUnitAttr::OnStartUpSec);
map.insert("OnUnitActiveSec", TimerUnitAttr::OnUnitInactiveSec);
map.insert("OnUnitActiveSec", TimerUnitAttr::OnUnitActiveSec);
map.insert("OnUnitInactiveSec", TimerUnitAttr::OnUnitInactiveSec);
map.insert("OnCalendar", TimerUnitAttr::OnCalendar);
map.insert("AccuracySec", TimerUnitAttr::AccuarcySec);
Expand Down Expand Up @@ -216,6 +223,7 @@ impl UnitParser {
match unit_type {
UnitType::Service => ServiceParser::parse(path),
UnitType::Target => TargetParser::parse(path),
UnitType::Timer => TimerParser::parse(path), //新实现的timer_unit
_ => Err(ParseError::new(ParseErrorType::EFILE, path.to_string(), 0)),
}
}
Expand Down Expand Up @@ -318,6 +326,7 @@ impl UnitParser {
};
//首先匹配所有unit文件都有的unit段和install段
if BASE_UNIT_ATTR_TABLE.get(attr_str).is_some() {
//匹配Unit字段
if segment != Segment::Unit {
return Err(ParseError::new(
ParseErrorType::EINVAL,
Expand All @@ -334,6 +343,7 @@ impl UnitParser {
return Err(e);
}
} else if INSTALL_UNIT_ATTR_TABLE.get(attr_str).is_some() {
//匹配Install字段
if segment != Segment::Install {
return Err(ParseError::new(
ParseErrorType::EINVAL,
Expand Down
Loading

0 comments on commit 2069cc0

Please sign in to comment.