mirror of
https://github.com/rcore-os/rCore-Tutorial-v3.git
synced 2024-11-22 01:16:26 +04:00
codecheck: Remove UB of ch8 usertests #140
This commit is contained in:
parent
8cd58cbe3a
commit
98255231b4
@ -6,6 +6,7 @@ extern crate user_lib;
|
|||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
@ -14,7 +15,7 @@ const THREAD_COUNT_DEFAULT: usize = 16;
|
|||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
@ -6,6 +6,7 @@ extern crate user_lib;
|
|||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use core::sync::atomic::{AtomicBool, Ordering};
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
||||||
|
|
||||||
@ -16,7 +17,7 @@ const THREAD_COUNT_DEFAULT: usize = 16;
|
|||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
@ -6,6 +6,7 @@ extern crate user_lib;
|
|||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock};
|
use user_lib::{mutex_blocking_create, mutex_lock, mutex_unlock};
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ const THREAD_COUNT_DEFAULT: usize = 16;
|
|||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
@ -6,6 +6,7 @@ extern crate user_lib;
|
|||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
use user_lib::{mutex_create, mutex_lock, mutex_unlock};
|
use user_lib::{mutex_create, mutex_lock, mutex_unlock};
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ const THREAD_COUNT_DEFAULT: usize = 16;
|
|||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::{addr_of, addr_of_mut, read_volatile};
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::sync::atomic::{compiler_fence, Ordering};
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ const THREAD_COUNT_DEFAULT: usize = 2;
|
|||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
@ -39,7 +39,7 @@ unsafe fn lock(id: usize) {
|
|||||||
// Otherwise the compiler will assume that they will never
|
// Otherwise the compiler will assume that they will never
|
||||||
// be changed on this thread. Thus, they will be accessed
|
// be changed on this thread. Thus, they will be accessed
|
||||||
// only once!
|
// only once!
|
||||||
while vload!(&FLAG[j]) && vload!(&TURN) == j {}
|
while read_volatile(addr_of!(FLAG[j])) && read_volatile(addr_of!(TURN)) == j {}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn unlock(id: usize) {
|
unsafe fn unlock(id: usize) {
|
||||||
|
@ -2,14 +2,16 @@
|
|||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::sync::atomic::{compiler_fence, Ordering};
|
use core::{
|
||||||
|
ptr::addr_of_mut,
|
||||||
|
sync::atomic::{compiler_fence, Ordering},
|
||||||
|
};
|
||||||
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
@ -20,7 +22,7 @@ const THREAD_COUNT_DEFAULT: usize = 2;
|
|||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::{addr_of, addr_of_mut, read_volatile};
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
@ -16,7 +16,7 @@ const THREAD_COUNT_DEFAULT: usize = 16;
|
|||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
@ -25,7 +25,7 @@ unsafe fn critical_section(t: &mut usize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn lock() {
|
unsafe fn lock() {
|
||||||
while vload!(&OCCUPIED) {}
|
while read_volatile(addr_of!(OCCUPIED)) {}
|
||||||
OCCUPIED = true;
|
OCCUPIED = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
use user_lib::{exit, get_time, thread_create, waittid, yield_};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
@ -16,7 +16,7 @@ const THREAD_COUNT_DEFAULT: usize = 16;
|
|||||||
static mut PER_THREAD: usize = 0;
|
static mut PER_THREAD: usize = 0;
|
||||||
|
|
||||||
unsafe fn critical_section(t: &mut usize) {
|
unsafe fn critical_section(t: &mut usize) {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..500 {
|
for _ in 0..500 {
|
||||||
*t = (*t) * (*t) % 10007;
|
*t = (*t) * (*t) % 10007;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
@ -8,7 +7,10 @@ extern crate alloc;
|
|||||||
extern crate core;
|
extern crate core;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
use core::{
|
||||||
|
ptr::{addr_of, addr_of_mut, read_volatile, write_volatile},
|
||||||
|
sync::atomic::{AtomicUsize, Ordering},
|
||||||
|
};
|
||||||
use user_lib::{exit, sleep, thread_create, waittid};
|
use user_lib::{exit, sleep, thread_create, waittid};
|
||||||
|
|
||||||
const N: usize = 2;
|
const N: usize = 2;
|
||||||
@ -38,19 +40,19 @@ fn critical_test_exit() {
|
|||||||
assert_eq!(GUARD.fetch_sub(1, Ordering::SeqCst), 1);
|
assert_eq!(GUARD.fetch_sub(1, Ordering::SeqCst), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eisenberg_enter_critical(id: usize) {
|
unsafe fn eisenberg_enter_critical(id: usize) {
|
||||||
/* announce that we want to enter */
|
/* announce that we want to enter */
|
||||||
loop {
|
loop {
|
||||||
println!("Thread[{}] try enter", id);
|
println!("Thread[{}] try enter", id);
|
||||||
vstore!(&FLAG[id], FlagState::Want);
|
write_volatile(addr_of_mut!(FLAG[id]), FlagState::Want);
|
||||||
loop {
|
loop {
|
||||||
/* check if any with higher priority is `Want` or `In` */
|
/* check if any with higher priority is `Want` or `In` */
|
||||||
let mut prior_thread: Option<usize> = None;
|
let mut prior_thread: Option<usize> = None;
|
||||||
let turn = vload!(&TURN);
|
let turn = read_volatile(addr_of!(TURN));
|
||||||
let ring_id = if id < turn { id + THREAD_NUM } else { id };
|
let ring_id = if id < turn { id + THREAD_NUM } else { id };
|
||||||
// FLAG.iter() may lead to some errors, use for-loop instead
|
// FLAG.iter() may lead to some errors, use for-loop instead
|
||||||
for i in turn..ring_id {
|
for i in turn..ring_id {
|
||||||
if vload!(&FLAG[i % THREAD_NUM]) != FlagState::Out {
|
if read_volatile(addr_of!(FLAG[i % THREAD_NUM])) != FlagState::Out {
|
||||||
prior_thread = Some(i % THREAD_NUM);
|
prior_thread = Some(i % THREAD_NUM);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -66,13 +68,13 @@ fn eisenberg_enter_critical(id: usize) {
|
|||||||
sleep(1);
|
sleep(1);
|
||||||
}
|
}
|
||||||
/* now tentatively claim the resource */
|
/* now tentatively claim the resource */
|
||||||
vstore!(&FLAG[id], FlagState::In);
|
write_volatile(addr_of_mut!(FLAG[id]), FlagState::In);
|
||||||
/* enforce the order of `claim` and `conflict check`*/
|
/* enforce the order of `claim` and `conflict check`*/
|
||||||
memory_fence!();
|
memory_fence!();
|
||||||
/* check if anthor thread is also `In`, which imply a conflict*/
|
/* check if anthor thread is also `In`, which imply a conflict*/
|
||||||
let mut conflict = false;
|
let mut conflict = false;
|
||||||
for i in 0..THREAD_NUM {
|
for i in 0..THREAD_NUM {
|
||||||
if i != id && vload!(&FLAG[i]) == FlagState::In {
|
if i != id && read_volatile(addr_of!(FLAG[i])) == FlagState::In {
|
||||||
conflict = true;
|
conflict = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,28 +85,28 @@ fn eisenberg_enter_critical(id: usize) {
|
|||||||
/* no need to sleep */
|
/* no need to sleep */
|
||||||
}
|
}
|
||||||
/* clain the trun */
|
/* clain the trun */
|
||||||
vstore!(&TURN, id);
|
write_volatile(addr_of_mut!(TURN), id);
|
||||||
println!("Thread[{}] enter", id);
|
println!("Thread[{}] enter", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eisenberg_exit_critical(id: usize) {
|
unsafe fn eisenberg_exit_critical(id: usize) {
|
||||||
/* find next one who wants to enter and give the turn to it*/
|
/* find next one who wants to enter and give the turn to it*/
|
||||||
let mut next = id;
|
let mut next = id;
|
||||||
let ring_id = id + THREAD_NUM;
|
let ring_id = id + THREAD_NUM;
|
||||||
for i in (id + 1)..ring_id {
|
for i in (id + 1)..ring_id {
|
||||||
let idx = i % THREAD_NUM;
|
let idx = i % THREAD_NUM;
|
||||||
if vload!(&FLAG[idx]) == FlagState::Want {
|
if read_volatile(addr_of!(FLAG[idx])) == FlagState::Want {
|
||||||
next = idx;
|
next = idx;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vstore!(&TURN, next);
|
write_volatile(addr_of_mut!(TURN), next);
|
||||||
/* All done */
|
/* All done */
|
||||||
vstore!(&FLAG[id], FlagState::Out);
|
write_volatile(addr_of_mut!(FLAG[id]), FlagState::Out);
|
||||||
println!("Thread[{}] exit, give turn to {}", id, next);
|
println!("Thread[{}] exit, give turn to {}", id, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn thread_fn(id: usize) -> ! {
|
pub unsafe fn thread_fn(id: usize) -> ! {
|
||||||
println!("Thread[{}] init.", id);
|
println!("Thread[{}] init.", id);
|
||||||
for _ in 0..N {
|
for _ in 0..N {
|
||||||
eisenberg_enter_critical(id);
|
eisenberg_enter_critical(id);
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate user_lib;
|
extern crate user_lib;
|
||||||
@ -8,6 +7,7 @@ extern crate alloc;
|
|||||||
extern crate core;
|
extern crate core;
|
||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::{addr_of, addr_of_mut, read_volatile, write_volatile};
|
||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use user_lib::{exit, sleep, thread_create, waittid};
|
use user_lib::{exit, sleep, thread_create, waittid};
|
||||||
const N: usize = 1000;
|
const N: usize = 1000;
|
||||||
@ -28,12 +28,12 @@ fn critical_test_exit() {
|
|||||||
assert_eq!(GUARD.fetch_sub(1, Ordering::SeqCst), 1);
|
assert_eq!(GUARD.fetch_sub(1, Ordering::SeqCst), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peterson_enter_critical(id: usize, peer_id: usize) {
|
unsafe fn peterson_enter_critical(id: usize, peer_id: usize) {
|
||||||
// println!("Thread[{}] try enter", id);
|
// println!("Thread[{}] try enter", id);
|
||||||
vstore!(&FLAG[id], true);
|
write_volatile(addr_of_mut!(FLAG[id]), true);
|
||||||
vstore!(&TURN, peer_id);
|
write_volatile(addr_of_mut!(TURN), peer_id);
|
||||||
memory_fence!();
|
memory_fence!();
|
||||||
while vload!(&FLAG[peer_id]) && vload!(&TURN) == peer_id {
|
while read_volatile(addr_of!(FLAG[peer_id])) && read_volatile(addr_of!(TURN)) == peer_id {
|
||||||
// println!("Thread[{}] enter fail", id);
|
// println!("Thread[{}] enter fail", id);
|
||||||
sleep(1);
|
sleep(1);
|
||||||
// println!("Thread[{}] retry enter", id);
|
// println!("Thread[{}] retry enter", id);
|
||||||
@ -41,12 +41,12 @@ fn peterson_enter_critical(id: usize, peer_id: usize) {
|
|||||||
// println!("Thread[{}] enter", id);
|
// println!("Thread[{}] enter", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peterson_exit_critical(id: usize) {
|
unsafe fn peterson_exit_critical(id: usize) {
|
||||||
vstore!(&FLAG[id], false);
|
write_volatile(addr_of_mut!(FLAG[id]), false);
|
||||||
// println!("Thread[{}] exit", id);
|
// println!("Thread[{}] exit", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn thread_fn(id: usize) -> ! {
|
pub unsafe fn thread_fn(id: usize) -> ! {
|
||||||
// println!("Thread[{}] init.", id);
|
// println!("Thread[{}] init.", id);
|
||||||
let peer_id: usize = id ^ 1;
|
let peer_id: usize = id ^ 1;
|
||||||
for iter in 0..N {
|
for iter in 0..N {
|
||||||
|
@ -7,6 +7,7 @@ extern crate alloc;
|
|||||||
|
|
||||||
use crate::alloc::string::ToString;
|
use crate::alloc::string::ToString;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ptr::addr_of_mut;
|
||||||
use user_lib::{exit, get_time, thread_create, waittid};
|
use user_lib::{exit, get_time, thread_create, waittid};
|
||||||
|
|
||||||
static mut A: usize = 0;
|
static mut A: usize = 0;
|
||||||
@ -16,7 +17,7 @@ const THREAD_COUNT: usize = 16;
|
|||||||
unsafe fn f(count: usize) -> ! {
|
unsafe fn f(count: usize) -> ! {
|
||||||
let mut t = 2usize;
|
let mut t = 2usize;
|
||||||
for _ in 0..PER_THREAD {
|
for _ in 0..PER_THREAD {
|
||||||
let a = &mut A as *mut usize;
|
let a = addr_of_mut!(A);
|
||||||
let cur = a.read_volatile();
|
let cur = a.read_volatile();
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
t = t * t % 10007;
|
t = t * t % 10007;
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#![feature(linkage)]
|
#![feature(linkage)]
|
||||||
#![feature(panic_info_message)]
|
#![feature(panic_info_message)]
|
||||||
#![feature(alloc_error_handler)]
|
#![feature(alloc_error_handler)]
|
||||||
#![feature(core_intrinsics)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod console;
|
pub mod console;
|
||||||
|
Loading…
Reference in New Issue
Block a user