@@ -9,6 +9,9 @@ use std::{
9
9
io:: { stdout, Write } ,
10
10
panic:: PanicInfo ,
11
11
path:: PathBuf ,
12
+ sync:: Arc ,
13
+ sync:: Condvar ,
14
+ sync:: Mutex ,
12
15
thread,
13
16
time:: { Duration , Instant } ,
14
17
} ;
@@ -57,7 +60,7 @@ pub enum BottomEvent<I, J> {
57
60
}
58
61
59
62
#[ derive( Debug ) ]
60
- pub enum CollectionThreadEvent {
63
+ pub enum ThreadControlEvent {
61
64
Reset ,
62
65
UpdateConfig ( Box < app:: AppConfigFields > ) ,
63
66
UpdateUsedWidgets ( Box < UsedWidgets > ) ,
@@ -87,7 +90,7 @@ pub fn handle_mouse_event(event: MouseEvent, app: &mut App) {
87
90
}
88
91
89
92
pub fn handle_key_event_or_break (
90
- event : KeyEvent , app : & mut App , reset_sender : & std:: sync:: mpsc:: Sender < CollectionThreadEvent > ,
93
+ event : KeyEvent , app : & mut App , reset_sender : & std:: sync:: mpsc:: Sender < ThreadControlEvent > ,
91
94
) -> bool {
92
95
// debug!("KeyEvent: {:?}", event);
93
96
@@ -144,7 +147,7 @@ pub fn handle_key_event_or_break(
144
147
KeyCode :: Up => app. move_widget_selection ( & WidgetDirection :: Up ) ,
145
148
KeyCode :: Down => app. move_widget_selection ( & WidgetDirection :: Down ) ,
146
149
KeyCode :: Char ( 'r' ) => {
147
- if reset_sender. send ( CollectionThreadEvent :: Reset ) . is_ok ( ) {
150
+ if reset_sender. send ( ThreadControlEvent :: Reset ) . is_ok ( ) {
148
151
app. reset ( ) ;
149
152
}
150
153
}
@@ -262,12 +265,6 @@ pub fn cleanup_terminal(
262
265
Ok ( ( ) )
263
266
}
264
267
265
- pub fn termination_hook ( ) {
266
- let mut stdout = stdout ( ) ;
267
- disable_raw_mode ( ) . unwrap ( ) ;
268
- execute ! ( stdout, DisableMouseCapture , LeaveAlternateScreen ) . unwrap ( ) ;
269
- }
270
-
271
268
/// Based on https://github.com/Rigellute/spotify-tui/blob/master/src/main.rs
272
269
pub fn panic_hook ( panic_info : & PanicInfo < ' _ > ) {
273
270
let mut stdout = stdout ( ) ;
@@ -564,48 +561,60 @@ pub fn create_input_thread(
564
561
sender : std:: sync:: mpsc:: Sender <
565
562
BottomEvent < crossterm:: event:: KeyEvent , crossterm:: event:: MouseEvent > ,
566
563
> ,
567
- ) {
564
+ termination_ctrl_lock : Arc < Mutex < bool > > ,
565
+ ) -> std:: thread:: JoinHandle < ( ) > {
568
566
trace ! ( "Creating input thread." ) ;
569
567
thread:: spawn ( move || {
570
568
trace ! ( "Spawned input thread." ) ;
571
569
let mut mouse_timer = Instant :: now ( ) ;
572
570
let mut keyboard_timer = Instant :: now ( ) ;
573
571
574
572
loop {
575
- trace ! ( "Waiting for an input event..." ) ;
576
- if poll ( Duration :: from_millis ( 20 ) ) . is_ok ( ) {
577
- if let Ok ( event) = read ( ) {
578
- trace ! ( "Input thread received an event: {:?}" , event) ;
579
- if let Event :: Key ( key) = event {
580
- if Instant :: now ( ) . duration_since ( keyboard_timer) . as_millis ( ) >= 20 {
581
- if sender. send ( BottomEvent :: KeyInput ( key) ) . is_err ( ) {
582
- break ;
573
+ if let Ok ( is_terminated) = termination_ctrl_lock. try_lock ( ) {
574
+ // We don't block.
575
+ if * is_terminated {
576
+ trace ! ( "Received termination lock in input thread!" ) ;
577
+ drop ( is_terminated) ;
578
+ break ;
579
+ }
580
+ }
581
+ if let Ok ( poll) = poll ( Duration :: from_millis ( 20 ) ) {
582
+ if poll {
583
+ if let Ok ( event) = read ( ) {
584
+ trace ! ( "Input thread received an event: {:?}" , event) ;
585
+ if let Event :: Key ( key) = event {
586
+ if Instant :: now ( ) . duration_since ( keyboard_timer) . as_millis ( ) >= 20 {
587
+ if sender. send ( BottomEvent :: KeyInput ( key) ) . is_err ( ) {
588
+ break ;
589
+ }
590
+ trace ! ( "Input thread sent keyboard data." ) ;
591
+ keyboard_timer = Instant :: now ( ) ;
583
592
}
584
- trace ! ( "Input thread sent data." ) ;
585
- keyboard_timer = Instant :: now ( ) ;
586
- }
587
- } else if let Event :: Mouse ( mouse ) = event {
588
- if Instant :: now ( ) . duration_since ( mouse_timer ) . as_millis ( ) >= 20 {
589
- if sender . send ( BottomEvent :: MouseInput ( mouse) ) . is_err ( ) {
590
- break ;
593
+ } else if let Event :: Mouse ( mouse ) = event {
594
+ if Instant :: now ( ) . duration_since ( mouse_timer ) . as_millis ( ) >= 20 {
595
+ if sender . send ( BottomEvent :: MouseInput ( mouse ) ) . is_err ( ) {
596
+ break ;
597
+ }
598
+ trace ! ( "Input thread sent mouse data." ) ;
599
+ mouse_timer = Instant :: now ( ) ;
591
600
}
592
- trace ! ( "Input thread sent data." ) ;
593
- mouse_timer = Instant :: now ( ) ;
594
601
}
595
602
}
596
603
}
597
604
}
598
605
}
599
- } ) ;
606
+ trace ! ( "Input thread loop has closed." ) ;
607
+ } )
600
608
}
601
609
602
610
pub fn create_collection_thread (
603
611
sender : std:: sync:: mpsc:: Sender <
604
612
BottomEvent < crossterm:: event:: KeyEvent , crossterm:: event:: MouseEvent > ,
605
613
> ,
606
- reset_receiver : std:: sync:: mpsc:: Receiver < CollectionThreadEvent > ,
614
+ control_receiver : std:: sync:: mpsc:: Receiver < ThreadControlEvent > ,
615
+ termination_ctrl_lock : Arc < Mutex < bool > > , termination_ctrl_cvar : Arc < Condvar > ,
607
616
app_config_fields : & app:: AppConfigFields , used_widget_set : UsedWidgets ,
608
- ) {
617
+ ) -> std :: thread :: JoinHandle < ( ) > {
609
618
trace ! ( "Creating collection thread." ) ;
610
619
let temp_type = app_config_fields. temperature_type . clone ( ) ;
611
620
let use_current_cpu_total = app_config_fields. use_current_cpu_total ;
@@ -617,50 +626,77 @@ pub fn create_collection_thread(
617
626
let mut data_state = data_harvester:: DataCollector :: default ( ) ;
618
627
trace ! ( "Created initial data state." ) ;
619
628
data_state. set_collected_data ( used_widget_set) ;
620
- trace ! ( "Set collected data." ) ;
621
629
data_state. set_temperature_type ( temp_type) ;
622
- trace ! ( "Set initial temp type." ) ;
623
630
data_state. set_use_current_cpu_total ( use_current_cpu_total) ;
624
- trace ! ( "Set current CPU total." ) ;
625
631
data_state. set_show_average_cpu ( show_average_cpu) ;
626
- trace ! ( "Set showing average CPU." ) ;
627
632
628
633
data_state. init ( ) ;
629
634
trace ! ( "Data state is now fully initialized." ) ;
630
635
loop {
631
- trace ! ( "Collecting..." ) ;
636
+ // Check once at the very top...
637
+ if let Ok ( is_terminated) = termination_ctrl_lock. try_lock ( ) {
638
+ // We don't block here.
639
+ if * is_terminated {
640
+ trace ! ( "Received termination lock in collection thread!" ) ;
641
+ drop ( is_terminated) ;
642
+ break ;
643
+ }
644
+ }
645
+
646
+ trace ! ( "Checking for collection control receiver event..." ) ;
632
647
let mut update_time = update_rate_in_milliseconds;
633
- if let Ok ( message) = reset_receiver . try_recv ( ) {
648
+ if let Ok ( message) = control_receiver . try_recv ( ) {
634
649
trace ! ( "Received message in collection thread: {:?}" , message) ;
635
650
match message {
636
- CollectionThreadEvent :: Reset => {
651
+ ThreadControlEvent :: Reset => {
637
652
data_state. data . cleanup ( ) ;
638
653
}
639
- CollectionThreadEvent :: UpdateConfig ( app_config_fields) => {
654
+ ThreadControlEvent :: UpdateConfig ( app_config_fields) => {
640
655
data_state. set_temperature_type ( app_config_fields. temperature_type . clone ( ) ) ;
641
656
data_state
642
657
. set_use_current_cpu_total ( app_config_fields. use_current_cpu_total ) ;
643
658
data_state. set_show_average_cpu ( app_config_fields. show_average_cpu ) ;
644
659
}
645
- CollectionThreadEvent :: UpdateUsedWidgets ( used_widget_set) => {
660
+ ThreadControlEvent :: UpdateUsedWidgets ( used_widget_set) => {
646
661
data_state. set_collected_data ( * used_widget_set) ;
647
662
}
648
- CollectionThreadEvent :: UpdateUpdateTime ( new_time) => {
663
+ ThreadControlEvent :: UpdateUpdateTime ( new_time) => {
649
664
update_time = new_time;
650
665
}
651
666
}
652
667
}
653
668
futures:: executor:: block_on ( data_state. update_data ( ) ) ;
654
- trace ! ( "Collection thread is updating..." ) ;
669
+
670
+ // Yet another check to bail if needed...
671
+ if let Ok ( is_terminated) = termination_ctrl_lock. try_lock ( ) {
672
+ // We don't block here.
673
+ if * is_terminated {
674
+ trace ! ( "Received termination lock in collection thread!" ) ;
675
+ drop ( is_terminated) ;
676
+ break ;
677
+ }
678
+ }
679
+
680
+ trace ! ( "Collection thread is updating and sending..." ) ;
655
681
let event = BottomEvent :: Update ( Box :: from ( data_state. data ) ) ;
656
- trace ! ( "Collection thread done updating. Sending data now..." ) ;
657
682
data_state. data = data_harvester:: Data :: default ( ) ;
658
683
if sender. send ( event) . is_err ( ) {
659
684
trace ! ( "Error sending from collection thread..." ) ;
660
685
break ;
661
686
}
662
687
trace ! ( "No problem sending from collection thread!" ) ;
663
- thread:: sleep ( Duration :: from_millis ( update_time) ) ;
688
+
689
+ if let Ok ( ( is_terminated, _wait_timeout_result) ) = termination_ctrl_cvar. wait_timeout (
690
+ termination_ctrl_lock. lock ( ) . unwrap ( ) ,
691
+ Duration :: from_millis ( update_time) ,
692
+ ) {
693
+ if * is_terminated {
694
+ trace ! ( "Received termination lock in collection thread from cvar!" ) ;
695
+ drop ( is_terminated) ;
696
+ break ;
697
+ }
698
+ }
664
699
}
665
- } ) ;
700
+ trace ! ( "Collection thread loop has closed." ) ;
701
+ } )
666
702
}
0 commit comments