Code Monkey home page Code Monkey logo

chan-signal's People

Contributors

bnewbold avatar burntsushi avatar ftilde avatar jwilm avatar l0kod avatar little-dude avatar mbrubeck avatar milkey-mouse avatar oconnor663 avatar sector-f avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

chan-signal's Issues

API for waiting on any signal

It would be nice if there was an API for waiting on any signal (or just some straight forward way of getting a complete slice of the signal enum without manually typing them all out).

I've got a small application that's already got a signal mask set in libc land, and just need to receive any of the signals it can get.

Alternative APIs

The chan-signal crate is currently tied to the chan crate. If I want to deliver signals to, for example, a mio event loop, I need to write a proxy that first receives on the chan receiver and then forwards to the event loop. This is just one case, I can imagine some folks might want to use mpsc channels or some other notification mechanism.

I propose that the notify API accept a generic Notify (name probably needs bikeshedding) parameter. That might look something like this:

/// Thing that can receive signal notifications
pub trait Notify {
    /// Called when a signal arrives
    fn notify(Signal);
}

and the notify function might look like this:

pub fn notify<N: Notify>(notifier: N, signals: &[Signal]) { /* ... */ }

A Notify based on chan::Sender could be added trivially with no overhead compared with the current implementation.

pub struct ChanNotify(chan::Sender<Signal>);

impl Notify for ChanNotify {
    #[inline]
    fn notify(signal: Signal) {
        self.0.send(signal);
    }
}

An implementation based on mpsc::Sender, mio::Sender, or whatever else a consumer might want could be added easily in their application.

I realize that this crate is chan-signal, so it's kind of tied to the chan crate. If these changes make sense, maybe it would be worth refactoring the core signal functionality into a generalized crate like signal-base or something with a much better name ;).

Strange (?) interaction with SIGINT, cargo run, and stdin

Not sure this is a chan-signal issue or a cargo/std::process issue.

Given the following code:

extern crate chan_signal;
use std::io::{stdin, stdout};
use std::io::Write;
use std::thread;
use std::sync::atomic::*;

pub static INTR: AtomicBool = ATOMIC_BOOL_INIT;

fn main() {
    let hchan = chan_signal::notify(&[chan_signal::Signal::INT]);
    thread::spawn(move || {
        if let Some(_) = hchan.recv() {
            INTR.store(true, Ordering::Relaxed);
        }
    });
    loop {
        if INTR.load(Ordering::Relaxed) {
            break;
        }
    }
    write!(stdout(), ">>> ");
    stdout().flush();
    let mut line = String::new();
    let input = stdin().read_line(&mut line);
    println!("Input: {:?} Result: {:?}", line, input);
}

it works fine when running the compiled binary on its own: loop happens, press Ctrl-C, prompt appears, line is read from stdin. When run with cargo run, reading the line fails with EIO.

Using chan_signal::notify masks all signals

Consider this program:

#[macro_use]
extern crate chan;
extern crate chan_signal;

use chan::Receiver;
use chan_signal::Signal;

fn signal_received(rec: &Receiver<Signal>) -> bool
{
  chan_select! {
    default         => { return false },
    rec.recv() -> _ => { return true  }
  }
}

fn main() {
    // Signal gets a value when the OS sent a INT or TERM signal.
    let signal = chan_signal::notify(&[Signal::ILL]);

    // Wait for a signal or for work to be done.
    loop {
      let ret = signal_received(&signal);
      if ret {
        println!("illegal instruction");
        break
      }
    }
}

When I run this it only responds to SIGILL and SIGKILL. It effectively ignores all other signals. This came as a surprise since only SIGILL is given to notify. I would have expected the other signals to work as normal.

doesn't seem to work with `fork()`

I'm trying to mix this chan module together with libc::fork() but somehow it doesn't work.
This is probably due to some difference between thread::spawn() and fork() but I just don't understand why it should not work.

Here's the example from the README adapted to fork(). Interestingly the INT signal works but the TERM not even though sdone is really moved into run

(this issue moved from here)

Windows support

Windows does not have the signal handling mechanism of *nix. Instead it has two things:

  1. SetConsoleCtrlHandler which catches things like ctrl + C in the command line.
  2. Registering an SEH exception handler to catch certain kinds of SEH exceptions such as segfaults, illegal instructions, arithmetic interrupts, stuff like that. Could probably be done with AddVectoredExceptionHandler.

Can't catch Ignored signals

