Skip to main content

rcore 第零章

Ch0 Anwser

1.配环境

我用的是nixos/macos双系统,我的macos也使用的nix-darwin,所以我基本上只用在nisos中配好home-manager,就可以了,当然其实最好的方式是写一个nix shell,然后每次工作的时候使用nix shell

然后qemu没什么好说的,加一个qemu包即可,但是交叉编译工具链可能和普通的包不一样,需要写pkgsCross.riscv64-embedded.buildPackages.gcc ,然后使用alias把riscv64-none-elf-gdb 到riscv64-unknown-elf-gdb,然后clone下rcore的仓库,make run即可,至于为啥是none,具体是由于stdenv的原因

2.exception

在Linux环境下编写一个会产生异常的应用程序,并简要解释操作系统的处理结果

使用rust编写一个除0函数,将报告

> rustc exception.rs
error: this operation will panic at runtime
 --> exception.rs:3:13
  |
3 |     let a = 1/0;
  |             ^^^ attempt to divide `1_i32` by zero
  |
  = note: `#[deny(unconditional_panic)]` on by default

error: aborting due to 1 previous error

如果使用他给的建议#![allow(unconditional_panic)]

> RUST_BACKTRACE=1 ./exception 

thread 'main' panicked at exception.rs:3:13:
attempt to divide by zero
stack backtrace:
   0: __rustc::rust_begin_unwind
             at /rustc/29483883eed69d5fb4db01964cdf2af4d86e9cb2/library/std/src/panicking.rs:697:5
   1: core::panicking::panic_fmt
             at /rustc/29483883eed69d5fb4db01964cdf2af4d86e9cb2/library/core/src/panicking.rs:75:14
   2: core::panicking::panic_const::panic_const_div_by_zero
             at /rustc/29483883eed69d5fb4db01964cdf2af4d86e9cb2/library/core/src/panicking.rs:175:17
   3: exception::main
   4: core::ops::function::FnOnce::call_once
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

会panic,但是看起来并不是操作系统的panic,而是unwind,然后走的编程语言级别的panic,于是打算使用c语言编写

> gcc exception.c      
exception.c: In function ‘main’:
exception.c:3:15: warning: division by zero [-Wdiv-by-zero]
    3 |     int a = 1 / 0;
> ./a.out    
0

很奇怪,为什么不会出错,是不是arm对于除0错误并不会报异常

搜了一下,发现是存在某个寄存器来控制是否报异常

3.sleep

** 在Linux环境下编写一个可以睡眠5秒后打印出一个字符串,并把字符串内容存入一个文件中的应用程序A。(基于C或Rust语言)

学习了一点rust中的文件操作,并学习了一点错误处理相关的知识,得到了如下最佳实践

  • 对于预料之内的错误应该错误传播,如rust中的?

  • 对于预料之外的错误应该立刻panic并退出

  • 函数应该检查参数的合法性,最好将参数定义为一个新类型,并由类型检查来检查合法性

  • 使用unwrap等方法会比match更简洁

之后的代码

use std::io::{self, Write};
use std::{thread, time};
use std::fs::{OpenOptions};

fn main() -> Result<(), io::Error>{
    let mut file = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .truncate(true)
        .open("foo.txt").expect("main: open file Unexpected error");
    loop {
        file.write_all(b"Hello, Rust\n").expect("main: write file unexpected error");
        println!("Hello, Rust!\n");
        thread::sleep(time::Duration::new(5, 0));
    }

4.Concurrency

*** 在Linux环境下编写一个应用程序B,简要说明此程序能够体现操作系统的并发性、异步性、共享性和持久性。(基于C或Rust语言)

有点懵逼,去学了rust book的Fearless Concurrency 但是第三个有点看不懂,就是线程中通过内存共享来通信,因为还没看智能指针部分,然后写下了如下简单的线程代码

use std::{sync::mpsc, thread, time::Duration};

fn main() {
    let (tx, rx) = mpsc::channel();
    let handle = thread::spawn(move || {
        for i in 1..10 {
            println!("hi {i} from spawned thread!");
            //thread::sleep(Duration::from_millis(1));
        }
        tx.send(String::from("hi")).unwrap();
    });
    let received = rx.recv().unwrap();
    for i in 1..10 {
        println!("hi {i} from main thread!");
        //thread::sleep(Duration::from_millis(1));
    }
    println!("got {received}");
    handle.join().unwrap();
}

handle.join().unwrap();let received = rx.recv().unwrap();放在不同位置会打印出不同的结果