From 2ed528a14093ddb3d426efb26526c9beb74b66ac Mon Sep 17 00:00:00 2001 From: transistor Date: Fri, 22 Oct 2021 19:36:05 -0700 Subject: [PATCH] Modified the PTY implementation to be use channels --- src/host/gfx.rs | 60 ++++++++++++++++++++++++ src/host/mod.rs | 2 + src/host/traits.rs | 66 +++----------------------- src/host/tty.rs | 96 ++++++++++++++++++-------------------- src/machines/computie.rs | 44 +++++++++-------- src/peripherals/mc68681.rs | 13 +++--- 6 files changed, 142 insertions(+), 139 deletions(-) create mode 100644 src/host/gfx.rs diff --git a/src/host/gfx.rs b/src/host/gfx.rs new file mode 100644 index 0000000..f74dbf9 --- /dev/null +++ b/src/host/gfx.rs @@ -0,0 +1,60 @@ + +use std::sync::{Arc, Mutex}; + +use crate::host::traits::WindowUpdater; + + +#[derive(Clone)] +pub struct Frame { + pub width: u32, + pub height: u32, + pub bitmap: Vec, +} + +pub struct FrameSwapper { + pub current: Frame, + pub previous: Frame, +} + +impl FrameSwapper { + pub fn new() -> FrameSwapper { + FrameSwapper { + current: Frame { width: 0, height: 0, bitmap: vec![] }, + previous: Frame { width: 0, height: 0, bitmap: vec![] }, + } + } + + pub fn new_shared() -> Arc> { + Arc::new(Mutex::new(FrameSwapper::new())) + } + + pub fn to_boxed(swapper: Arc>) -> Box { + Box::new(FrameSwapperWrapper(swapper)) + } +} + +impl WindowUpdater for FrameSwapper { + fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]) { + std::mem::swap(&mut self.current, &mut self.previous); + if self.current.width != width || self.current.height != height { + self.current.width = width; + self.current.height = height; + self.current.bitmap.resize((width * height) as usize, 0); + self.previous = self.current.clone(); + return; + } + + for i in 0..(width as usize * height as usize) { + bitmap[i] = self.current.bitmap[i]; + } + } +} + +pub struct FrameSwapperWrapper(Arc>); + +impl WindowUpdater for FrameSwapperWrapper { + fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]) { + self.0.lock().map(|mut swapper| swapper.update_frame(width, height, bitmap)); + } +} + diff --git a/src/host/mod.rs b/src/host/mod.rs index adfbd99..2cafe27 100644 --- a/src/host/mod.rs +++ b/src/host/mod.rs @@ -4,3 +4,5 @@ pub mod traits; #[cfg(feature = "tty")] pub mod tty; +pub mod gfx; + diff --git a/src/host/traits.rs b/src/host/traits.rs index 7e4fb5e..b736955 100644 --- a/src/host/traits.rs +++ b/src/host/traits.rs @@ -5,69 +5,17 @@ use crate::error::Error; pub trait Host { + //fn create_pty(&self) -> Result, Error>; fn add_window(&self, updater: Box) -> Result<(), Error>; - //fn create_pty(&self) -> Tty; } -// TODO should you rename this Drawable, FrameUpdater, WindowUpdater? +pub trait Tty { + fn device_name(&self) -> String; + fn read(&mut self) -> Option; + fn write(&mut self, output: u8) -> bool; +} + pub trait WindowUpdater: Send { fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]); } - - -#[derive(Clone)] -pub struct Frame { - pub width: u32, - pub height: u32, - pub bitmap: Vec, -} - -pub struct FrameSwapper { - pub current: Frame, - pub previous: Frame, -} - -impl FrameSwapper { - pub fn new() -> FrameSwapper { - FrameSwapper { - current: Frame { width: 0, height: 0, bitmap: vec![] }, - previous: Frame { width: 0, height: 0, bitmap: vec![] }, - } - } - - pub fn new_shared() -> Arc> { - Arc::new(Mutex::new(FrameSwapper::new())) - } - - pub fn to_boxed(swapper: Arc>) -> Box { - Box::new(FrameSwapperWrapper(swapper)) - } -} - -impl WindowUpdater for FrameSwapper { - fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]) { - std::mem::swap(&mut self.current, &mut self.previous); - println!("{} {}", self.current.width, self.current.height); - if self.current.width != width || self.current.height != height { - self.current.width = width; - self.current.height = height; - self.current.bitmap.resize((width * height) as usize, 0); - self.previous = self.current.clone(); - return; - } - - for i in 0..(width as usize * height as usize) { - bitmap[i] = self.current.bitmap[i]; - } - } -} - -pub struct FrameSwapperWrapper(Arc>); - -impl WindowUpdater for FrameSwapperWrapper { - fn update_frame(&mut self, width: u32, height: u32, bitmap: &mut [u32]) { - self.0.lock().map(|mut swapper| swapper.update_frame(width, height, bitmap)); - } -} - diff --git a/src/host/tty.rs b/src/host/tty.rs index 7b0b382..17cac5d 100644 --- a/src/host/tty.rs +++ b/src/host/tty.rs @@ -1,5 +1,6 @@ use std::thread; +use std::sync::mpsc; use std::time::Duration; use std::io::{Read, Write}; use std::sync::{Arc, Mutex}; @@ -10,81 +11,58 @@ use nix::pty::{self, PtyMaster}; use nix::fcntl::{fcntl, FcntlArg}; use crate::error::Error; +use crate::host::traits::Tty; pub struct SimplePty { pub name: String, - input: Option, - output: Vec, + input: mpsc::Receiver, + output: mpsc::Sender, } -pub type SharedSimplePty = Arc>; - impl SimplePty { - pub fn new_shared(name: String) -> SharedSimplePty { - Arc::new(Mutex::new(SimplePty { + pub fn new(name: String, input: mpsc::Receiver, output: mpsc::Sender) -> SimplePty { + SimplePty { name, - input: None, - output: vec![], - })) + input, + output, + } } - pub fn open() -> Result { + pub fn open() -> Result { let pty = pty::posix_openpt(OFlag::O_RDWR).and_then(|pty| { pty::grantpt(&pty)?; pty::unlockpt(&pty)?; - fcntl(pty.as_raw_fd(), FcntlArg::F_SETFL(OFlag::O_NONBLOCK))?; Ok(pty) }).map_err(|_| Error::new("Error opening new pseudoterminal"))?; let name = unsafe { pty::ptsname(&pty).map_err(|_| Error::new("Unable to get pty name"))? }; - let shared = SimplePty::new_shared(name); - SimplePty::spawn_poller(pty, shared.clone()); + let (input_tx, input_rx) = mpsc::channel(); + let (output_tx, output_rx) = mpsc::channel(); + let shared = SimplePty::new(name.clone(), input_rx, output_tx); + + SimplePty::spawn_poller(pty, name, input_tx, output_rx); Ok(shared) } - pub fn read(&mut self) -> Option { - if self.input.is_some() { - let input = self.input; - self.input = None; - input - } else { - None - } - } - - pub fn write(&mut self, output: u8) -> bool { - self.output.push(output); - true - } - - fn spawn_poller(mut pty: PtyMaster, shared: SharedSimplePty) { + fn spawn_poller(mut pty: PtyMaster, name: String, input_tx: mpsc::Sender, output_rx: mpsc::Receiver) { thread::spawn(move || { - println!("pty: spawned reader for {}", shared.lock().unwrap().name); + println!("pty: spawned reader for {}", name); + + fcntl(pty.as_raw_fd(), FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).unwrap(); let mut buf = [0; 1]; loop { - { - let mut value = shared.lock().unwrap(); - if value.input.is_none() { - match pty.read(&mut buf) { - Ok(_) => { - (*value).input = Some(buf[0]); - }, - Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { }, - Err(err) => { - println!("ERROR: {:?}", err); - } - } - } + match pty.read(&mut buf) { + Ok(_) => { + input_tx.send(buf[0]); + }, + Err(err) if err.kind() == std::io::ErrorKind::WouldBlock => { }, + Err(err) => { println!("ERROR: {:?}", err); } + } - if !value.output.is_empty() { - match pty.write_all(value.output.as_slice()) { - Ok(()) => { }, - _ => panic!(""), - } - (*value).output.clear(); - } + while let Ok(data) = output_rx.try_recv() { + pty.write_all(&[data]).unwrap(); } thread::sleep(Duration::from_millis(10)); @@ -93,3 +71,21 @@ impl SimplePty { } } +impl Tty for SimplePty { + fn device_name(&self) -> String { + self.name.clone() + } + + fn read(&mut self) -> Option { + match self.input.try_recv() { + Ok(data) => Some(data), + _ => None, + } + } + + fn write(&mut self, output: u8) -> bool { + self.output.send(output); + true + } +} + diff --git a/src/machines/computie.rs b/src/machines/computie.rs index 0f0741c..45ed331 100644 --- a/src/machines/computie.rs +++ b/src/machines/computie.rs @@ -9,29 +9,27 @@ use crate::peripherals::ata::AtaDevice; use crate::peripherals::mc68681::MC68681; use crate::host::traits::Host; +use crate::host::tty::SimplePty; pub fn build_computie(host: &H) -> Result { let mut system = System::new(); - let monitor = MemoryBlock::load("binaries/monitor.bin").unwrap(); - for byte in monitor.contents.iter() { - print!("{:02x} ", byte); - } - system.add_addressable_device(0x00000000, wrap_transmutable(monitor)).unwrap(); + let monitor = MemoryBlock::load("binaries/monitor.bin")?; + system.add_addressable_device(0x00000000, wrap_transmutable(monitor))?; let mut ram = MemoryBlock::new(vec![0; 0x00100000]); - ram.load_at(0, "binaries/kernel.bin").unwrap(); - system.add_addressable_device(0x00100000, wrap_transmutable(ram)).unwrap(); + ram.load_at(0, "binaries/kernel.bin")?; + system.add_addressable_device(0x00100000, wrap_transmutable(ram))?; let mut ata = AtaDevice::new(); - ata.load("binaries/disk-with-partition-table.img").unwrap(); - system.add_addressable_device(0x00600000, wrap_transmutable(ata)).unwrap(); + ata.load("binaries/disk-with-partition-table.img")?; + system.add_addressable_device(0x00600000, wrap_transmutable(ata))?; let mut serial = MC68681::new(); - launch_terminal_emulator(serial.port_a.open().unwrap()); - launch_slip_connection(serial.port_b.open().unwrap()); - system.add_addressable_device(0x00700000, wrap_transmutable(serial)).unwrap(); + launch_terminal_emulator(serial.port_a.connect(Box::new(SimplePty::open()?))?); + launch_slip_connection(serial.port_b.connect(Box::new(SimplePty::open()?))?); + system.add_addressable_device(0x00700000, wrap_transmutable(serial))?; let mut cpu = M68k::new(M68kType::MC68010); @@ -45,7 +43,7 @@ pub fn build_computie(host: &H) -> Result { //cpu.decoder.dump_disassembly(&mut system, 0x100000, 0x2000); //cpu.decoder.dump_disassembly(&mut system, 0x2ac, 0x200); - system.add_interruptable_device(wrap_transmutable(cpu)).unwrap(); + system.add_interruptable_device(wrap_transmutable(cpu))?; Ok(system) } @@ -53,21 +51,21 @@ pub fn build_computie(host: &H) -> Result { pub fn build_computie_k30(host: &H) -> Result { let mut system = System::new(); - let monitor = MemoryBlock::load("binaries/monitor-68030.bin").unwrap(); - system.add_addressable_device(0x00000000, wrap_transmutable(monitor)).unwrap(); + let monitor = MemoryBlock::load("binaries/monitor-68030.bin")?; + system.add_addressable_device(0x00000000, wrap_transmutable(monitor))?; let mut ram = MemoryBlock::new(vec![0; 0x00100000]); - ram.load_at(0, "binaries/kernel-68030.bin").unwrap(); - system.add_addressable_device(0x00100000, wrap_transmutable(ram)).unwrap(); + ram.load_at(0, "binaries/kernel-68030.bin")?; + system.add_addressable_device(0x00100000, wrap_transmutable(ram))?; let mut ata = AtaDevice::new(); - ata.load("binaries/disk-with-partition-table.img").unwrap(); - system.add_addressable_device(0x00600000, wrap_transmutable(ata)).unwrap(); + ata.load("binaries/disk-with-partition-table.img")?; + system.add_addressable_device(0x00600000, wrap_transmutable(ata))?; let mut serial = MC68681::new(); - launch_terminal_emulator(serial.port_a.open().unwrap()); - //launch_slip_connection(serial.port_b.open().unwrap()); - system.add_addressable_device(0x00700000, wrap_transmutable(serial)).unwrap(); + launch_terminal_emulator(serial.port_a.connect(Box::new(SimplePty::open()?))?); + //launch_slip_connection(serial.port_b.connect(Box::new(SimplePty::open()?))?); + system.add_addressable_device(0x00700000, wrap_transmutable(serial))?; let mut cpu = M68k::new(M68kType::MC68030); @@ -81,7 +79,7 @@ pub fn build_computie_k30(host: &H) -> Result { //cpu.decoder.dump_disassembly(&mut system, 0x100000, 0x2000); //cpu.decoder.dump_disassembly(&mut system, 0x2ac, 0x200); - system.add_interruptable_device(wrap_transmutable(cpu)).unwrap(); + system.add_interruptable_device(wrap_transmutable(cpu))?; Ok(system) } diff --git a/src/peripherals/mc68681.rs b/src/peripherals/mc68681.rs index bbb4a98..c50a9be 100644 --- a/src/peripherals/mc68681.rs +++ b/src/peripherals/mc68681.rs @@ -3,7 +3,7 @@ use crate::error::Error; use crate::system::System; use crate::devices::{Clock, Address, Steppable, Addressable, Transmutable, MAX_READ}; -use crate::host::tty::{SimplePty, SharedSimplePty}; +use crate::host::traits::Tty; const REG_MR1A_MR2A: Address = 0x01; @@ -71,7 +71,7 @@ const ISR_CH_A_TX_READY: u8 = 0x01; const DEV_NAME: &'static str = "mc68681"; pub struct MC68681Port { - pub tty: Option, + pub tty: Option>, pub status: u8, pub tx_enabled: bool, @@ -93,16 +93,15 @@ impl MC68681Port { } } - pub fn open(&mut self) -> Result { - let pty = SimplePty::open()?; - let name = pty.lock().unwrap().name.clone(); + pub fn connect(&mut self, pty: Box) -> Result { + let name = pty.device_name(); println!("{}: opening pts {}", DEV_NAME, name); self.tty = Some(pty); Ok(name) } pub fn send_byte(&mut self, data: u8) { - self.tty.as_mut().map(|tty| tty.lock().unwrap().write(data)); + self.tty.as_mut().map(|tty| tty.write(data)); self.set_tx_status(false); } @@ -123,7 +122,7 @@ impl MC68681Port { pub fn check_rx(&mut self) -> Result { if self.rx_enabled && (self.status & SR_RX_READY) == 0 && self.tty.is_some() { let tty = self.tty.as_mut().unwrap(); - let result = tty.lock().unwrap().read(); + let result = tty.read(); match result { Some(input) => { self.input = input;