-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
uptime: locale init per thread #9028
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
2fa7a32
43cd6e5
f549910
0b2affa
d561365
dca827e
43e5cb2
17f85cb
15ed57b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,9 +13,11 @@ | |
| // See https://github.com/uutils/coreutils/pull/7289 for discussion. | ||
|
|
||
| use crate::error::{UError, UResult}; | ||
| use crate::locale::{self, LocalizationError}; | ||
| use crate::translate; | ||
| use chrono::Local; | ||
| use libc::time_t; | ||
| use std::cell::Cell; | ||
| use thiserror::Error; | ||
|
|
||
| #[derive(Debug, Error)] | ||
|
|
@@ -36,6 +38,29 @@ impl UError for UptimeError { | |
| } | ||
| } | ||
|
|
||
| thread_local! { | ||
| static LOCALE_READY: Cell<bool> = const { Cell::new(false) }; | ||
| } | ||
|
|
||
| fn ensure_uptime_locale() { | ||
| LOCALE_READY.with(|ready| { | ||
| if ready.get() { | ||
| return; | ||
| } | ||
|
|
||
| match locale::setup_localization("uptime") { | ||
| Ok(()) => ready.set(true), | ||
| Err(LocalizationError::Bundle(msg)) if msg.contains("already initialized") => { | ||
| ready.set(true); | ||
| } | ||
| Err(err) => { | ||
| #[cfg(debug_assertions)] | ||
| eprintln!("uucore::uptime localization setup failed: {err}"); | ||
| } | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| /// Returns the formatted time string, e.g. "12:34:56" | ||
| pub fn get_formatted_time() -> String { | ||
| Local::now().time().format("%H:%M:%S").to_string() | ||
|
|
@@ -52,6 +77,7 @@ pub fn get_formatted_time() -> String { | |
| /// Returns a UResult with the uptime in seconds if successful, otherwise an UptimeError. | ||
| #[cfg(target_os = "openbsd")] | ||
| pub fn get_uptime(_boot_time: Option<time_t>) -> UResult<i64> { | ||
| ensure_uptime_locale(); | ||
| use libc::CLOCK_BOOTTIME; | ||
| use libc::clock_gettime; | ||
|
|
||
|
|
@@ -91,6 +117,7 @@ pub fn get_uptime(_boot_time: Option<time_t>) -> UResult<i64> { | |
| #[cfg(unix)] | ||
| #[cfg(not(target_os = "openbsd"))] | ||
| pub fn get_uptime(boot_time: Option<time_t>) -> UResult<i64> { | ||
| ensure_uptime_locale(); | ||
| use crate::utmpx::Utmpx; | ||
| use libc::BOOT_TIME; | ||
| use std::fs::File; | ||
|
|
@@ -150,6 +177,7 @@ pub fn get_uptime(boot_time: Option<time_t>) -> UResult<i64> { | |
| /// Returns a UResult with the uptime in seconds if successful, otherwise an UptimeError. | ||
| #[cfg(windows)] | ||
| pub fn get_uptime(_boot_time: Option<time_t>) -> UResult<i64> { | ||
| ensure_uptime_locale(); | ||
| use windows_sys::Win32::System::SystemInformation::GetTickCount; | ||
| // SAFETY: always return u32 | ||
| let uptime = unsafe { GetTickCount() }; | ||
|
|
@@ -167,6 +195,7 @@ pub fn get_uptime(_boot_time: Option<time_t>) -> UResult<i64> { | |
| /// Returns a UResult with the uptime in a human-readable format(e.g. "1 day, 3:45") if successful, otherwise an UptimeError. | ||
| #[inline] | ||
| pub fn get_formatted_uptime(boot_time: Option<time_t>) -> UResult<String> { | ||
| ensure_uptime_locale(); | ||
| let up_secs = get_uptime(boot_time)?; | ||
|
|
||
| if up_secs < 0 { | ||
|
|
@@ -307,6 +336,7 @@ pub fn get_nusers() -> usize { | |
| /// e.g. "0 users", "1 user", "2 users" | ||
| #[inline] | ||
| pub fn format_nusers(n: usize) -> String { | ||
| ensure_uptime_locale(); | ||
| translate!( | ||
| "uptime-user-count", | ||
| "count" => n | ||
|
|
@@ -320,6 +350,7 @@ pub fn format_nusers(n: usize) -> String { | |
| /// e.g. "0 user", "1 user", "2 users" | ||
| #[inline] | ||
| pub fn get_formatted_nusers() -> String { | ||
| ensure_uptime_locale(); | ||
| #[cfg(not(target_os = "openbsd"))] | ||
| return format_nusers(get_nusers()); | ||
|
|
||
|
|
@@ -335,6 +366,7 @@ pub fn get_formatted_nusers() -> String { | |
| /// The load average is a tuple of three floating point numbers representing the 1-minute, 5-minute, and 15-minute load averages. | ||
| #[cfg(unix)] | ||
| pub fn get_loadavg() -> UResult<(f64, f64, f64)> { | ||
| ensure_uptime_locale(); | ||
| use crate::libc::c_double; | ||
| use libc::getloadavg; | ||
|
|
||
|
|
@@ -357,6 +389,7 @@ pub fn get_loadavg() -> UResult<(f64, f64, f64)> { | |
| /// Returns a UResult with an UptimeError. | ||
| #[cfg(windows)] | ||
| pub fn get_loadavg() -> UResult<(f64, f64, f64)> { | ||
| ensure_uptime_locale(); | ||
| Err(UptimeError::WindowsLoadavg)? | ||
| } | ||
|
|
||
|
|
@@ -368,6 +401,7 @@ pub fn get_loadavg() -> UResult<(f64, f64, f64)> { | |
| /// e.g. "load average: 0.00, 0.00, 0.00" | ||
| #[inline] | ||
| pub fn get_formatted_loadavg() -> UResult<String> { | ||
| ensure_uptime_locale(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i am not a fan to duplicate this call in every functions of uptime
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the suggestion. Unfortunately |
||
| let loadavg = get_loadavg()?; | ||
| Ok(translate!( | ||
| "uptime-lib-format-loadavg", | ||
|
|
@@ -392,4 +426,24 @@ mod tests { | |
| assert_eq!("1 user", format_nusers(1)); | ||
| assert_eq!("2 users", format_nusers(2)); | ||
| } | ||
|
|
||
| #[test] | ||
| fn test_format_nusers_threaded() { | ||
| unsafe { | ||
| std::env::set_var("LANG", "en_US.UTF-8"); | ||
| } | ||
| let _ = locale::setup_localization("top"); | ||
| let _ = locale::setup_localization("uptime"); | ||
|
|
||
| assert_eq!("uptime-user-count", format_nusers(0)); | ||
|
|
||
| std::thread::spawn(move || { | ||
| let _ = locale::setup_localization("uptime"); | ||
| assert_eq!("0 users", format_nusers(0)); | ||
| assert_eq!("1 user", format_nusers(1)); | ||
| assert_eq!("2 users", format_nusers(2)); | ||
| }) | ||
| .join() | ||
| .expect("thread should succeed"); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.