forked from rcore-os/zCore
drivers: implement EventListener
This commit is contained in:
parent
994f8b80f2
commit
022d7f0e96
|
@ -8,7 +8,7 @@ description = "Device drivers of zCore"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
mock = []
|
mock = ["async-std"]
|
||||||
virtio = ["virtio-drivers"]
|
virtio = ["virtio-drivers"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -16,4 +16,6 @@ log = "0.4"
|
||||||
spin = "0.9"
|
spin = "0.9"
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
bitflags = "1.3"
|
bitflags = "1.3"
|
||||||
|
lazy_static = "1.4"
|
||||||
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "2b3c6cf", optional = true }
|
virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "2b3c6cf", optional = true }
|
||||||
|
async-std = { version = "1.10", optional = true }
|
||||||
|
|
|
@ -29,4 +29,4 @@ pub enum DeviceError {
|
||||||
|
|
||||||
pub type DeviceResult<T = ()> = core::result::Result<T, DeviceError>;
|
pub type DeviceResult<T = ()> = core::result::Result<T, DeviceError>;
|
||||||
|
|
||||||
pub type IrqHandler = alloc::boxed::Box<dyn Fn() + Send + Sync>;
|
pub type IrqHandler = alloc::boxed::Box<dyn Fn(u32) + Send + Sync>;
|
||||||
|
|
|
@ -1,28 +1,43 @@
|
||||||
use std::io::{self, Read};
|
use std::collections::VecDeque;
|
||||||
use std::sync::mpsc::{self, Receiver};
|
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
|
|
||||||
|
use async_std::{io, io::prelude::*, task};
|
||||||
|
|
||||||
use crate::scheme::{Scheme, UartScheme};
|
use crate::scheme::{Scheme, UartScheme};
|
||||||
use crate::DeviceResult;
|
use crate::DeviceResult;
|
||||||
|
|
||||||
pub struct MockUart {
|
const UART_BUF_LEN: usize = 256;
|
||||||
stdin_channel: Mutex<Receiver<u8>>,
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
static ref UART_BUF: Mutex<VecDeque<u8>> = Mutex::new(VecDeque::with_capacity(UART_BUF_LEN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct MockUart;
|
||||||
|
|
||||||
impl MockUart {
|
impl MockUart {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let (tx, rx) = mpsc::channel();
|
Self
|
||||||
std::thread::spawn(move || loop {
|
}
|
||||||
let mut buf = [0];
|
|
||||||
io::stdin().read_exact(&mut buf).unwrap();
|
pub fn start_irq_serve(irq_handler: impl Fn() + Send + Sync + 'static) {
|
||||||
if tx.send(buf[0]).is_err() {
|
task::spawn(async move {
|
||||||
break;
|
loop {
|
||||||
|
let mut buf = [0; UART_BUF_LEN];
|
||||||
|
let remains = UART_BUF_LEN - UART_BUF.lock().unwrap().len();
|
||||||
|
if remains > 0 {
|
||||||
|
if let Ok(n) = io::stdin().read(&mut buf[..remains]).await {
|
||||||
|
{
|
||||||
|
let mut uart_buf = UART_BUF.lock().unwrap();
|
||||||
|
for c in &buf[..n] {
|
||||||
|
uart_buf.push_back(*c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
irq_handler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task::yield_now().await;
|
||||||
}
|
}
|
||||||
core::hint::spin_loop();
|
|
||||||
});
|
});
|
||||||
Self {
|
|
||||||
stdin_channel: Mutex::new(rx),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,9 +51,10 @@ impl Scheme for MockUart {}
|
||||||
|
|
||||||
impl UartScheme for MockUart {
|
impl UartScheme for MockUart {
|
||||||
fn try_recv(&self) -> DeviceResult<Option<u8>> {
|
fn try_recv(&self) -> DeviceResult<Option<u8>> {
|
||||||
match self.stdin_channel.lock().unwrap().try_recv() {
|
if let Some(c) = UART_BUF.lock().unwrap().pop_front() {
|
||||||
Ok(ch) => Ok(Some(ch)),
|
Ok(Some(c))
|
||||||
_ => Ok(None),
|
} else {
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,10 +72,14 @@ impl UartScheme for MockUart {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mock_uart() {
|
fn test_mock_uart() {
|
||||||
let uart = MockUart::new();
|
let uart = Arc::new(MockUart::new());
|
||||||
|
let u = uart.clone();
|
||||||
|
MockUart::start_irq_serve(move || u.handle_irq(0));
|
||||||
|
|
||||||
uart.write_str("Hello, World!\n").unwrap();
|
uart.write_str("Hello, World!\n").unwrap();
|
||||||
uart.write_str(format!("{} + {} = {}\n", 1, 2, 1 + 2).as_str())
|
uart.write_str(format!("{} + {} = {}\n", 1, 2, 1 + 2).as_str())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
use alloc::vec::Vec;
|
||||||
|
|
||||||
|
use spin::Mutex;
|
||||||
|
|
||||||
|
use super::{Scheme, UartScheme};
|
||||||
|
use crate::{DeviceResult, IrqHandler};
|
||||||
|
|
||||||
|
pub struct EventListener<T: Scheme> {
|
||||||
|
inner: T,
|
||||||
|
events: Mutex<Vec<(IrqHandler, bool)>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Scheme> EventListener<T> {
|
||||||
|
pub fn new(inner: T) -> Self {
|
||||||
|
Self {
|
||||||
|
inner,
|
||||||
|
events: Mutex::new(Vec::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Scheme> Scheme for EventListener<T> {
|
||||||
|
fn handle_irq(&self, irq_num: u32) {
|
||||||
|
self.inner.handle_irq(irq_num);
|
||||||
|
self.events.lock().retain(|(f, once)| {
|
||||||
|
f(irq_num);
|
||||||
|
!once
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn subscribe(&self, handler: IrqHandler, once: bool) {
|
||||||
|
self.events.lock().push((handler, once));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: UartScheme> UartScheme for EventListener<T> {
|
||||||
|
fn try_recv(&self) -> DeviceResult<Option<u8>> {
|
||||||
|
self.inner.try_recv()
|
||||||
|
}
|
||||||
|
fn send(&self, ch: u8) -> DeviceResult {
|
||||||
|
self.inner.send(ch)
|
||||||
|
}
|
||||||
|
fn write_str(&self, s: &str) -> DeviceResult {
|
||||||
|
self.inner.write_str(s)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,20 @@
|
||||||
mod block;
|
mod block;
|
||||||
mod display;
|
mod display;
|
||||||
|
mod event;
|
||||||
mod input;
|
mod input;
|
||||||
mod net;
|
mod net;
|
||||||
mod uart;
|
mod uart;
|
||||||
|
|
||||||
pub use block::BlockScheme;
|
pub use block::BlockScheme;
|
||||||
pub use display::DisplayScheme;
|
pub use display::DisplayScheme;
|
||||||
|
pub use event::EventListener;
|
||||||
pub use input::InputScheme;
|
pub use input::InputScheme;
|
||||||
pub use net::NetScheme;
|
pub use net::NetScheme;
|
||||||
pub use uart::UartScheme;
|
pub use uart::UartScheme;
|
||||||
|
|
||||||
pub trait Scheme: Send + Sync {
|
pub trait Scheme: Send + Sync {
|
||||||
fn handle_irq(&self, _irq_num: u32) {}
|
fn handle_irq(&self, _irq_num: u32) {}
|
||||||
|
fn subscribe(&self, _handler: crate::IrqHandler, _once: bool) {
|
||||||
|
unimplemented!("please call `subscribe()` with the `EventListener` wrapper")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,11 +102,6 @@ where
|
||||||
fn write_str(&mut self, s: &str) -> DeviceResult {
|
fn write_str(&mut self, s: &str) -> DeviceResult {
|
||||||
for b in s.bytes() {
|
for b in s.bytes() {
|
||||||
match b {
|
match b {
|
||||||
8 | 0x7F => {
|
|
||||||
self.send(8)?;
|
|
||||||
self.send(b' ')?;
|
|
||||||
self.send(8)?;
|
|
||||||
}
|
|
||||||
b'\n' => {
|
b'\n' => {
|
||||||
self.send(b'\r')?;
|
self.send(b'\r')?;
|
||||||
self.send(b'\n')?;
|
self.send(b'\n')?;
|
||||||
|
|
|
@ -16,7 +16,11 @@ impl<'a> VirtIoBlk<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Scheme for VirtIoBlk<'a> {}
|
impl<'a> Scheme for VirtIoBlk<'a> {
|
||||||
|
fn handle_irq(&self, _irq_num: u32) {
|
||||||
|
self.inner.lock().ack_interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> BlockScheme for VirtIoBlk<'a> {
|
impl<'a> BlockScheme for VirtIoBlk<'a> {
|
||||||
fn read_block(&self, block_id: usize, buf: &mut [u8]) -> DeviceResult {
|
fn read_block(&self, block_id: usize, buf: &mut [u8]) -> DeviceResult {
|
||||||
|
|
|
@ -18,7 +18,11 @@ impl<'a> VirtIoConsole<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Scheme for VirtIoConsole<'a> {}
|
impl<'a> Scheme for VirtIoConsole<'a> {
|
||||||
|
fn handle_irq(&self, _irq_num: u32) {
|
||||||
|
self.inner.lock().ack_interrupt().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> UartScheme for VirtIoConsole<'a> {
|
impl<'a> UartScheme for VirtIoConsole<'a> {
|
||||||
fn try_recv(&self) -> DeviceResult<Option<u8>> {
|
fn try_recv(&self) -> DeviceResult<Option<u8>> {
|
||||||
|
|
|
@ -28,7 +28,7 @@ zcore-drivers = { path = "../drivers" }
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
async-std = { version = "1.9", optional = true }
|
async-std = { version = "1.10", optional = true }
|
||||||
|
|
||||||
# Bare-metal mode
|
# Bare-metal mode
|
||||||
[target.'cfg(target_os = "none")'.dependencies]
|
[target.'cfg(target_os = "none")'.dependencies]
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
|
use zcore_drivers::scheme::EventListener;
|
||||||
use zcore_drivers::uart::Uart16550Mmio;
|
use zcore_drivers::uart::Uart16550Mmio;
|
||||||
|
|
||||||
use crate::{drivers::UART, mem::phys_to_virt};
|
use crate::{drivers::UART, mem::phys_to_virt};
|
||||||
|
|
||||||
pub(super) fn init() {
|
pub(super) fn init() {
|
||||||
UART.init_by(Box::new(unsafe {
|
UART.init_by(Box::new(EventListener::new(unsafe {
|
||||||
Uart16550Mmio::<u8>::new(phys_to_virt(super::consts::UART_BASE))
|
Uart16550Mmio::<u8>::new(phys_to_virt(super::consts::UART_BASE))
|
||||||
}));
|
})));
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ const U_PLIC: u32 = 8;
|
||||||
const S_PLIC: u32 = 9;
|
const S_PLIC: u32 = 9;
|
||||||
const M_PLIC: u32 = 11;
|
const M_PLIC: u32 = 11;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static! {
|
||||||
static ref IRQ_MANAGER: Mutex<IrqManager> = Mutex::new(IrqManager::new(1, 15));
|
static ref IRQ_MANAGER: Mutex<IrqManager> = Mutex::new(IrqManager::new(1, 15));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,9 @@ pub mod vm;
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
vm::remap_the_kernel().unwrap();
|
vm::remap_the_kernel().unwrap();
|
||||||
|
drivers::init();
|
||||||
interrupt::init();
|
interrupt::init();
|
||||||
timer::init();
|
timer::init();
|
||||||
drivers::init();
|
|
||||||
|
|
||||||
#[cfg(feature = "board_qemu")]
|
#[cfg(feature = "board_qemu")]
|
||||||
{
|
{
|
||||||
|
|
|
@ -88,7 +88,7 @@ pub(super) fn handle_interrupt() {
|
||||||
}
|
}
|
||||||
UART0_INT_NUM => {
|
UART0_INT_NUM => {
|
||||||
//UART中断ID是10
|
//UART中断ID是10
|
||||||
crate::serial::handle_irq();
|
crate::drivers::UART.handle_irq(UART0_INT_NUM);
|
||||||
|
|
||||||
//换用sbi的方式获取字符
|
//换用sbi的方式获取字符
|
||||||
//interrupt::try_process_serial();
|
//interrupt::try_process_serial();
|
||||||
|
|
|
@ -13,7 +13,7 @@ pub struct AcpiTable {
|
||||||
inner: Acpi,
|
inner: Acpi,
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static! {
|
||||||
static ref ACPI_TABLE: Mutex<Option<AcpiTable>> = Mutex::default();
|
static ref ACPI_TABLE: Mutex<Option<AcpiTable>> = Mutex::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
lazy_static::lazy_static! {
|
lazy_static! {
|
||||||
static ref TSC_FREQUENCY: u16 = {
|
static ref TSC_FREQUENCY: u16 = {
|
||||||
const DEFAULT: u16 = 2600;
|
const DEFAULT: u16 = 2600;
|
||||||
if let Some(info) = raw_cpuid::CpuId::new().get_processor_frequency_info() {
|
if let Some(info) = raw_cpuid::CpuId::new().get_processor_frequency_info() {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
|
use zcore_drivers::scheme::EventListener;
|
||||||
use zcore_drivers::uart::Uart16550Pio;
|
use zcore_drivers::uart::Uart16550Pio;
|
||||||
|
|
||||||
use crate::drivers::UART;
|
use crate::drivers::UART;
|
||||||
|
|
||||||
pub(super) fn init() {
|
pub(super) fn init() {
|
||||||
UART.init_by(Box::new(Uart16550Pio::new(0x3F8)));
|
UART.init_by(Box::new(EventListener::new(Uart16550Pio::new(0x3F8))));
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ const Spurious: u32 = 31;
|
||||||
|
|
||||||
const IO_APIC_NUM_REDIRECTIONS: u8 = 120;
|
const IO_APIC_NUM_REDIRECTIONS: u8 = 120;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static! {
|
||||||
static ref IRQ_MANAGER: Mutex<IrqManager> = Mutex::new(IrqManager::new(0x20, 0xff));
|
static ref IRQ_MANAGER: Mutex<IrqManager> = Mutex::new(IrqManager::new(0x20, 0xff));
|
||||||
static ref MAX_INSTR_TABLE: Mutex<Vec<(usize, u8)>> = Mutex::default();
|
static ref MAX_INSTR_TABLE: Mutex<Vec<(usize, u8)>> = Mutex::default();
|
||||||
}
|
}
|
||||||
|
@ -239,10 +239,6 @@ fn timer() {
|
||||||
crate::timer::timer_tick();
|
crate::timer::timer_tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn com1() {
|
|
||||||
crate::serial::handle_irq();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fn keyboard() {
|
fn keyboard() {
|
||||||
use pc_keyboard::{DecodedKey, KeyCode};
|
use pc_keyboard::{DecodedKey, KeyCode};
|
||||||
|
@ -285,7 +281,11 @@ pub(super) fn init() {
|
||||||
.ok();
|
.ok();
|
||||||
// im.register_handler(Keyboard + IRQ_MIN_ID, Box::new(keyboard));
|
// im.register_handler(Keyboard + IRQ_MIN_ID, Box::new(keyboard));
|
||||||
// im.register_handler(Mouse + IRQ_MIN_ID, Box::new(mouse));
|
// im.register_handler(Mouse + IRQ_MIN_ID, Box::new(mouse));
|
||||||
im.register_handler(COM1 + IRQ_MIN_ID, Box::new(com1)).ok();
|
im.register_handler(
|
||||||
|
COM1 + IRQ_MIN_ID,
|
||||||
|
Box::new(|| crate::drivers::UART.handle_irq(COM1)),
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
im.register_handler(57u32, Box::new(irq57test)).ok();
|
im.register_handler(57u32, Box::new(irq57test)).ok();
|
||||||
// register_handler(Keyboard, Keyboard + IRQ_MIN_ID);
|
// register_handler(Keyboard, Keyboard + IRQ_MIN_ID);
|
||||||
// register_handler(Mouse, Mouse + IRQ_MIN_ID);
|
// register_handler(Mouse, Mouse + IRQ_MIN_ID);
|
||||||
|
|
|
@ -4,7 +4,7 @@ use core::time::Duration;
|
||||||
use naive_timer::Timer;
|
use naive_timer::Timer;
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static! {
|
||||||
pub static ref NAIVE_TIMER: Mutex<Timer> = Mutex::new(Timer::default());
|
pub static ref NAIVE_TIMER: Mutex<Timer> = Mutex::new(Timer::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,11 @@
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use core::future::Future;
|
|
||||||
use core::pin::Pin;
|
|
||||||
use core::task::{Context, Poll};
|
use core::task::{Context, Poll};
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
use core::{future::Future, pin::Pin};
|
||||||
/// Yields execution back to the async runtime.
|
|
||||||
pub fn yield_now() -> impl Future<Output = ()> {
|
|
||||||
YieldFuture::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[must_use = "yield_now does nothing unless polled/`await`-ed"]
|
#[must_use = "yield_now does nothing unless polled/`await`-ed"]
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct YieldFuture {
|
pub(super) struct YieldFuture {
|
||||||
flag: bool,
|
flag: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,14 +23,15 @@ impl Future for YieldFuture {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sleeps until the specified of time.
|
#[must_use = "sleep does nothing unless polled/`await`-ed"]
|
||||||
pub fn sleep_until(deadline: Duration) -> impl Future {
|
pub(super) struct SleepFuture {
|
||||||
SleepFuture { deadline }
|
deadline: Duration,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use = "sleep does nothing unless polled/`await`-ed"]
|
impl SleepFuture {
|
||||||
pub struct SleepFuture {
|
pub fn new(deadline: Duration) -> Self {
|
||||||
deadline: Duration,
|
Self { deadline }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Future for SleepFuture {
|
impl Future for SleepFuture {
|
||||||
|
@ -54,29 +49,37 @@ impl Future for SleepFuture {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a char from serial.
|
#[must_use = "serial_getchar does nothing unless polled/`await`-ed"]
|
||||||
pub fn serial_getchar() -> impl Future<Output = u8> {
|
pub(super) struct SerialFuture<'a> {
|
||||||
SerialFuture
|
buf: &'a mut [u8],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use = "serial_getchar does nothing unless polled/`await`-ed"]
|
impl<'a> SerialFuture<'a> {
|
||||||
pub struct SerialFuture;
|
pub fn new(buf: &'a mut [u8]) -> Self {
|
||||||
|
Self { buf }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Future for SerialFuture {
|
impl Future for SerialFuture<'_> {
|
||||||
type Output = u8;
|
type Output = usize;
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||||
let mut buf = [0u8];
|
use crate::drivers::UART;
|
||||||
if crate::serial::serial_read(&mut buf) != 0 {
|
let buf = &mut self.get_mut().buf;
|
||||||
return Poll::Ready(buf[0]);
|
let mut n = 0;
|
||||||
|
for i in 0..buf.len() {
|
||||||
|
if let Some(c) = UART.try_recv().unwrap() {
|
||||||
|
buf[i] = if c == b'\r' { b'\n' } else { c };
|
||||||
|
n += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if n > 0 {
|
||||||
|
return Poll::Ready(n);
|
||||||
}
|
}
|
||||||
let waker = cx.waker().clone();
|
let waker = cx.waker().clone();
|
||||||
crate::serial::serial_set_callback(Box::new({
|
UART.subscribe(Box::new(move |_| waker.wake_by_ref()), true);
|
||||||
move || {
|
|
||||||
waker.wake_by_ref();
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
Poll::Pending
|
Poll::Pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl Drop for PhysFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static! {
|
||||||
/// The global physical frame contains all zeros.
|
/// The global physical frame contains all zeros.
|
||||||
pub static ref ZERO_FRAME: PhysFrame = PhysFrame::new_zero().expect("failed to alloc zero frame");
|
pub static ref ZERO_FRAME: PhysFrame = PhysFrame::new_zero().expect("failed to alloc zero frame");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
|
mod future;
|
||||||
|
|
||||||
pub(super) mod defs;
|
pub(super) mod defs;
|
||||||
pub(super) mod fb;
|
pub(super) mod fb;
|
||||||
|
|
||||||
pub mod addr;
|
pub mod addr;
|
||||||
pub mod context;
|
pub mod context;
|
||||||
pub mod drivers;
|
pub mod drivers;
|
||||||
pub mod future;
|
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
pub mod serial;
|
pub mod serial;
|
||||||
|
pub mod thread;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
pub mod vdso;
|
pub mod vdso;
|
||||||
pub mod vm;
|
pub mod vm;
|
||||||
|
|
|
@ -1,16 +1,7 @@
|
||||||
use alloc::{boxed::Box, collections::VecDeque, vec::Vec};
|
|
||||||
use core::fmt::{Arguments, Result, Write};
|
use core::fmt::{Arguments, Result, Write};
|
||||||
|
|
||||||
use spin::Mutex;
|
|
||||||
|
|
||||||
use crate::drivers::UART;
|
use crate::drivers::UART;
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
|
||||||
static ref STDIN: Mutex<VecDeque<u8>> = Mutex::new(VecDeque::new());
|
|
||||||
static ref STDIN_CALLBACK: Mutex<Vec<Box<dyn Fn() -> bool + Send + Sync>>> =
|
|
||||||
Mutex::new(Vec::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
struct SerialWriter;
|
struct SerialWriter;
|
||||||
|
|
||||||
impl Write for SerialWriter {
|
impl Write for SerialWriter {
|
||||||
|
@ -22,31 +13,6 @@ impl Write for SerialWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn handle_irq() {
|
|
||||||
if let Some(uart) = UART.try_get() {
|
|
||||||
if let Some(c) = uart.try_recv().unwrap() {
|
|
||||||
let c = if c == b'\r' { b'\n' } else { c };
|
|
||||||
STDIN.lock().push_back(c);
|
|
||||||
STDIN_CALLBACK.lock().retain(|f| !f());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Register a callback of serial readable event.
|
|
||||||
pub fn serial_set_callback(callback: Box<dyn Fn() -> bool + Send + Sync>) {
|
|
||||||
STDIN_CALLBACK.lock().push(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read a string from serial buffer.
|
|
||||||
pub fn serial_read(buf: &mut [u8]) -> usize {
|
|
||||||
let mut stdin = STDIN.lock();
|
|
||||||
let len = stdin.len().min(buf.len());
|
|
||||||
for c in &mut buf[..len] {
|
|
||||||
*c = stdin.pop_front().unwrap();
|
|
||||||
}
|
|
||||||
len
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Print format string and its arguments to serial.
|
/// Print format string and its arguments to serial.
|
||||||
pub fn serial_write_fmt(fmt: Arguments) {
|
pub fn serial_write_fmt(fmt: Arguments) {
|
||||||
SerialWriter.write_fmt(fmt).unwrap();
|
SerialWriter.write_fmt(fmt).unwrap();
|
||||||
|
@ -56,3 +22,8 @@ pub fn serial_write_fmt(fmt: Arguments) {
|
||||||
pub fn serial_write(s: &str) {
|
pub fn serial_write(s: &str) {
|
||||||
serial_write_fmt(format_args!("{}", s));
|
serial_write_fmt(format_args!("{}", s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a char from serial.
|
||||||
|
pub async fn serial_read(buf: &mut [u8]) -> usize {
|
||||||
|
super::future::SerialFuture::new(buf).await
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
use core::time::Duration;
|
||||||
|
|
||||||
|
use super::future::{SleepFuture, YieldFuture};
|
||||||
|
|
||||||
|
/// Sleeps until the specified of time.
|
||||||
|
pub async fn sleep_until(deadline: Duration) {
|
||||||
|
SleepFuture::new(deadline).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Yields execution back to the async runtime.
|
||||||
|
pub async fn yield_now() {
|
||||||
|
YieldFuture::default().await
|
||||||
|
}
|
|
@ -33,12 +33,12 @@ hal_fn_def! {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod vm: common::vm {
|
pub mod vm: common::vm {
|
||||||
|
/// Read current VM token. (e.g. CR3, SATP, ...)
|
||||||
|
pub fn current_vmtoken() -> PhysAddr;
|
||||||
|
|
||||||
/// Activate this page table by given `vmtoken`.
|
/// Activate this page table by given `vmtoken`.
|
||||||
pub(crate) fn activate_paging(vmtoken: PhysAddr);
|
pub(crate) fn activate_paging(vmtoken: PhysAddr);
|
||||||
|
|
||||||
/// Read current VM token. (e.g. CR3, SATP, ...)
|
|
||||||
pub(crate) fn current_vmtoken() -> PhysAddr;
|
|
||||||
|
|
||||||
/// Flush TLB by the associated `vaddr`, or flush the entire TLB. (`vaddr` is `None`).
|
/// Flush TLB by the associated `vaddr`, or flush the entire TLB. (`vaddr` is `None`).
|
||||||
pub(crate) fn flush_tlb(vaddr: Option<VirtAddr>);
|
pub(crate) fn flush_tlb(vaddr: Option<VirtAddr>);
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ hal_fn_def! {
|
||||||
pub fn fetch_page_fault_info(info_reg: usize) -> (VirtAddr, MMUFlags);
|
pub fn fetch_page_fault_info(info_reg: usize) -> (VirtAddr, MMUFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod thread {
|
pub mod thread: common::thread {
|
||||||
/// Spawn a new thread.
|
/// Spawn a new thread.
|
||||||
pub fn spawn(future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>, vmtoken: usize);
|
pub fn spawn(future: Pin<Box<dyn Future<Output = ()> + Send + 'static>>, vmtoken: usize);
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
|
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate cfg_if;
|
extern crate cfg_if;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate lazy_static;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
@ -31,7 +31,7 @@ cfg_if! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use common::{addr, defs::*, drivers, future, serial, user};
|
pub use common::{addr, defs::*, drivers, serial, user};
|
||||||
pub use config::*;
|
pub use config::*;
|
||||||
pub use imp::*;
|
pub use imp::*;
|
||||||
pub use kernel_handler::*;
|
pub use kernel_handler::*;
|
||||||
|
|
|
@ -20,7 +20,7 @@ struct InputEvent {
|
||||||
value: i32,
|
value: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static! {
|
||||||
static ref MOUSE_CALLBACK: Mutex<Vec<Box<MouseCallbackFn>>> = Mutex::new(Vec::new());
|
static ref MOUSE_CALLBACK: Mutex<Vec<Box<MouseCallbackFn>>> = Mutex::new(Vec::new());
|
||||||
static ref KBD_CALLBACK: Mutex<Vec<Box<KBDCallbackFn>>> = Mutex::new(Vec::new());
|
static ref KBD_CALLBACK: Mutex<Vec<Box<KBDCallbackFn>>> = Mutex::new(Vec::new());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
|
|
||||||
use zcore_drivers::mock::MockUart;
|
use zcore_drivers::mock::MockUart;
|
||||||
|
use zcore_drivers::scheme::EventListener;
|
||||||
|
|
||||||
use crate::drivers::UART;
|
use crate::drivers::UART;
|
||||||
|
|
||||||
pub(super) fn init() {
|
pub(super) fn init() {
|
||||||
UART.init_by(Box::new(MockUart::new()));
|
UART.init_by(Box::new(EventListener::new(MockUart::new())));
|
||||||
|
MockUart::start_irq_serve(|| UART.handle_irq(0));
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::{mem::phys_to_virt, VirtAddr, PAGE_SIZE};
|
||||||
pub(super) const PMEM_BASE: VirtAddr = 0x8_0000_0000;
|
pub(super) const PMEM_BASE: VirtAddr = 0x8_0000_0000;
|
||||||
pub(super) const PMEM_SIZE: usize = 0x4000_0000; // 1GiB
|
pub(super) const PMEM_SIZE: usize = 0x4000_0000; // 1GiB
|
||||||
|
|
||||||
lazy_static::lazy_static! {
|
lazy_static! {
|
||||||
pub(super) static ref FRAME_FILE: File = create_pmem_file();
|
pub(super) static ref FRAME_FILE: File = create_pmem_file();
|
||||||
pub(super) static ref AVAILABLE_FRAMES: Mutex<VecDeque<usize>> =
|
pub(super) static ref AVAILABLE_FRAMES: Mutex<VecDeque<usize>> =
|
||||||
Mutex::new((PAGE_SIZE..PMEM_SIZE).step_by(PAGE_SIZE).collect());
|
Mutex::new((PAGE_SIZE..PMEM_SIZE).step_by(PAGE_SIZE).collect());
|
||||||
|
|
|
@ -38,10 +38,4 @@ pub fn init() {
|
||||||
unsafe {
|
unsafe {
|
||||||
register_sigsegv_handler();
|
register_sigsegv_handler();
|
||||||
}
|
}
|
||||||
// spawn a thread to read stdin
|
|
||||||
// TODO: raw mode
|
|
||||||
std::thread::spawn(|| loop {
|
|
||||||
crate::serial::handle_irq();
|
|
||||||
core::hint::spin_loop();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,8 +56,7 @@ pub fn run(args: Vec<String>, envs: Vec<String>, rootfs: Arc<dyn FileSystem>) ->
|
||||||
let path = args[0].clone();
|
let path = args[0].clone();
|
||||||
debug!("Linux process: {:?}", path);
|
debug!("Linux process: {:?}", path);
|
||||||
|
|
||||||
use kernel_hal::vm::{GenericPageTable, PageTable};
|
let pg_token = kernel_hal::vm::current_vmtoken();
|
||||||
let pg_token = PageTable::from_current().table_phys();
|
|
||||||
debug!("current pgt = {:#x}", pg_token);
|
debug!("current pgt = {:#x}", pg_token);
|
||||||
//调用zircon-object/src/task/thread.start设置好要执行的thread
|
//调用zircon-object/src/task/thread.start设置好要执行的thread
|
||||||
let (entry, sp) = loader.load(&proc.vmar(), &data, args, envs, path).unwrap();
|
let (entry, sp) = loader.load(&proc.vmar(), &data, args, envs, path).unwrap();
|
||||||
|
@ -96,7 +95,7 @@ async fn new_thread(thread: CurrentThread) {
|
||||||
0x20..=0x3f => {
|
0x20..=0x3f => {
|
||||||
kernel_hal::interrupt::handle_irq(cx.trap_num as u32);
|
kernel_hal::interrupt::handle_irq(cx.trap_num as u32);
|
||||||
if cx.trap_num == 0x20 {
|
if cx.trap_num == 0x20 {
|
||||||
kernel_hal::future::yield_now().await;
|
kernel_hal::thread::yield_now().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0xe => {
|
0xe => {
|
||||||
|
@ -133,7 +132,7 @@ async fn new_thread(thread: CurrentThread) {
|
||||||
if trap_num == 4 || trap_num == 5 {
|
if trap_num == 4 || trap_num == 5 {
|
||||||
debug!("Timer interrupt: {}", trap_num);
|
debug!("Timer interrupt: {}", trap_num);
|
||||||
|
|
||||||
kernel_hal::future::yield_now().await;
|
kernel_hal::thread::yield_now().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
//kernel_hal::interrupt::handle_irq(trap_num as u32);
|
//kernel_hal::interrupt::handle_irq(trap_num as u32);
|
||||||
|
|
|
@ -21,16 +21,18 @@ async fn main() {
|
||||||
kernel_hal::dev::fb::init();
|
kernel_hal::dev::fb::init();
|
||||||
kernel_hal::dev::input::init();
|
kernel_hal::dev::input::init();
|
||||||
}
|
}
|
||||||
kernel_hal::serial::serial_set_callback(Box::new({
|
|
||||||
move || {
|
use kernel_hal::drivers::UART;
|
||||||
let mut buffer = [0; 255];
|
UART.subscribe(
|
||||||
let len = kernel_hal::serial::serial_read(&mut buffer);
|
Box::new(|_| {
|
||||||
for c in &buffer[..len] {
|
while let Some(c) = UART.try_recv().unwrap() {
|
||||||
STDIN.push((*c).into());
|
let c = if c == b'\r' { b'\n' } else { c };
|
||||||
|
STDIN.push(c as char);
|
||||||
}
|
}
|
||||||
false
|
}),
|
||||||
}
|
false,
|
||||||
}));
|
);
|
||||||
|
|
||||||
// run first process
|
// run first process
|
||||||
let args: Vec<_> = std::env::args().skip(1).collect();
|
let args: Vec<_> = std::env::args().skip(1).collect();
|
||||||
let envs = vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()];
|
let envs = vec!["PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/x86_64-alpine-linux-musl/bin".into()];
|
||||||
|
|
|
@ -297,7 +297,7 @@ impl Syscall<'_> {
|
||||||
pub async fn sys_nanosleep(&self, req: UserInPtr<TimeSpec>) -> SysResult {
|
pub async fn sys_nanosleep(&self, req: UserInPtr<TimeSpec>) -> SysResult {
|
||||||
info!("nanosleep: deadline={:?}", req);
|
info!("nanosleep: deadline={:?}", req);
|
||||||
let req = req.read()?;
|
let req = req.read()?;
|
||||||
kernel_hal::future::sleep_until(req.into()).await;
|
kernel_hal::thread::sleep_until(req.into()).await;
|
||||||
Ok(0)
|
Ok(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -167,19 +167,18 @@ fn get_rootproc(cmdline: &str) -> Vec<String> {
|
||||||
|
|
||||||
#[cfg(feature = "linux")]
|
#[cfg(feature = "linux")]
|
||||||
fn main(ramfs_data: &'static mut [u8], cmdline: &str) -> ! {
|
fn main(ramfs_data: &'static mut [u8], cmdline: &str) -> ! {
|
||||||
|
use kernel_hal::drivers::UART;
|
||||||
use linux_object::fs::STDIN;
|
use linux_object::fs::STDIN;
|
||||||
|
|
||||||
kernel_hal::serial::serial_set_callback(Box::new({
|
UART.subscribe(
|
||||||
move || {
|
Box::new(|_| {
|
||||||
let mut buffer = [0; 255];
|
while let Some(c) = UART.try_recv().unwrap() {
|
||||||
let len = kernel_hal::serial::serial_read(&mut buffer);
|
let c = if c == b'\r' { b'\n' } else { c };
|
||||||
for c in &buffer[..len] {
|
STDIN.push(c as char);
|
||||||
STDIN.push((*c).into());
|
|
||||||
// kernel_hal::serial::serial_write(alloc::format!("{}", *c as char).as_str());
|
|
||||||
}
|
}
|
||||||
false
|
}),
|
||||||
}
|
false,
|
||||||
}));
|
);
|
||||||
|
|
||||||
//let args: Vec<String> = vec!["/bin/busybox".into(), "sh".into()];
|
//let args: Vec<String> = vec!["/bin/busybox".into(), "sh".into()];
|
||||||
let args: Vec<String> = get_rootproc(cmdline);
|
let args: Vec<String> = get_rootproc(cmdline);
|
||||||
|
@ -234,6 +233,9 @@ impl KernelHandler for ZcoreKernelHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_page_fault(&self, fault_vaddr: usize, access_flags: MMUFlags) {
|
fn handle_page_fault(&self, fault_vaddr: usize, access_flags: MMUFlags) {
|
||||||
panic!("page fault from kernel mode @ {:#x}({:?})", fault_vaddr, access_flags);
|
panic!(
|
||||||
|
"page fault from kernel mode @ {:#x}({:?})",
|
||||||
|
fault_vaddr, access_flags
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -220,7 +220,7 @@ async fn new_thread(thread: CurrentThread) {
|
||||||
kernel_hal::interrupt::handle_irq(trap_num as u32);
|
kernel_hal::interrupt::handle_irq(trap_num as u32);
|
||||||
if trap_num == 0x20 {
|
if trap_num == 0x20 {
|
||||||
EXCEPTIONS_TIMER.add(1);
|
EXCEPTIONS_TIMER.add(1);
|
||||||
kernel_hal::future::yield_now().await;
|
kernel_hal::thread::yield_now().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
0xe => {
|
0xe => {
|
||||||
|
|
|
@ -15,7 +15,6 @@ use {
|
||||||
},
|
},
|
||||||
futures::{channel::oneshot::*, future::FutureExt, pin_mut, select_biased},
|
futures::{channel::oneshot::*, future::FutureExt, pin_mut, select_biased},
|
||||||
kernel_hal::context::{GeneralRegs, UserContext},
|
kernel_hal::context::{GeneralRegs, UserContext},
|
||||||
// kernel_hal::future::sleep_until,
|
|
||||||
spin::Mutex,
|
spin::Mutex,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -603,14 +602,14 @@ impl CurrentThread {
|
||||||
select_biased! {
|
select_biased! {
|
||||||
ret = future.fuse() => ret.into_result(),
|
ret = future.fuse() => ret.into_result(),
|
||||||
_ = killed.fuse() => Err(ZxError::STOP),
|
_ = killed.fuse() => Err(ZxError::STOP),
|
||||||
_ = kernel_hal::future::sleep_until(deadline).fuse() => Err(ZxError::TIMED_OUT),
|
_ = kernel_hal::thread::sleep_until(deadline).fuse() => Err(ZxError::TIMED_OUT),
|
||||||
_ = cancel_token.fuse() => Err(ZxError::CANCELED),
|
_ = cancel_token.fuse() => Err(ZxError::CANCELED),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
select_biased! {
|
select_biased! {
|
||||||
ret = future.fuse() => ret.into_result(),
|
ret = future.fuse() => ret.into_result(),
|
||||||
_ = killed.fuse() => Err(ZxError::STOP),
|
_ = killed.fuse() => Err(ZxError::STOP),
|
||||||
_ = kernel_hal::future::sleep_until(deadline).fuse() => Err(ZxError::TIMED_OUT),
|
_ = kernel_hal::thread::sleep_until(deadline).fuse() => Err(ZxError::TIMED_OUT),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut inner = self.inner.lock();
|
let mut inner = self.inner.lock();
|
||||||
|
|
|
@ -25,15 +25,10 @@ impl Syscall<'_> {
|
||||||
let proc = self.thread.proc();
|
let proc = self.thread.proc();
|
||||||
proc.get_object::<Resource>(handle)?
|
proc.get_object::<Resource>(handle)?
|
||||||
.validate(ResourceKind::ROOT)?;
|
.validate(ResourceKind::ROOT)?;
|
||||||
// FIXME: To make 'console' work, now debug_read is a blocking call.
|
let mut vec = vec![0u8; buf_size as usize];
|
||||||
// But it should be non-blocking.
|
let len = kernel_hal::serial::serial_read(&mut vec).await;
|
||||||
// let mut vec = vec![0u8; buf_size as usize];
|
buf.write_array(&vec[..len])?;
|
||||||
// let len = kernel_hal::serial_read(&mut vec);
|
actual.write(len as u32)?;
|
||||||
// buf.write_array(&vec[..len])?;
|
|
||||||
// actual.write(len as u32)?;
|
|
||||||
let c = kernel_hal::future::serial_getchar().await;
|
|
||||||
buf.write_array(&[c])?;
|
|
||||||
actual.write(1)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,11 +94,13 @@ impl Syscall<'_> {
|
||||||
pub async fn sys_nanosleep(&self, deadline: Deadline) -> ZxResult {
|
pub async fn sys_nanosleep(&self, deadline: Deadline) -> ZxResult {
|
||||||
info!("nanosleep: deadline={:?}", deadline);
|
info!("nanosleep: deadline={:?}", deadline);
|
||||||
if deadline.0 <= 0 {
|
if deadline.0 <= 0 {
|
||||||
kernel_hal::future::yield_now().await;
|
kernel_hal::thread::yield_now().await;
|
||||||
} else {
|
} else {
|
||||||
|
let future = kernel_hal::thread::sleep_until(deadline.into());
|
||||||
|
pin_mut!(future);
|
||||||
self.thread
|
self.thread
|
||||||
.blocking_run(
|
.blocking_run(
|
||||||
kernel_hal::future::sleep_until(deadline.into()),
|
future,
|
||||||
ThreadState::BlockedSleeping,
|
ThreadState::BlockedSleeping,
|
||||||
Deadline::forever().into(),
|
Deadline::forever().into(),
|
||||||
None,
|
None,
|
||||||
|
|
Loading…
Reference in New Issue