#![warn(missing_docs)]
use bitvec::prelude::*;
use libc::SIGSTKFLT;
use std::{io, thread::sleep, time::Duration};
use signal_hook::consts::*;
use signal_hook::iterator::Signals;
pub struct SignalStream {
signals: Signals,
pid: u32,
}
pub use std::io::{Read, Write};
impl SignalStream {
pub fn new(pid: u32) -> Self {
Self {
signals: Signals::new([SIGUSR1, SIGUSR2, SIGSTKFLT]).unwrap(),
pid: pid,
}
}
}
impl std::io::Read for SignalStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let mut n = 0;
let forever = self.signals.forever();
let mut bitlist = bitvec![];
for signal in forever {
n += 1;
bitlist.push(match signal {
SIGUSR1 => false,
SIGUSR2 => true,
SIGSTKFLT => break, _ => {
panic!("Program recieved an unexpected signal, despite it not being registered")
}
});
if n >= buf.len() * 8 {
break;
}
}
for (i, bit) in bitlist.iter().enumerate() {
let byte = i / 8;
let shift = 7 - i % 8;
buf[byte] |= ((*bit) as u8) << shift;
}
Ok(n)
}
}
impl std::io::Write for SignalStream {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
for num in buf {
let bit_representation = String::from(format!("{num:08b}"));
for bit in bit_representation.chars() {
let signal = match bit
.to_digit(2)
.expect("Non-binary digit in binary representation")
{
0 => SIGUSR1,
1 => SIGUSR2,
_ => panic!("Non-binary digit in binary representation"),
};
unsafe {
libc::kill(self.pid as i32, signal);
sleep(Duration::from_millis(5));
};
}
};
unsafe { libc::kill(self.pid as i32, SIGSTKFLT) };
Ok(0)
}
fn flush(&mut self) -> io::Result<()> {
todo!()
}
}
#[cfg(test)]
mod tests {
use std::{thread::sleep, time::Duration};
use libc::fork;
use super::*;
const LIPSUM: &'static str = include_str!("lipsum.txt");
#[test]
fn test() {
let new_pid = unsafe {
fork() as u32
};
if new_pid == 0 { let mut sigstream = SignalStream::new(0);
let mut buf = [0; LIPSUM.len()];
sigstream.read(&mut buf).unwrap();
assert_eq!(buf, LIPSUM.as_bytes());
} else { let mut sigstream = SignalStream::new(new_pid);
sleep(Duration::from_millis(5)); sigstream.write(LIPSUM.as_bytes()).unwrap();
};
}
}