
Narrowing the notion of a runtime in Rust - heinrich5991
https://github.com/rust-lang/rust/commit/0efafac398ff7f28c5f0fe756c15b9008b3e0534
======
Animats
They're getting rid of trying to do their own CPU dispatching. (Some people
call this "lightweight threads" or "green threads"; Go's "goroutines" work
that way.) That simplifies things considerably.

There's a compile-time optimization which does many of the things people want
to do with such threads. If you have two tasks communicating over a channel or
queue, only one task writes to the queue, only one task reads from the queue,
and the maximum length of the queue is 1, the code can be compiled as a
coroutine. Go may get that optimization at some point; it's been discussed.

(Things that have been learned about Go goroutines: 1) the above case is
moderately common, 2) for "select", the most common case is N=1 alternatives,
followed by N=2. N>2 is rare. Go has special case code for N=1, and the case
for N>1 is very general and does a lot of dynamic allocation. A special case
for N=2, which in practice is usually read-or-timeout/abort, would be useful.)

~~~
dbaupp
Support for green threads (and hence any manual CPU dispatching) were actually
removed a month ago[18967] along with much of the generic infrastructure for
mediating between 1:1 and M:N threads, the patch linked here just completes
the removal of that infrastructure and switches things to be much closer to
the raw OS in implementation and semantics.

