From 88a6210ab4ecb06659342684b4f8e3b51f254c84 Mon Sep 17 00:00:00 2001 From: huyubiao Date: Fri, 17 Nov 2023 21:20:49 +0800 Subject: [PATCH] feature(devmaster): Add subcommands for devctl settle --- Cargo.lock | 2 +- core/coms/service/Cargo.toml | 1 + core/coms/service/src/config.rs | 2 +- core/coms/service/src/rentry.rs | 2 +- exts/devmaster/Cargo.toml | 1 + exts/devmaster/src/bin/devctl/main.rs | 32 +- .../src/bin/devctl/subcmds/devctl_settle.rs | 262 ++++++++++++++ .../src/bin/devctl/subcmds/devctl_utils.rs | 14 + exts/devmaster/src/bin/devctl/subcmds/mod.rs | 1 + .../src/lib/framework/control_manager.rs | 5 + libs/basic/Cargo.toml | 2 + libs/basic/src/lib.rs | 2 + libs/basic/src/time_util.rs | 323 ++++++++++++++++++ libs/constants/src/lib.rs | 9 - libs/event/Cargo.toml | 2 +- libs/event/src/timer.rs | 2 +- 16 files changed, 646 insertions(+), 16 deletions(-) create mode 100644 exts/devmaster/src/bin/devctl/subcmds/devctl_settle.rs create mode 100644 libs/basic/src/time_util.rs diff --git a/Cargo.lock b/Cargo.lock index f2fa0618..60b3401f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -490,7 +490,7 @@ dependencies = [ name = "event" version = "0.5.1" dependencies = [ - "constants", + "basic", "libc", "libtests", "nix 0.24.3", diff --git a/core/coms/service/Cargo.toml b/core/coms/service/Cargo.toml index f60b58c4..408fa075 100644 --- a/core/coms/service/Cargo.toml +++ b/core/coms/service/Cargo.toml @@ -15,6 +15,7 @@ basic = { path = "../../../libs/basic", default-features = false, features = [ "fs", "fd", "unit_name", + "time_util", ] } cgroup = { path = "../../../libs/cgroup", default-features = false } constants = { path = "../../../libs/constants" } diff --git a/core/coms/service/src/config.rs b/core/coms/service/src/config.rs index e69ba089..c3f2d2b1 100644 --- a/core/coms/service/src/config.rs +++ b/core/coms/service/src/config.rs @@ -14,7 +14,7 @@ use super::comm::ServiceUnitComm; use super::rentry::{NotifyAccess, SectionService, ServiceCommand, ServiceType}; use basic::unit_name::unit_name_to_instance; -use constants::{USEC_INFINITY, USEC_PER_SEC}; +use basic::time_util::{USEC_INFINITY, USEC_PER_SEC}; use core::error::*; use core::exec::ExecCommand; use core::rel::ReStation; diff --git a/core/coms/service/src/rentry.rs b/core/coms/service/src/rentry.rs index b4f18e58..46940bfb 100644 --- a/core/coms/service/src/rentry.rs +++ b/core/coms/service/src/rentry.rs @@ -34,7 +34,7 @@ use core::rel::{ReDb, ReDbRwTxn, ReDbTable, Reliability}; use core::unit::KillMode; use basic::EXEC_RUNTIME_PREFIX; -use constants::USEC_PER_SEC; +use basic::time_util::USEC_PER_SEC; struct ServiceReDb(ReDb); diff --git a/exts/devmaster/Cargo.toml b/exts/devmaster/Cargo.toml index c52e9880..4a3a8176 100644 --- a/exts/devmaster/Cargo.toml +++ b/exts/devmaster/Cargo.toml @@ -32,6 +32,7 @@ basic = { path = "../../libs/basic", default-features = false, features = [ "socket", "io", "argv", + "time_util", ] } blkid_rs = { path = "../../libs/blkid_rs" } device = { path = "../../libs/device" } diff --git a/exts/devmaster/src/bin/devctl/main.rs b/exts/devmaster/src/bin/devctl/main.rs index 17645ee6..3994bf01 100644 --- a/exts/devmaster/src/bin/devctl/main.rs +++ b/exts/devmaster/src/bin/devctl/main.rs @@ -27,6 +27,7 @@ use subcmds::devctl_info::InfoArgs; use subcmds::devctl_monitor::subcommand_monitor; use subcmds::devctl_test_builtin::subcommand_test_builtin; use subcmds::devctl_trigger::TriggerArgs; +use subcmds::devctl_settle::SettleArgs; use subcmds::Result; /// parse program arguments @@ -169,8 +170,24 @@ enum SubCmd { devices: Vec, }, - /// Test builtin command on a device + /// Kill all devmaster workers #[clap(display_order = 5)] + Settle { + /// Maximum time to wait for events + #[clap(short('t'), long)] + timeout: Option, + + /// Stop waiting if file exists + #[clap(short('E'), long)] + exit_if_exists: Option, + + /// other args + #[clap(required = false)] + other: Vec, + }, + + /// Test builtin command on a device + #[clap(display_order = 6)] TestBuiltin { /// device action #[clap(short, long)] @@ -183,7 +200,7 @@ enum SubCmd { syspath: String, }, /// Test builtin command on a device - #[clap(display_order = 6)] + #[clap(display_order = 7)] Hwdb { /// update the hardware database #[clap(short('u'), long)] @@ -287,6 +304,17 @@ fn main() -> Result<()> { ) .subcommand() } + SubCmd::Settle { + timeout, + exit_if_exists, + other, + } => { + return SettleArgs::new( + timeout, + exit_if_exists, + other, + ).subcommand(); + } SubCmd::TestBuiltin { action, builtin, diff --git a/exts/devmaster/src/bin/devctl/subcmds/devctl_settle.rs b/exts/devmaster/src/bin/devctl/subcmds/devctl_settle.rs new file mode 100644 index 00000000..f21cc959 --- /dev/null +++ b/exts/devmaster/src/bin/devctl/subcmds/devctl_settle.rs @@ -0,0 +1,262 @@ +// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved. +// +// sysMaster is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +//! subcommand for devctl settle +//! + +use crate::Result; +use event::{EventState, EventType, Events, Source}; +use nix::unistd::{AccessFlags, access, getuid}; +use std::os::unix::io::RawFd; +use std::rc::Rc; +use libdevmaster::framework::control_manager::CONTROL_MANAGER_LISTEN_ADDR; +use std::os::unix::net::UnixStream; +use std::io::Write; +use nix::sys::inotify::AddWatchFlags; +use crate::subcmds::devctl_utils::devmaster_queue_is_empty; +use basic::time_util; + + +#[derive(Debug)] +pub struct SettleArgs { + timeout: Option, + exit_if_exists: Option, + _other: Vec, +} + +impl SettleArgs { + pub fn new( + timeout: Option, + exit_if_exists: Option, + _other: Vec, + ) -> Self { + SettleArgs { + timeout, + exit_if_exists, + _other, + } + } + + /// subcommand for Wait for pending udev events + pub fn subcommand(&self) -> Result<()> { + let timeout = match &self.timeout { + Some(timeout) => { + let d = match time_util::parse_sec(&timeout) { + Ok(d) => { + println!("{:?}", d); + d + } + Err(err) => { + log::error!("Failed to parse timeout value:{:?} err:{:?}", timeout, err); + return Err(err); + }, + }; + d + } + None => 0, + }; + + // TODO: emit_deprecation_warning(); dbus is not currently implemented + + if 0 == getuid().as_raw() { + /* guarantee that the udev daemon isn't pre-processing */ + let mut stream = match UnixStream::connect(CONTROL_MANAGER_LISTEN_ADDR) { + Ok(stream) => stream, + Err(err) => { + log::error!("Failed to connect to udev daemon, ignoring err:{:?}", err); + return Ok(()); + } + }; + if let Err(err) = stream.write_all(b"ping ") { + log::error!("Failed to ping to udev daemon, err:{:?}", err); + return Ok(()); + } + } else { + /* For non-privileged users, at least check if udevd is running. */ + if let Err(err) = access(CONTROL_MANAGER_LISTEN_ADDR, AccessFlags::F_OK) { + if err == nix::Error::ENOENT { + log::error!("sysmaster is not running err:{:?}", err); + } else { + log::error!("Failed to check if {} exists err:{:?}", CONTROL_MANAGER_LISTEN_ADDR, err); + } + return Err(err); + } + } + + + let events = Events::new().unwrap(); + if timeout != time_util::USEC_INFINITY { + let time: Rc = Rc::new(Timer::new(timeout)); + events.add_source(time.clone()).unwrap(); + events.set_enabled(time.clone(), EventState::OneShot).unwrap(); + } + + let _wd = events.add_watch("/run/devmaster", AddWatchFlags::IN_DELETE); + let s: Rc = Rc::new(Inotify::new(self.exit_if_exists.clone())); + + events.add_source(s.clone()).unwrap(); + events.set_enabled(s.clone(), EventState::On).unwrap(); + + /* Check before entering the event loop, as the udev queue may be already empty. */ + if check(&self.exit_if_exists) { + return Ok(()); + } + + events.rloop().unwrap(); + + Ok(()) + } +} + +/// trigger monitor +#[derive(Debug)] +struct Inotify { + exit_if_exists: Option, +} + +/// public methods +impl Inotify { + /// create a monitor instance for monitoring trigger + pub fn new(exit_if_exists: Option) -> Self { + Inotify { + exit_if_exists, + } + } +} + +impl Source for Inotify { + /// socket fd + fn fd(&self) -> RawFd { + 0 + } + + /// event type + fn event_type(&self) -> EventType { + EventType::Inotify + } + + /// epoll type + fn epoll_event(&self) -> u32 { + (libc::EPOLLIN) as u32 + } + + /// priority of event source + fn priority(&self) -> i8 { + 0i8 + } + + fn time_relative(&self) -> u64 { + 0 + } + + /// receive device from socket and remove path or uuid from settle_path_or_ids + fn dispatch(&self, event: &Events) -> i32 { + println!("IN_DELETE"); + + let _events = event.read_events(); + + if check(&self.exit_if_exists) { + event.set_exit(); + } + + 0 + } + + /// token of event source + fn token(&self) -> u64 { + let data: u64 = unsafe { std::mem::transmute(self) }; + data + } +} + + +/// trigger monitor +#[derive(Debug)] +struct Timer { + time_usec: u64, +} + +/// public methods +impl Timer { + /// create a monitor instance for monitoring trigger + pub fn new(time_usec: u64) -> Self { + Timer { + time_usec, + } + } +} + +impl Source for Timer { + /// socket fd + fn fd(&self) -> RawFd { + 0 + } + + /// event type + fn event_type(&self) -> EventType { + EventType::TimerBoottime + } + + /// epoll type + fn epoll_event(&self) -> u32 { + (libc::EPOLLIN) as u32 + } + + /// priority of event source + fn priority(&self) -> i8 { + 0i8 + } + + fn time_relative(&self) -> u64 { + self.time_usec + } + + /// receive device from socket and remove path or uuid from settle_path_or_ids + fn dispatch(&self, event: &Events) -> i32 { + println!("Time out"); + event.set_exit(); + 0 + } + + /// token of event source + fn token(&self) -> u64 { + let data: u64 = unsafe { std::mem::transmute(self) }; + data + } +} + +/// check the existence of exit_if_exists +fn check(exit_if_exists: &Option) -> bool { + if let Some(path) = exit_if_exists { + match access(path.as_str(), AccessFlags::F_OK) { + Ok(()) => return true, + Err(err) => { + if err != nix::Error::ENOENT { + log::error!("Failed to check the existence of {:?}, ignoring: {:?}", path, err); + } + } + } + } + + /* exit if queue is empty */ + match devmaster_queue_is_empty() { + Ok(flag) => return flag, + Err(err) => { + if err != nix::Error::ENOENT { + log::error!("Failed to check if udev queue is empty, ignoring: {:?}", err); + } + + return false; + } + } + +} \ No newline at end of file diff --git a/exts/devmaster/src/bin/devctl/subcmds/devctl_utils.rs b/exts/devmaster/src/bin/devctl/subcmds/devctl_utils.rs index ecaab3a2..25c9598d 100644 --- a/exts/devmaster/src/bin/devctl/subcmds/devctl_utils.rs +++ b/exts/devmaster/src/bin/devctl/subcmds/devctl_utils.rs @@ -1,5 +1,6 @@ use device::Device; use std::path::PathBuf; +use nix::unistd::{AccessFlags, access}; type Result = std::result::Result; @@ -36,3 +37,16 @@ pub fn find_device(id: &str, prefix: &str) -> Result { fn find_device_from_unit(_unit_name: &str) -> Result { todo!() } + +/// check if the queue is empty +pub fn devmaster_queue_is_empty() -> Result { + match access("/run/devmaster/queue", AccessFlags::F_OK) { + Ok(()) => return Ok(false), + Err(err) => { + if err == nix::Error::ENOENT { + return Ok(true); + } + return Err(err); + } + } +} diff --git a/exts/devmaster/src/bin/devctl/subcmds/mod.rs b/exts/devmaster/src/bin/devctl/subcmds/mod.rs index e4289028..0d389f8f 100644 --- a/exts/devmaster/src/bin/devctl/subcmds/mod.rs +++ b/exts/devmaster/src/bin/devctl/subcmds/mod.rs @@ -18,6 +18,7 @@ pub(crate) mod devctl_info; pub(crate) mod devctl_monitor; pub(crate) mod devctl_test_builtin; pub(crate) mod devctl_trigger; +pub(crate) mod devctl_settle; pub(self) mod devctl_utils; pub(crate) type Result = std::result::Result; diff --git a/exts/devmaster/src/lib/framework/control_manager.rs b/exts/devmaster/src/lib/framework/control_manager.rs index 75fae984..3dfabd47 100644 --- a/exts/devmaster/src/lib/framework/control_manager.rs +++ b/exts/devmaster/src/lib/framework/control_manager.rs @@ -84,6 +84,11 @@ impl ControlManager { "kill" => { self.worker_manager.upgrade().unwrap().kill_workers(); } + + "ping" => { + log::debug!("Received devmaster control message (PING)"); + } + _ => { todo!(); } diff --git a/libs/basic/Cargo.toml b/libs/basic/Cargo.toml index ebcb7801..d6d3e211 100644 --- a/libs/basic/Cargo.toml +++ b/libs/basic/Cargo.toml @@ -64,6 +64,7 @@ full = [ "argv", "exec_util", "random", + "time_util", ] capability = [] @@ -113,3 +114,4 @@ strbuf = [] argv = [] exec_util = [] random = [] +time_util = [] diff --git a/libs/basic/src/lib.rs b/libs/basic/src/lib.rs index ead31ea2..267eed29 100644 --- a/libs/basic/src/lib.rs +++ b/libs/basic/src/lib.rs @@ -83,6 +83,8 @@ pub mod unistd; pub mod unit_name; #[cfg(feature = "uuid")] pub mod uuid; +#[cfg(feature = "time_util")] +pub mod time_util; pub mod error; pub mod macros; diff --git a/libs/basic/src/time_util.rs b/libs/basic/src/time_util.rs new file mode 100644 index 00000000..8b409f9d --- /dev/null +++ b/libs/basic/src/time_util.rs @@ -0,0 +1,323 @@ +// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved. +// +// sysMaster is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +//!Parse time + +use nix::errno::Errno; +use std::ffi::CString; +use libc::{c_char, strtoll}; +use std::ffi::CStr; + +/// USec infinity +pub const USEC_INFINITY: u64 = u64::MAX; + +/// USec per Sec +pub const USEC_PER_SEC: u64 = 1000000; +/// USec per MSec +pub const USEC_PER_MSEC: u64 = 1000; +/// NSec per Sec +pub const NSEC_PER_SEC: u64 = 1000000000; +/// NSec per USec +pub const NSEC_PER_USEC: u64 = 1000; + +/// USec per Minute +pub const USEC_PER_MINUTE: u64 = 60 * USEC_PER_SEC; +/// USec per Month +pub const USEC_PER_MONTH: u64 = 2629800 * USEC_PER_SEC; +/// USec per Hour +pub const USEC_PER_HOUR: u64 = 60 * USEC_PER_MINUTE; +/// USec per Day +pub const USEC_PER_DAY: u64 = 24 * USEC_PER_HOUR; +/// USec per Week +pub const USEC_PER_WEEK: u64 = 7 * USEC_PER_DAY; +/// USec per Year +pub const USEC_PER_YEAR: u64 = 31557600 * USEC_PER_SEC; + +/// NSEC per Minute +pub const NSEC_PER_MINUTE: u64 = 60 * NSEC_PER_SEC; + + +/// parse time +/// default_unit: convert to the specified time unit +pub fn parse_time(t: &str, default_unit: u64) -> Result { + if t.is_empty() { + return Err(Errno::EINVAL); + } + + let mut usec = 0; + let mut something = false; + let mut p = t.trim(); + let mut cstr_p; + + if p.starts_with("infinity") { + let (_, right) = p.split_at("infinity".len()); + let s = right.trim().to_string(); + if !s.is_empty() { + return Err(Errno::EINVAL); + } + return Ok(USEC_INFINITY); + } + + loop { + let mut multiplier = default_unit; + + p = p.trim_start(); + if p.is_empty() { + if !something { + return Err(Errno::EINVAL); + } + break; + } + + /* Don't allow "-0" */ + if p.chars().next().unwrap() == '-' { + return Err(Errno::ERANGE); + } + + cstr_p = CString::new(p).unwrap(); + let mut endp: *mut c_char = std::ptr::null_mut(); + let (l, e) = unsafe { + let l = strtoll(cstr_p.as_ptr() as *const c_char, &mut endp, 10); + let errno = libc::__errno_location(); + if *errno > 0 { + return Err(nix::errno::from_i32(*errno)); + } + + (l, CStr::from_ptr(endp).to_str().unwrap()) + }; + + if l < 0 { + return Err(Errno::ERANGE); + } + + if e.starts_with('.') { + let (_, e_right) = e.split_at(1); + p = e_right; + p = p.trim_start_matches(char::is_numeric); + } else if e == p { + return Err(Errno::EINVAL); + } else { + p = e; + } + + let s = p; + p = p.trim_start(); + extract_multiplier(&mut p, &mut multiplier); + + if s == p && !p.is_empty() { + /* Don't allow '12.34.56', but accept '12.34 .56' or '12.34s.56' */ + return Err(Errno::EINVAL); + } + + if l as u64 >= USEC_INFINITY / multiplier { + return Err(Errno::ERANGE); + } + + let mut k = l as u64 * multiplier; + if k >= USEC_INFINITY - usec { + return Err(Errno::ERANGE); + } + + usec += k; + + something = true; + + if e.starts_with('.') { + let mut m = multiplier / 10; + let (_, e_right) = e.split_at(1); + let e_right_byte = e_right.as_bytes(); + + /* Don't allow "0.-0", "3.+1", "3. 1", "3.sec" or "3.hoge" */ + if e_right_byte.is_empty() || !e_right_byte[0].is_ascii_digit() { + return Err(Errno::EINVAL); + } + for b in e_right_byte.iter() { + if !b.is_ascii_digit() { + break; + } + + k = (*b as u64 - '0' as u64) * m; + if k >= USEC_INFINITY - usec { + return Err(Errno::ERANGE); + } + usec += k; + m /= 10; + } + } + } + return Ok(usec); +} + +/// parse time to sec +pub fn parse_sec(t: &str) -> Result { + return parse_time(t, USEC_PER_SEC); +} + +struct Table<'a> { + suffix: &'a str, + usec: u64, +} + +const TABLE: &[Table] = &[ + Table{suffix:"seconds", usec:USEC_PER_SEC}, + Table{suffix:"sec", usec:USEC_PER_SEC}, + Table{suffix:"s", usec:USEC_PER_SEC}, + Table{suffix:"minutes", usec:NSEC_PER_MINUTE}, + Table{suffix:"minute", usec:NSEC_PER_MINUTE}, + Table{suffix:"min", usec:NSEC_PER_MINUTE}, + Table{suffix:"months", usec:USEC_PER_MONTH}, + Table{suffix:"month", usec:USEC_PER_MONTH}, + Table{suffix:"M", usec:USEC_PER_MONTH}, + Table{suffix:"msec", usec:USEC_PER_MSEC}, + Table{suffix:"ms", usec:USEC_PER_MSEC}, + Table{suffix:"m", usec:USEC_PER_MINUTE}, + Table{suffix:"hours", usec:USEC_PER_HOUR}, + Table{suffix:"hour", usec:USEC_PER_HOUR}, + Table{suffix:"hr", usec:USEC_PER_HOUR}, + Table{suffix:"h", usec:USEC_PER_HOUR}, + Table{suffix:"days", usec:USEC_PER_DAY}, + Table{suffix:"day", usec:USEC_PER_DAY}, + Table{suffix:"d", usec:USEC_PER_DAY}, + Table{suffix:"weeks", usec:USEC_PER_WEEK}, + Table{suffix:"week", usec:USEC_PER_WEEK}, + Table{suffix:"w", usec:USEC_PER_WEEK}, + Table{suffix:"years", usec:USEC_PER_YEAR}, + Table{suffix:"year", usec:USEC_PER_YEAR}, + Table{suffix:"y", usec:USEC_PER_YEAR}, + Table{suffix:"usec", usec:1}, + Table{suffix:"us", usec:1}, + Table{suffix:"µs", usec:1}, +]; + + +fn extract_multiplier(p: &mut &str, multiplier: &mut u64) { + for table in TABLE { + if p.starts_with(table.suffix) { + *multiplier = table.usec; + let (_, e) = p.split_at(table.suffix.len()); + *p = e; + return; + } + } + return; +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_sec() { + let u = parse_sec("5s").unwrap(); + assert_eq!(u, 5 * USEC_PER_SEC); + + let u = parse_sec("5s500ms").unwrap(); + assert_eq!(u, 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC); + + let u = parse_sec(" 5s 500ms ").unwrap(); + assert_eq!(u, 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC); + + let u = parse_sec(" 5.5s ").unwrap(); + assert_eq!(u, 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC); + + let u = parse_sec(" 5.5s 0.5ms ").unwrap(); + assert_eq!(u, 5 * USEC_PER_SEC + 500 * USEC_PER_MSEC + 500); + + let u = parse_sec(" .22s ").unwrap(); + assert_eq!(u, 220 * USEC_PER_MSEC); + + let u = parse_sec(" .50y ").unwrap(); + assert_eq!(u, USEC_PER_YEAR / 2); + + let u = parse_sec("2.5").unwrap(); + assert_eq!(u, 2500 * USEC_PER_MSEC); + + let u = parse_sec(".7").unwrap(); + assert_eq!(u, 700 * USEC_PER_MSEC); + + let u = parse_sec("23us").unwrap(); + assert_eq!(u, 23); + + let u = parse_sec("23µs").unwrap(); + assert_eq!(u, 23); + + let u = parse_sec("infinity").unwrap(); + assert_eq!(u, USEC_INFINITY); + + let u = parse_sec(" infinity ").unwrap(); + assert_eq!(u, USEC_INFINITY); + + let u = parse_sec("+3.1s").unwrap(); + assert_eq!(u, 3100 * USEC_PER_MSEC); + + let u = parse_sec("3.1s.2").unwrap(); + assert_eq!(u, 3300 * USEC_PER_MSEC); + + let u = parse_sec("3.1 .2").unwrap(); + assert_eq!(u, 3300 * USEC_PER_MSEC); + + let u = parse_sec("3.1 sec .2 sec").unwrap(); + assert_eq!(u, 3300 * USEC_PER_MSEC); + + let u = parse_sec("3.1 sec 1.2 sec").unwrap(); + assert_eq!(u, 4300 * USEC_PER_MSEC); + + assert!(parse_sec(" xyz ").is_err()); + assert!(parse_sec("").is_err()); + assert!(parse_sec(" . ").is_err()); + assert!(parse_sec(" 5. ").is_err()); + assert!(parse_sec(".s ").is_err()); + assert!(parse_sec("-5s ").is_err()); + assert!(parse_sec("-0.3s ").is_err()); + assert!(parse_sec("-0.0s ").is_err()); + assert!(parse_sec("-0.-0s ").is_err()); + assert!(parse_sec("0.-0s ").is_err()); + assert!(parse_sec("3.-0s ").is_err()); + assert!(parse_sec(" infinity .7").is_err()); + assert!(parse_sec(".3 infinity").is_err()); + assert!(parse_sec("3.+1s").is_err()); + assert!(parse_sec("3. 1s").is_err()); + assert!(parse_sec("3.s").is_err()); + assert!(parse_sec("12.34.56").is_err()); + assert!(parse_sec("12..34").is_err()); + assert!(parse_sec("..1234").is_err()); + assert!(parse_sec("1234..").is_err()); + } + #[test] + fn test_parse_time() { + let u = parse_time("5", 1).unwrap(); + assert_eq!(u, 5); + + let u = parse_time("5", USEC_PER_MSEC).unwrap(); + assert_eq!(u, 5 * USEC_PER_MSEC); + + let u = parse_time("5", USEC_PER_SEC).unwrap(); + assert_eq!(u, 5 * USEC_PER_SEC); + + let u = parse_time("5s", 1).unwrap(); + assert_eq!(u, 5 * USEC_PER_SEC); + + let u = parse_time("5s", USEC_PER_SEC).unwrap(); + assert_eq!(u, 5 * USEC_PER_SEC); + + let u = parse_time("5s", USEC_PER_MSEC).unwrap(); + assert_eq!(u, 5 * USEC_PER_SEC); + + assert_eq!(parse_time("11111111111111y", 1), Err(Errno::ERANGE)); + + let u = parse_time("1.1111111111111y", 1).unwrap(); + assert_eq!(u, 35063999999997); + } +} + + diff --git a/libs/constants/src/lib.rs b/libs/constants/src/lib.rs index 3be57232..46a3a50a 100644 --- a/libs/constants/src/lib.rs +++ b/libs/constants/src/lib.rs @@ -35,12 +35,3 @@ pub const INIT_PARA_PATH: &str = "/run/sysmaster/init_para"; /// invalid fd pub const INVALID_FD: i32 = -1; - -/// USec per Sec -pub const USEC_PER_SEC: u64 = 1000000; -/// NSec per USec -pub const NSEC_PER_USEC: u64 = 1000; -/// NSec per Sec -pub const NSEC_PER_SEC: u64 = 1000000000; -/// USec infinity -pub const USEC_INFINITY: u64 = u64::MAX; diff --git a/libs/event/Cargo.toml b/libs/event/Cargo.toml index 2609fbdc..fb8e343b 100644 --- a/libs/event/Cargo.toml +++ b/libs/event/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -constants = { path = "../constants" } +basic = { path = "../basic", default-features = false, features = ["time_util"]} libc = { version = "0.2", default-features = false } nix = { version = "0.24", default-features = false, features = [ diff --git a/libs/event/src/timer.rs b/libs/event/src/timer.rs index 53d42e97..c5f020c2 100644 --- a/libs/event/src/timer.rs +++ b/libs/event/src/timer.rs @@ -18,7 +18,7 @@ use std::{ }; use crate::{EventType, Source}; -use constants::{NSEC_PER_SEC, NSEC_PER_USEC, USEC_INFINITY, USEC_PER_SEC}; +use basic::time_util::{NSEC_PER_SEC, NSEC_PER_USEC, USEC_INFINITY, USEC_PER_SEC}; #[derive(Debug, Clone, Copy)] pub(crate) struct Timestamp { -- Gitee