@@ -23,6 +23,8 @@ use nix::fcntl::OFlag;
2323use parseargs:: Parser ;
2424use progress:: ProgUpdateType ;
2525use progress:: { ProgUpdate , ReadStat , StatusLevel , WriteStat , gen_prog_updater} ;
26+ #[ cfg( target_os = "linux" ) ]
27+ use progress:: { check_and_reset_sigusr1, install_sigusr1_handler} ;
2628use uucore:: io:: OwnedFileDescriptorOrHandle ;
2729use uucore:: translate;
2830
@@ -45,8 +47,7 @@ use std::os::unix::{
4547#[ cfg( windows) ]
4648use std:: os:: windows:: { fs:: MetadataExt , io:: AsHandle } ;
4749use std:: path:: Path ;
48- use std:: sync:: atomic:: AtomicU8 ;
49- use std:: sync:: { Arc , atomic:: Ordering :: Relaxed , mpsc} ;
50+ use std:: sync:: mpsc;
5051use std:: thread;
5152use std:: time:: { Duration , Instant } ;
5253
@@ -86,72 +87,6 @@ struct Settings {
8687 buffered : bool ,
8788}
8889
89- /// A timer which triggers on a given interval
90- ///
91- /// After being constructed with [`Alarm::with_interval`], [`Alarm::get_trigger`]
92- /// will return [`ALARM_TRIGGER_TIMER`] once per the given [`Duration`].
93- /// Alarm can be manually triggered with closure returned by [`Alarm::manual_trigger_fn`].
94- /// [`Alarm::get_trigger`] will return [`ALARM_TRIGGER_SIGNAL`] in this case.
95- ///
96- /// Can be cloned, but the trigger status is shared across all instances so only
97- /// the first caller each interval will yield true.
98- ///
99- /// When all instances are dropped the background thread will exit on the next interval.
100- pub struct Alarm {
101- interval : Duration ,
102- trigger : Arc < AtomicU8 > ,
103- }
104-
105- pub const ALARM_TRIGGER_NONE : u8 = 0 ;
106- pub const ALARM_TRIGGER_TIMER : u8 = 1 ;
107- pub const ALARM_TRIGGER_SIGNAL : u8 = 2 ;
108-
109- impl Alarm {
110- /// use to construct alarm timer with duration
111- pub fn with_interval ( interval : Duration ) -> Self {
112- let trigger = Arc :: new ( AtomicU8 :: default ( ) ) ;
113-
114- let weak_trigger = Arc :: downgrade ( & trigger) ;
115- thread:: spawn ( move || {
116- while let Some ( trigger) = weak_trigger. upgrade ( ) {
117- thread:: sleep ( interval) ;
118- trigger. store ( ALARM_TRIGGER_TIMER , Relaxed ) ;
119- }
120- } ) ;
121-
122- Self { interval, trigger }
123- }
124-
125- /// Returns a closure that allows to manually trigger the alarm
126- ///
127- /// This is useful for cases where more than one alarm even source exists
128- /// In case of `dd` there is the SIGUSR1/SIGINFO case where we want to
129- /// trigger an manual progress report.
130- pub fn manual_trigger_fn ( & self ) -> Box < dyn Send + Sync + Fn ( ) > {
131- let weak_trigger = Arc :: downgrade ( & self . trigger ) ;
132- Box :: new ( move || {
133- if let Some ( trigger) = weak_trigger. upgrade ( ) {
134- trigger. store ( ALARM_TRIGGER_SIGNAL , Relaxed ) ;
135- }
136- } )
137- }
138-
139- /// Use this function to poll for any pending alarm event
140- ///
141- /// Returns `ALARM_TRIGGER_NONE` for no pending event.
142- /// Returns `ALARM_TRIGGER_TIMER` if the event was triggered by timer
143- /// Returns `ALARM_TRIGGER_SIGNAL` if the event was triggered manually
144- /// by the closure returned from `manual_trigger_fn`
145- pub fn get_trigger ( & self ) -> u8 {
146- self . trigger . swap ( ALARM_TRIGGER_NONE , Relaxed )
147- }
148-
149- // Getter function for the configured interval duration
150- pub fn get_interval ( & self ) -> Duration {
151- self . interval
152- }
153- }
154-
15590/// A number in blocks or bytes
15691///
15792/// Some values (seek, skip, iseek, oseek) can have values either in blocks or in bytes.
@@ -1177,20 +1112,11 @@ fn dd_copy(mut i: Input, o: Output) -> io::Result<()> {
11771112 // This is the max size needed.
11781113 let mut buf = vec ! [ BUF_INIT_BYTE ; bsize] ;
11791114
1180- // Spawn a timer thread to provide a scheduled signal indicating when we
1181- // should send an update of our progress to the reporting thread.
1182- //
1183- // This avoids the need to query the OS monotonic clock for every block.
1184- let alarm = Alarm :: with_interval ( Duration :: from_secs ( 1 ) ) ;
1115+ let mut next_progress_time = Instant :: now ( ) + Duration :: from_secs ( 1 ) ;
11851116
1186- // The signal handler spawns an own thread that waits for signals.
1187- // When the signal is received, it calls a handler function.
1188- // We inject a handler function that manually triggers the alarm.
11891117 #[ cfg( target_os = "linux" ) ]
1190- let signal_handler = progress:: SignalHandler :: install_signal_handler ( alarm. manual_trigger_fn ( ) ) ;
1191- #[ cfg( target_os = "linux" ) ]
1192- if let Err ( e) = & signal_handler {
1193- if Some ( StatusLevel :: None ) != i. settings . status {
1118+ if let Err ( e) = install_sigusr1_handler ( ) {
1119+ if i. settings . status != Some ( StatusLevel :: None ) {
11941120 eprintln ! ( "{}\n \t {e}" , translate!( "dd-warning-signal-handler" ) ) ;
11951121 }
11961122 }
@@ -1270,17 +1196,18 @@ fn dd_copy(mut i: Input, o: Output) -> io::Result<()> {
12701196 // error.
12711197 rstat += rstat_update;
12721198 wstat += wstat_update;
1273- match alarm. get_trigger ( ) {
1274- ALARM_TRIGGER_NONE => { }
1275- t @ ( ALARM_TRIGGER_TIMER | ALARM_TRIGGER_SIGNAL ) => {
1276- let tp = match t {
1277- ALARM_TRIGGER_TIMER => ProgUpdateType :: Periodic ,
1278- _ => ProgUpdateType :: Signal ,
1279- } ;
1280- let prog_update = ProgUpdate :: new ( rstat, wstat, start. elapsed ( ) , tp) ;
1281- prog_tx. send ( prog_update) . unwrap_or ( ( ) ) ;
1282- }
1283- _ => { }
1199+
1200+ #[ cfg( target_os = "linux" ) ]
1201+ if check_and_reset_sigusr1 ( ) {
1202+ let prog_update =
1203+ ProgUpdate :: new ( rstat, wstat, start. elapsed ( ) , ProgUpdateType :: Signal ) ;
1204+ prog_tx. send ( prog_update) . unwrap_or ( ( ) ) ;
1205+ }
1206+ if Instant :: now ( ) >= next_progress_time {
1207+ let prog_update =
1208+ ProgUpdate :: new ( rstat, wstat, start. elapsed ( ) , ProgUpdateType :: Periodic ) ;
1209+ prog_tx. send ( prog_update) . unwrap_or ( ( ) ) ;
1210+ next_progress_time += Duration :: from_secs ( 1 ) ;
12841211 }
12851212 }
12861213
0 commit comments