sigwait can't catch ignored signals at least in macOS (e.g., SIGIO or SIGWINCH).
man page of sigwait notes:

Processes which call sigwait() on ignored signals will wait indefinitely. Ignored signals are dropped immediately by the system, before delivery to a waiting process.

chan-signal mechanism is spawning watcher thread, wait with sigwait, and send Signal to chan.
However, sigwait ignore SIGWINCH, and it will never be sent to chan.

I'm using macOS, and I'm not sure this is also problem in linux.

The easiest way to resolve this is set the empty signal handler for ignored signals.
But this might cause other problems.
Is there any other way to resolve this?

Please export Signal::as_sig

Enumerable values are nice, but hard to use when I come to kill a child process with the trapped signal. Is there any chance that Signal::as_sig to be exported or am I missing something? Great library, thanks.

Drop Trait blocked for variables given to the worker thread

I have a variable that I want to be properly destroyed after a SIGINT. Therefor I have implemented the Drop trait for the type of the variable, initialize it before starting the runner thread and give the thread a reference.
Unfortunately the drop() function will never be called.
Here is an example to illustrate the problem:

#[macro_use]
extern crate chan;
extern crate chan_signal;

use std::thread;
use chan_signal::Signal;

struct Thing{
    a_thing: u8
}

impl Drop for Thing {
    fn drop(&mut self){
        println!("Thing #{:?} dropped", self.a_thing);
    }
}
fn main() {
    let signal = chan_signal::notify(&[Signal::INT, Signal::TERM]);
    let (sdone, rdone) = chan::sync(0);

    {
        let thing1 = Thing{a_thing: 1};
        let thing2 = Thing{a_thing: 2};
        thread::spawn(move || run( thing2, sdone));
        chan_select! {
            signal.recv() -> signal => {
                println!("received signal: {:?}", signal)
            },
            rdone.recv() => {
                println!("Program completed normally.");
            }
        }
    }
}

fn run(thing:  Thing, _sdone: chan::Sender<()>) {
    let thing3 = Thing{a_thing: 3};
    loop {
    }
}

running this example will output:

received signal: Some(INT)
Thing #1 dropped

Expected would be:

received signal: Some(INT)
Thing #1 dropped
Thing #2 dropped

I would expect thing3.drop() not to be called, since its thread is terminated violently.

My rustc is at 1.19.0 and I tested the code on Kubuntu 16.04

I assume rust can't call the destructor safely because the inner state of the object might be inconsistent (e.g. maybe the runner thread already started to call the destructor and didn't finished entirely). So I don't assume that this issue will be fixed anytime soon, but I thought it might be of interest.

Using longer constant names?

INT and TERM are ambiguous. They have their own meanings. So you may want to rename them to INTERRUPT and TERMINATE, because we do have the possibility to spell them in full in the 21th century. If you look to the Apple API or Java API, this is really common and helps newcomers to better understand the code.

Proceed with other constants the same way like SIGALRM.

Consider to do a breaking change in order to have just one right way.

Allow Setting signals to default handling as well as ignoring them

The way i imagine this is somewhat hard due to some design choices, and in most cases this would probably be a breaking change. My proposel would be the following

// Handle SIGTERM. channel is the writing end of the channel
chan_signal::handle([Signal::TERM], Handle(channel));
// We don't care about SIGINT
chan_signal::handle([Signal::INT], Ignore);
// Someone else has messed with SIGSEGV - lets teach them a lesson
chan_signal::handle([Signal::SEGV], Default);

Implementing this would also fix #2

Mac doesn't seem to close properly on any signal

Example code:

extern crate chan;
extern crate chan_signal;

use chan_signal::{Signal, notify};

fn main() {
    let signal = notify(&[Signal::INT]);
    println!("Signal: {:?}", signal.recv());
}

Here's what I've got from ps on 10.9.5:

fauna:~ edwinamsler$ ps
  PID TTY           TIME CMD
  301 ttys000    0:00.19 -bash
 1560 ttys000    0:00.00 target/debug/signals
 1575 ttys000    0:00.00 target/debug/signals
 1601 ttys000    0:00.00 target/debug/signals
 1629 ttys000    0:00.00 target/debug/signals
 1645 ttys000    0:00.00 target/debug/signals
 1650 ttys000    0:00.00 target/debug/signals
 1678 ttys000    0:00.00 target/debug/signals
 1691 ttys000    0:00.00 target/debug/signals
 1696 ttys000    0:00.00 target/debug/signals

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.