[18967]: [https://github.com/rust-
lang/rust/pull/18967](https://github.com/rust-lang/rust/pull/18967)

~~~
Juan_Shapiro
What impact will big changes like these have on an eventual stable release of
Rust? My team has been reading about Rust for a long time now, and we've tried
it out, but we just can't deal with the constant change. We need a language
that offers what Rust can offer, but we also need our code to still work
without changes a few months after we write it. Earlier this year we were
hearing that a stable release of Rust would be out before the end of 2014. But
that clearly isn't going to happen. The latest I read was that it's now
supposed to be ready sometime in March 2015 at the earliest. I understand that
software schedules slip, and that it's important to get things done right the
first time around whenever possible, but getting out a stable release of Rust
just seems to be dragging on and on! I really, really hope that Rust 1 is
available by this upcoming March, but if history is any indication, that may
be unlikely to happen. Big changes like these don't bring me much comfort at
all.

~~~
keeperofdakeys
Most of this work is occurring precisely so it can be made stable. If you are
curious about the Rust 1.0 cycle, go here [http://blog.rust-
lang.org/2014/12/12/1.0-Timeline.html](http://blog.rust-
lang.org/2014/12/12/1.0-Timeline.html)

The main reason that it's taking a while is they want to get it right. There
are a number of breaking changes in the pipeline that they want to get
finalised, to improve the language. After that, they still have plenty of
features in mind for post 1.0, but these will be added as to not break 1.0
code.

------
NickPollard
This looks to me to be an important and very promising change. I don't know
how much they've had to compromise, but making this easily callable in from C
(and hence, easily callable from other languages with C interop) makes it
simple to embed rust in other languages and applications.

For example, I'd been looking at doing Rust development for Android; currently
native (i.e. C/C++ apps) on Android get run through a Java wrapper; starting a
Rust process with the Rust runtime active is incredibly complex. With this
change, it should be trivial to have a basic Android activity that just calls
a Rust main() and have everything go from there.

~~~
patal
Does anyone know if this makes using Rust code on an Arduino easier? There's
[[https://github.com/jensnockert/dueboot](https://github.com/jensnockert/dueboot)]
which only works on the Due, not the Uno.

~~~
lambda
I think the main blocking part there is getting LLVM working on AVR. I believe
there is a fork of LLVM that does ([https://github.com/sushihangover/llvm-
avr](https://github.com/sushihangover/llvm-avr)), but you would have to merge
that fork with the LLVM that Rust uses in order to run Rust on it, and it
looks like the fork is a little out of date so it may take some work.

This particular likely doesn't affect running Rust on an Arduino at all, as
what it is doing is removing the runtime for std, which contains many of the
OS abstractions. You don't have an OS on an Arduino however, so std isn't
particularly helpful there. Several months ago they already did what was
necessary for that, factoring out much of the completely OS independent
functionality into a "core" library ([http://doc.rust-
lang.org/core/](http://doc.rust-lang.org/core/)), so you can opt out of using
std and use "core" instead, plus add a little bit of platform specific glue,
to run Rust on bare metal.

~~~
MrBuddyCasino
Too bad, I was hoping for easier embedded usage as well. I don't particularly
like the Arduino abstractions, too much is hidden, and to get decent
performance or ADC precision often requires dropping to low-level C or even
assembler.

But the last commit to that fork was just 10 months ago though... might be
tempted to have a look during the holidays.

~~~
errordeveloper
Yeah, as said above, checkout zinc.rs. It runs on ARM MCUs though, but AVRs
are becoming legacy anyway.

~~~
tormeh
Aren't AVR and ARM different power envelopes, though? I thought ARM was for
small computers and AVR is for things that want to be slightly more
complicated than a gearbox.

~~~
zokier
Cortex-A series is for small computers (eg smartphones etc), Cortex-M is more
of a contender for AVR, especially Cortex-M0 which are the smallest ARM cores.
There is currently lot of activity around ARM and power-optimization in the
industry, while AVRs are generally bit older design.

Just for fun, I picked a semi-random example of ARM mcu from digikey:
EFM32ZG110F32[1]. Based on the datasheet it consumes about 8mW when running on
full 24MHz speed. Meanwhile the AVR chip used in eg. Arduino Uno[2] consumes
about 10mW when running at 8MHz. Of course at these ultra-low power levels
there are quite a large amount of variability depending exactly what you are
doing and how well your code is made.

[1] [http://www.digikey.com/product-
detail/en/EFM32ZG110F32-QFN24...](http://www.digikey.com/product-
detail/en/EFM32ZG110F32-QFN24/336-2578-2-ND/4457701)

[2] Atmega 328p
[http://www.atmel.com/devices/atmega328p.aspx](http://www.atmel.com/devices/atmega328p.aspx)

------
alexanderblom
Link to the PR: [https://github.com/rust-
lang/rust/pull/19654](https://github.com/rust-lang/rust/pull/19654)

~~~
sciurus
and to the RFC: [https://github.com/rust-
lang/rfcs/blob/master/text/0230-remo...](https://github.com/rust-
lang/rfcs/blob/master/text/0230-remove-runtime.md)

------
cosarara97
I'm more surprised to find Lovecraft quotes in Rust's source code:

[https://github.com/rust-
lang/rust/blob/6bdce25e155d846bb9252...](https://github.com/rust-
lang/rust/blob/6bdce25e155d846bb9252fa4a18baef7e74cf8bf/src/librustrt/util.rs)

~~~
kibwen
And in your Rust binaries, though this is a bug long since acknowledged :)
[https://github.com/rust-lang/rust/issues/13871](https://github.com/rust-
lang/rust/issues/13871)

(And one of those isn't a Lovecraft quote, it's a Majora's Mask quote.)

------
imron
This is going to make rust so much easier for me to use in serious projects. I
have a ton of stuff in c++ that I can't realistically just stop using. I'd
love to be able to start introducing rust into those code bases however and
this will make things much less hassle.

------
ikawe
Ok, I don't know rust at all, but often when I'm trying to understand a
change, I look at how it affects the test cases.

Seeing the diff in the test cases should show how the API has changed, but I'm
having a hard time reconciling the description of the changes with how the
tests have changed.

There are several occurrences of changes like this:

    
    
        - spawn(move|| {
        + Thread::spawn(move|| {
             tx.send(i);
        - })
        + }).detach()
    

Thread methods have been namespaced under "Thread::" and now a "detach" method
is appended to each call to spawn.

Can anyone shed some light?

~~~
kibwen
In ancient Rust, the standard library attempted to provide an abstraction over
the underlying threading model. The purpose of this abstraction, called a
"task", was to allow libraries to make use of the standard concurrency
constructs while allowing the _consumers_ of those libraries to determine
whether or not to use 1:1 threading (the typical platform thread model) or M:N
threading (green threads), and it would all Just Work with no effort required.

This was quite an exciting idea at the time. However, in practice, it just
didn't pan out: the compromises required to paper over the differences between
1:1 threading and M:N threading managed to almost entirely obliterate the
respective advantages of both models.

As a result, Rust is in the process of removing the "tasks" abstraction and
replacing it with a bog-standard 1:1 threading model (though it still benefits
from all the typical memory-safe and concurrency-safe abstractions that Rust
otherwise provides). All users of concurrency in the stdlib will now be using
native threads, and it will be left to outside implementors to experiment with
green threading libraries (see
[https://github.com/carllerche/mio](https://github.com/carllerche/mio) for one
example of such).

One of the consequences of this change is that the `std::task` module has been
replaced with `std::thread`. Formerly, every Rust program imported the
function `std::task::spawn` to use for spawning tasks. With the removal of
`std::task`, the newly analogous function from `std::thread` has not been
added to the prelude, and is therefore not imported by default in every Rust
program. It could be added if such a thing were desired (you can see remarks
to this effect in the comments on the PR itself ([https://github.com/rust-
lang/rust/pull/19654#issuecomment-66...](https://github.com/rust-
lang/rust/pull/19654#issuecomment-66239082) and [https://github.com/rust-
lang/rust/pull/19654#issuecomment-66...](https://github.com/rust-
lang/rust/pull/19654#issuecomment-66956364) )).

~~~
mietek
What a disappointment.

~~~
thomasahle
I like it. Platform threads should just be lightweight enough, that you don't
have to patch on top of them.

And if you really need to M:N behaviour, it is still available as a library.

~~~
lgunsch
The two different threading models have different costs/benifits. Native
threads are much faster at context switching then green threads, however,
native threads have a significant startup cost where as spawning green threads
is nearly cost-free.

~~~
imanaccount247
>Native threads are much faster at context switching then green threads

No, native threads have a much higher context switch overhead. The downside of
green threads is the lack of parallelism, you can only use one CPU core. This
is why decent languages multiplex green threads over OS threads (M:N). The
mistake rust made was trying to make that distinction transparent.

~~~
lgunsch
Quote from Wikipedia article on Green Threads: "Linux native threads have
slightly better performance on I/O and context switching operations."

Some of the actual context switch in native threads is performed by the CPU,
where as with green threads it is not. On top of this, the whole stack is
copied upon a context switch.

~~~
SamReidHughes
Wikipedia is wrong and generally speaking you shouldn't trust it on CS
matters. Or any other subject, really. Green thread context switching is much
faster than native thread switching, as long as you don't do it badly. For
example, on Linux, don't use setcontext/swapcontext/etc, because they do a
system call to change the signal mask.

------
jephir
Does removing the runtime have any effect on the current effort to get Rust
working on Emscripten?

~~~
kibwen
Very simple and stripped-down Rust programs have already been demonstrated to
work via Emscripten. I expect the work here would make it a little bit easier,
but I don't know of anyone actively working on supporting this use case.

Last I heard, more advanced support hinged on Emscripten upgrading their
version of LLVM, which was much more ancient than the bleeding-edge version
that Rust uses.

------
xfalcox
I'm not a low level guy, but this means we can have rust libs callable from
ruby gems through C interop?

Isn't this fucking awesome?

~~~
kibwen
Not only is this already possible, but the largest production deployment of
Rust does exactly this (www.skylight.io).

Here's a dummy repo from steveklabnik to demonstrate the process:
[https://github.com/steveklabnik/rust_example](https://github.com/steveklabnik/rust_example)
(though the change in the OP is so now that I doubt this repo has yet been
updated)

~~~
steveklabnik
I compiled a Rust yesterday, ran `make`, and it worked, sooo...

------
btown
Is this going to be part of the 1.0 release schedule, then? It seems
ridiculously breaking when they're only 20 days from stable!

[http://blog.rust-lang.org/2014/12/12/1.0-Timeline.html](http://blog.rust-
lang.org/2014/12/12/1.0-Timeline.html)

~~~
kibwen
Don't expect the January 9th alpha to signal the end of breaking changes. It
merely represents a significant raising of the bar for breaking changes to be
accepted. The subsequent betas will raise the bar even further.

In fact, as we approach the alpha, I expect several frantic last-minute
breaking changes as people attempt to beat the buzzer.

~~~
blt
Why did you decide to use hard deadline project management? It seems like
Rust's ideals of correctness and fixing fundamental C/C++ flaws are more
aligned with a "when it's done" release. On the other hand, the language needs
a stable release to pick up many users. I'm guessing the latter was your
motivator. And knowing that real world users will likely find problems with
your design no matter how long you spent perfecting it. Just curious what went
into the decision.

~~~
scott_s
I think it's worth noting that 1.0 is a _stable_ release, meaning that any 1.x
future release will not introduce breaking changes. But that does not preclude
them from eventually releasing a 2.0 which does break compatibility with 1.0.

That allows them to tell people that, yes, they _can_ depend on the fact that
the language and API will not change from, say, 1.2 to 1.3. And that they will
continue to support it for the foreseeable future. But I imagine that
eventually they will want to make breaking changes, as they certainly won't
get everything completely right with 1.0. But that will be clearly marked as
an entirely new version.

~~~
MichaelGG
Except the std lib isn't going stable for 1.0. They have a system that marks
which APIs are stable, but a lot of stuff is still unstable/experimental. So
it's very possible to write a Rust 1.0 program that won't work on 1.x, if you
used those parts if the stdlib. Fortunately, the compiler can warn you of this
so you know what you're getting into.

~~~
dbaupp
The plan is to have those unstable parts disabled in the stable compiler, so
that any program that works with rustc 1.0 will work with rustc 1.x etc. One
can use those parts via the nightly branch. The plan is also to try to have
much of the most useful parts of the stdlib stable (at least the core
functionality).

More info:

\- [https://github.com/rust-lang/rfcs/pull/507](https://github.com/rust-
lang/rfcs/pull/507)

\- [http://blog.rust-lang.org/2014/12/12/1.0-Timeline.html](http://blog.rust-
lang.org/2014/12/12/1.0-Timeline.html)

------
MichaelGG
Now to remove unwinding and make it optional, or make fully recoverable
exceptions... This seems like the biggest controversy in Rust, and it sounds
like the plan is to just make unwinding optional, though last I read, that
means two incompatible stdlibs and s need to compile everything in two
different modes. Still it'd be really nice to not have unwinding when your
program doesn't need it, but also be able to make apps that benefit from
exceptions, like web servers.

~~~
fanf2
Isn't unwinding a standard part of C/C++ ABIs these days? I would have thought
that disabling it would cause more compatibility problems than supporting it.

------
saosebastiao
Is it possible to have a threading model without an OS kernel? In other words,
is it possible to package the rust runtime with an embedded execatable and run
threaded software without the OS? Or does threading inherently require the OS
to do the thread scheduling, etc.?

~~~
dexen
Plan 9's libthread [1] implements _cooperative_ threading entirely in
userspace library. This is apart of Plan 9's fork() [2] syscall which allows
both forking processes and creating kernel-level threads.

Thanks to libthread being orthogonal to processes, it turned out to be easily
portable.

[1]
[http://man.cat-v.org/plan_9/2/thread](http://man.cat-v.org/plan_9/2/thread)

[2] [http://man.cat-v.org/plan_9/2/fork](http://man.cat-v.org/plan_9/2/fork)
\-- this is what linux' clone(3) syscall was modeled after.

------
andrewchambers
It seems to me like the designers really couldn't make up their minds.

Do you want GC or not? Do you want lightweight threads or not? What level of
runtime requirements do you want?

Its finally converging on something sane, but its taken a while.

~~~
jeffreyrogers
I've thought similar things when I've looked at Rust in the past. It seems to
me that designers really wanted to make it nice from a PL theory perspective,
(hence the focus on functional programming and a strong type system). I'm more
partial to the Go style of language design, which focused on making it easy to
do the things the designers did in practice.

I don't want to make it seem like I'm coming down too hard on Rust however,
and I'm excited to see how everything works out once version 1.0 is released.

~~~
jeffdavis
For the time I've been interested in rust, it's been quite focused on a very
practical problem: safe, without requiring a GC.

