mirror of
https://github.com/sharkdp/fd.git
synced 2024-11-17 17:35:16 +01:00
Merge pull request #902 from tavianator/quit-senders
Quit senders more aggressively
This commit is contained in:
commit
81669f4c10
2 changed files with 44 additions and 34 deletions
|
@ -1,7 +1,6 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
|
|
||||||
use lscolors::{Indicator, LsColors, Style};
|
use lscolors::{Indicator, LsColors, Style};
|
||||||
|
|
||||||
|
@ -15,12 +14,7 @@ fn replace_path_separator(path: &str, new_path_separator: &str) -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this function is performance critical and can probably be optimized
|
// TODO: this function is performance critical and can probably be optimized
|
||||||
pub fn print_entry<W: Write>(
|
pub fn print_entry<W: Write>(stdout: &mut W, entry: &Path, config: &Config) {
|
||||||
stdout: &mut W,
|
|
||||||
entry: &Path,
|
|
||||||
config: &Config,
|
|
||||||
wants_to_quit: &AtomicBool,
|
|
||||||
) {
|
|
||||||
let path = if config.strip_cwd_prefix {
|
let path = if config.strip_cwd_prefix {
|
||||||
strip_current_dir(entry)
|
strip_current_dir(entry)
|
||||||
} else {
|
} else {
|
||||||
|
@ -28,7 +22,7 @@ pub fn print_entry<W: Write>(
|
||||||
};
|
};
|
||||||
|
|
||||||
let r = if let Some(ref ls_colors) = config.ls_colors {
|
let r = if let Some(ref ls_colors) = config.ls_colors {
|
||||||
print_entry_colorized(stdout, path, config, ls_colors, wants_to_quit)
|
print_entry_colorized(stdout, path, config, ls_colors)
|
||||||
} else {
|
} else {
|
||||||
print_entry_uncolorized(stdout, path, config)
|
print_entry_uncolorized(stdout, path, config)
|
||||||
};
|
};
|
||||||
|
@ -50,7 +44,6 @@ fn print_entry_colorized<W: Write>(
|
||||||
path: &Path,
|
path: &Path,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
ls_colors: &LsColors,
|
ls_colors: &LsColors,
|
||||||
wants_to_quit: &AtomicBool,
|
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
// Split the path between the parent and the last component
|
// Split the path between the parent and the last component
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
|
@ -92,12 +85,6 @@ fn print_entry_colorized<W: Write>(
|
||||||
writeln!(stdout)?;
|
writeln!(stdout)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if wants_to_quit.load(Ordering::Relaxed) {
|
|
||||||
// Ignore any errors on flush, because we're about to exit anyway
|
|
||||||
let _ = stdout.flush();
|
|
||||||
ExitCode::KilledBySigint.exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
61
src/walk.rs
61
src/walk.rs
|
@ -134,11 +134,19 @@ pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<Config>) -> R
|
||||||
|
|
||||||
let parallel_walker = walker.threads(config.threads).build_parallel();
|
let parallel_walker = walker.threads(config.threads).build_parallel();
|
||||||
|
|
||||||
let wants_to_quit = Arc::new(AtomicBool::new(false));
|
// Flag for cleanly shutting down the parallel walk
|
||||||
|
let quit_flag = Arc::new(AtomicBool::new(false));
|
||||||
|
// Flag specifically for quitting due to ^C
|
||||||
|
let interrupt_flag = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
if config.ls_colors.is_some() && config.command.is_none() {
|
if config.ls_colors.is_some() && config.command.is_none() {
|
||||||
let wq = Arc::clone(&wants_to_quit);
|
let quit_flag = Arc::clone(&quit_flag);
|
||||||
|
let interrupt_flag = Arc::clone(&interrupt_flag);
|
||||||
|
|
||||||
ctrlc::set_handler(move || {
|
ctrlc::set_handler(move || {
|
||||||
if wq.fetch_or(true, Ordering::Relaxed) {
|
quit_flag.store(true, Ordering::Relaxed);
|
||||||
|
|
||||||
|
if interrupt_flag.fetch_or(true, Ordering::Relaxed) {
|
||||||
// Ctrl-C has been pressed twice, exit NOW
|
// Ctrl-C has been pressed twice, exit NOW
|
||||||
ExitCode::KilledBySigint.exit();
|
ExitCode::KilledBySigint.exit();
|
||||||
}
|
}
|
||||||
|
@ -147,15 +155,15 @@ pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<Config>) -> R
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spawn the thread that receives all results through the channel.
|
// Spawn the thread that receives all results through the channel.
|
||||||
let receiver_thread = spawn_receiver(&config, &wants_to_quit, rx);
|
let receiver_thread = spawn_receiver(&config, &quit_flag, &interrupt_flag, rx);
|
||||||
|
|
||||||
// Spawn the sender threads.
|
// Spawn the sender threads.
|
||||||
spawn_senders(&config, &wants_to_quit, pattern, parallel_walker, tx);
|
spawn_senders(&config, &quit_flag, pattern, parallel_walker, tx);
|
||||||
|
|
||||||
// Wait for the receiver thread to print out all results.
|
// Wait for the receiver thread to print out all results.
|
||||||
let exit_code = receiver_thread.join().unwrap();
|
let exit_code = receiver_thread.join().unwrap();
|
||||||
|
|
||||||
if wants_to_quit.load(Ordering::Relaxed) {
|
if interrupt_flag.load(Ordering::Relaxed) {
|
||||||
Ok(ExitCode::KilledBySigint)
|
Ok(ExitCode::KilledBySigint)
|
||||||
} else {
|
} else {
|
||||||
Ok(exit_code)
|
Ok(exit_code)
|
||||||
|
@ -166,8 +174,10 @@ pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<Config>) -> R
|
||||||
struct ReceiverBuffer<W> {
|
struct ReceiverBuffer<W> {
|
||||||
/// The configuration.
|
/// The configuration.
|
||||||
config: Arc<Config>,
|
config: Arc<Config>,
|
||||||
|
/// For shutting down the senders.
|
||||||
|
quit_flag: Arc<AtomicBool>,
|
||||||
/// The ^C notifier.
|
/// The ^C notifier.
|
||||||
wants_to_quit: Arc<AtomicBool>,
|
interrupt_flag: Arc<AtomicBool>,
|
||||||
/// Receiver for worker results.
|
/// Receiver for worker results.
|
||||||
rx: Receiver<WorkerResult>,
|
rx: Receiver<WorkerResult>,
|
||||||
/// Standard output.
|
/// Standard output.
|
||||||
|
@ -186,7 +196,8 @@ impl<W: Write> ReceiverBuffer<W> {
|
||||||
/// Create a new receiver buffer.
|
/// Create a new receiver buffer.
|
||||||
fn new(
|
fn new(
|
||||||
config: Arc<Config>,
|
config: Arc<Config>,
|
||||||
wants_to_quit: Arc<AtomicBool>,
|
quit_flag: Arc<AtomicBool>,
|
||||||
|
interrupt_flag: Arc<AtomicBool>,
|
||||||
rx: Receiver<WorkerResult>,
|
rx: Receiver<WorkerResult>,
|
||||||
stdout: W,
|
stdout: W,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -195,7 +206,8 @@ impl<W: Write> ReceiverBuffer<W> {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
config,
|
config,
|
||||||
wants_to_quit,
|
quit_flag,
|
||||||
|
interrupt_flag,
|
||||||
rx,
|
rx,
|
||||||
stdout,
|
stdout,
|
||||||
mode: ReceiverMode::Buffering,
|
mode: ReceiverMode::Buffering,
|
||||||
|
@ -209,6 +221,7 @@ impl<W: Write> ReceiverBuffer<W> {
|
||||||
fn process(&mut self) -> ExitCode {
|
fn process(&mut self) -> ExitCode {
|
||||||
loop {
|
loop {
|
||||||
if let Err(ec) = self.poll() {
|
if let Err(ec) = self.poll() {
|
||||||
|
self.quit_flag.store(true, Ordering::Relaxed);
|
||||||
return ec;
|
return ec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,7 +257,7 @@ impl<W: Write> ReceiverBuffer<W> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ReceiverMode::Streaming => {
|
ReceiverMode::Streaming => {
|
||||||
self.print(&path);
|
self.print(&path)?;
|
||||||
self.flush()?;
|
self.flush()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,8 +286,16 @@ impl<W: Write> ReceiverBuffer<W> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Output a path.
|
/// Output a path.
|
||||||
fn print(&mut self, path: &Path) {
|
fn print(&mut self, path: &Path) -> Result<(), ExitCode> {
|
||||||
output::print_entry(&mut self.stdout, path, &self.config, &self.wants_to_quit)
|
output::print_entry(&mut self.stdout, path, &self.config);
|
||||||
|
|
||||||
|
if self.interrupt_flag.load(Ordering::Relaxed) {
|
||||||
|
// Ignore any errors on flush, because we're about to exit anyway
|
||||||
|
let _ = self.flush();
|
||||||
|
return Err(ExitCode::KilledBySigint);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Switch ourselves into streaming mode.
|
/// Switch ourselves into streaming mode.
|
||||||
|
@ -283,7 +304,7 @@ impl<W: Write> ReceiverBuffer<W> {
|
||||||
|
|
||||||
let buffer = mem::take(&mut self.buffer);
|
let buffer = mem::take(&mut self.buffer);
|
||||||
for path in buffer {
|
for path in buffer {
|
||||||
self.print(&path);
|
self.print(&path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.flush()
|
self.flush()
|
||||||
|
@ -315,11 +336,13 @@ impl<W: Write> ReceiverBuffer<W> {
|
||||||
|
|
||||||
fn spawn_receiver(
|
fn spawn_receiver(
|
||||||
config: &Arc<Config>,
|
config: &Arc<Config>,
|
||||||
wants_to_quit: &Arc<AtomicBool>,
|
quit_flag: &Arc<AtomicBool>,
|
||||||
|
interrupt_flag: &Arc<AtomicBool>,
|
||||||
rx: Receiver<WorkerResult>,
|
rx: Receiver<WorkerResult>,
|
||||||
) -> thread::JoinHandle<ExitCode> {
|
) -> thread::JoinHandle<ExitCode> {
|
||||||
let config = Arc::clone(config);
|
let config = Arc::clone(config);
|
||||||
let wants_to_quit = Arc::clone(wants_to_quit);
|
let quit_flag = Arc::clone(quit_flag);
|
||||||
|
let interrupt_flag = Arc::clone(interrupt_flag);
|
||||||
|
|
||||||
let show_filesystem_errors = config.show_filesystem_errors;
|
let show_filesystem_errors = config.show_filesystem_errors;
|
||||||
let threads = config.threads;
|
let threads = config.threads;
|
||||||
|
@ -375,7 +398,7 @@ fn spawn_receiver(
|
||||||
let stdout = stdout.lock();
|
let stdout = stdout.lock();
|
||||||
let stdout = io::BufWriter::new(stdout);
|
let stdout = io::BufWriter::new(stdout);
|
||||||
|
|
||||||
let mut rxbuffer = ReceiverBuffer::new(config, wants_to_quit, rx, stdout);
|
let mut rxbuffer = ReceiverBuffer::new(config, quit_flag, interrupt_flag, rx, stdout);
|
||||||
rxbuffer.process()
|
rxbuffer.process()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -439,7 +462,7 @@ impl DirEntry {
|
||||||
|
|
||||||
fn spawn_senders(
|
fn spawn_senders(
|
||||||
config: &Arc<Config>,
|
config: &Arc<Config>,
|
||||||
wants_to_quit: &Arc<AtomicBool>,
|
quit_flag: &Arc<AtomicBool>,
|
||||||
pattern: Arc<Regex>,
|
pattern: Arc<Regex>,
|
||||||
parallel_walker: ignore::WalkParallel,
|
parallel_walker: ignore::WalkParallel,
|
||||||
tx: Sender<WorkerResult>,
|
tx: Sender<WorkerResult>,
|
||||||
|
@ -448,10 +471,10 @@ fn spawn_senders(
|
||||||
let config = Arc::clone(config);
|
let config = Arc::clone(config);
|
||||||
let pattern = Arc::clone(&pattern);
|
let pattern = Arc::clone(&pattern);
|
||||||
let tx_thread = tx.clone();
|
let tx_thread = tx.clone();
|
||||||
let wants_to_quit = Arc::clone(wants_to_quit);
|
let quit_flag = Arc::clone(quit_flag);
|
||||||
|
|
||||||
Box::new(move |entry_o| {
|
Box::new(move |entry_o| {
|
||||||
if wants_to_quit.load(Ordering::Relaxed) {
|
if quit_flag.load(Ordering::Relaxed) {
|
||||||
return ignore::WalkState::Quit;
|
return ignore::WalkState::Quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue