The vast majority of Rust users use stable. You just happen to see a lot of folks who are interested in the cutting edge blog about things. (You may also run into older things where that thing is stable now, too, to be clear.)
It depends on the features you enable. Stable is basically just a pinned nightly version with no features enabled, and I'd definitely view "nightly with no features" as more stable than most languages.
Using some of the more experimental features would make it less stable, you can generally get a feel for how stable a feature is by looking at it's tracking issue.
These days most tutorials/books/tools don't seem to use nightly in my experience, though many still do. But if you're primarily looking at blog posts that are pushing the boundaries of the language (e.g. by writing operating systems) I expect that most of them would be using nightly.
Whether that generally happens in reality, or people get into a loop of "well, this other new features is nice and in nightly, and we're already in it, so why not", I'm not sure.
In my experience, that is rarely the case.
People mostly use nightly features because they just need to get something done, and these features make that easier.
The tooling around Rust is quite good (rustup, cargo, docker), so if you follow the language a bit, judge which nightly features you opt-into, pin nightly version in your build environment, etc. breakage only happens when you actually have time to fix it and the fixes are simple.
So the bar for how much easier a nightly feature needs to make your problem to overcome its costs is quite low. The moment you are using one nightly feature, the cost of using more is even smaller.
There are two uses for nightly:
1. Access to unreleased features. I think I'm down to just needing this for associated_type_defaults (rfc here: https://github.com/rust-lang/rfcs/pull/2532/files). 2. Nightly allows passing extra compiler flags, which is occasionally useful for debugging things like macro expansion.
Personally I've found that nightly is pretty solid and I do tend to use it more than stable, but I certainly would not consider it dirty in itself. Furthermore if you're looking at a tutorial or a book the features it relies upon may have gotten into the stable build.
* move asm! to llvm_asm. https://github.com/rust-lang/rust/pull/68404
* implement the actual asm! we want to stabilize: https://github.com/rust-lang/rfcs/pull/2873
* stabilize it
Curious why not WASM also? I have no use case for that, just asking.
This is the only reason I am still using nightly builds...because I'm forced to use the asm language feature, which is unstable, and because it's unstable, it cannot be used on the stable channel.
Edit: to respond to the second half, for out-of-the-box Rust builds, yes, I need global_asm! and asm!. However, asm! is for inline assembly only. Originally, I used GNU's assembler to assemble and then linked using GNU's ld. However, I have since switched to trying to make Rust do everything through its build manager, cargo.
It looks like what you're referring to is the interim plan to rename asm! to llvm_asm! (which will never be stabilized), since it's a very thin wrapper over the current LLVM inline asm support, and then replace asm! with a better implementation.
There is a working group specifically for inline asm, so it will happen eventually... but it's not going to be a quick process--think about how long async/await takes, and inline asm is actually rather close to that in terms of all the issues that come out of it.
I wish someday we'll get something like the ESP32 boards but with RISCV.
You might want to check out the Kendryte K210. I'm trying out these boards for development. They are designed with two (I think) 64-bit RISC-V cores with a hardware FPU. https://www.seeedstudio.com/blog/2019/09/12/get-started-with...
I've flashed mine a few times, but I'm still working to getting it to work. The documentation isn't very good, so I'm working to reverse engineer some aspects of it.
This is a low cost alternative. Of course, we could go with the SiFive Unleashed (64-bit) or the SiFive HiFive1, which uses a 32-bit RISC-V CPU in an Arduino form factor. https://www.sifive.com/boards
The SiFive Unleashed cost me a cool $1k, so I'm still scared to mess with it.
The most interesting route is using an FPGA. There are many examples of running RISC-V softcores on FPGAs (for example, Berkeley's RocketChip) and many boards that support a decent amount of memory (even beyond 1 GiB).
ULP-RISCV has the following features:
support for IMC instruction set
thirty-two 32-bit general-purpose registers
32-bit multiplier and divider
support for interrupts
boot by the CPU, its dedicated timer, or RTC GPIO
https://www.espressif.com/sites/default/files/documentation/...This would be good for embedded applications on Raspberry Pi sized machines, where the Arduino environment is too weak and Linux is too much.
The fast interprocess call mechanism is what makes it all go. It's mostly about it being simple. Mach tried to get too cute, moving pages from one address space to another. Turns out that copying is usually cheaper than stalling out the CPU and flushing caches while you mess with the page tables of recently active pages. L4 just offers shared memory, dumping the problem on the next level up. QNX offers useful send/receive message functionality that goes fast. Yes, there's a penalty, maybe 20%. But you usually get that back because you're not forced to do interprocess communication with something far slower, like HTTP.
> The singly-indirect pointer can address 1,024 * 1,024 / 4 = 1,024 * 256 = 262 KiB of data.
256 kilobytes, not 262 'kibi'bytes.
> 1,024 * 256 * 256 = 67 Mi
> 1,024 * 256 * 256 * 256 = 17 Gi
64 and 16 respectively.
All jokes aside. Fixed, thanks.
The seven blocks at the start would make it 263 KB, but I don't think that what you meant.
Any thoughts on this[1] walkthrough in comparison? This one looks more explicitly up to date.
As a note, I believe os.phil-opp.com is using the AMD/Intel architecture.
Nowadays I might point at MIT's xv6, which implements a very similar simple unix filesystem: https://github.com/mit-pdos/xv6-public/blob/master/fs.c
My only criticism is that sometimes there's parts in your tutorial that are missing but present in your os. When going through chapter 3/4 I think you skipped over explaining your kmalloc implementation. It's fine that you do since I feel your tutorial should be more about navigating embedded rust than learning os basics, but a note about this task being implemented at some point would've helped.
I do try to put lots of comments in the Rust code to describe what I didn't in the blog for those more interested in the implementation.
>"Recall that the block driver makes a request and sends it off to the block device. The block device services the request and then sends an interrupt when it's finished. We don't really know when that interrupt will come, and we can't wait around for it. This is why I decided to make the file system reader a kernel process. We can put this kernel process in the waiting state so it won't be scheduled until the interrupt is received from the block device"
Then further down: >"Now, when we handle the block device's interrupt, we have to match the watcher and awaken it."
Is the watcher here similar to the filesystem driver at the VFS layer in Linux i.e the ext4/xfs etc? I believe this is how Linux handles it - the file system driver creates a block IO request and hands it off to the actual block device driver and when the block device driver get's invoked on an interrupt from the disk the block device driver informs the filesystem driver that the IO request is now complete correct?