ethrecv 0.0.1

Receive ethernet packets at a high rate.
Documentation
use std::sync::Arc;

#[cfg(unix)]
use {mio::unix::pipe, parking_lot::Mutex, std::io::Write};

#[cfg(windows)]
use {
  crate::win,
  std::sync::atomic::{AtomicU32, Ordering},
  windows_sys::Win32::{Foundation::HANDLE, System::Threading::SetEvent}
};

use crate::err::Error;


/// Internal object used to signal receiver thread.
#[derive(Clone)]
pub(crate) struct CmdSignal {
  #[cfg(unix)]
  pub(crate) ctl_tx: Arc<Mutex<pipe::Sender>>,

  #[cfg(windows)]
  pub(crate) cmdreq: Arc<AtomicU32>,

  #[cfg(windows)]
  pub(crate) hev_wakeup: HANDLE
}

impl CmdSignal {
  /// Instruct receiver thread to self-terminate.
  pub(crate) fn kill<E>(&self) -> Result<(), Error<E>> {
    #[cfg(unix)]
    {
      let buf = "t";
      self.ctl_tx.lock().write_all(buf.as_bytes()).map_err(|e| {
        Error::Internal(format!(
          "Unable to send termination signal to receiver thread; {}",
          e
        ))
      })?;
    }

    #[cfg(windows)]
    {
      // ToDo: Is there a more efficient ordering here?
      self
        .cmdreq
        .fetch_or(win::CmdFlags::KILL.bits(), Ordering::SeqCst);
      unsafe {
        if SetEvent(self.hev_wakeup) == 0 {
          Err(Error::Internal(format!(
            "Unable to send termination signal to receiver thread"
          )))?;
        }
      }
    }
    Ok(())
  }

  /// Instruct receiver thread to call inspect call-back.
  #[cfg(feature = "inspect")]
  pub(crate) fn inspect(&self) {
    #[cfg(unix)]
    {
      let buf = "i";
      if let Err(e) = self.ctl_tx.lock().write_all(buf.as_bytes()) {
        eprintln!("Unable to send inspect signal to receiver thread; {}", e);
      }
    }

    #[cfg(windows)]
    {
      // ToDo: Is there a more efficient ordering here?
      self
        .cmdreq
        .fetch_or(win::CmdFlags::INSPECT.bits(), Ordering::SeqCst);
      unsafe {
        if SetEvent(self.hev_wakeup) == 0 {
          eprintln!("Unable to send inspect signal to receiver thread");
        }
      }
    }
  }

  /// Instruct receiver thread to call idle callback.
  #[cfg(feature = "idle")]
  pub(crate) fn idle(&self) {
    #[cfg(unix)]
    {
      let buf = "d";
      if let Err(e) = self.ctl_tx.lock().write_all(buf.as_bytes()) {
        eprintln!("Unable to send idle command to receiver thread; {}", e);
      }
    }

    #[cfg(windows)]
    {
      self
        .cmdreq
        .fetch_or(win::CmdFlags::IDLE.bits(), Ordering::SeqCst);
      unsafe {
        if SetEvent(self.hev_wakeup) == 0 {
          eprintln!("Unable to send idle signal to receiver thread");
        }
      }
    }
  }

  #[allow(dead_code)]
  pub(crate) fn channel(&self) {
    #[cfg(unix)]
    {
      let buf = "c";
      if let Err(e) = self.ctl_tx.lock().write_all(buf.as_bytes()) {
        eprintln!("Unable to send channel command to receiver thread; {}", e);
      }
    }

    #[cfg(windows)]
    {
      self
        .cmdreq
        .fetch_or(win::CmdFlags::CHANNEL.bits(), Ordering::SeqCst);
      unsafe {
        if SetEvent(self.hev_wakeup) == 0 {
          eprintln!("Unable to send channel signal to receiver thread");
        }
      }
    }
  }
}

// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 :