Skip to content

Commit 9545a10

Browse files
committed
---
yaml --- r: 137727 b: refs/heads/auto c: dae48a0 h: refs/heads/master i: 137725: c1f1d95 137723: b222b25 137719: ac8a74c 137711: af07965 137695: e352483 137663: 1fefb9a 137599: 1aa336c 137471: aa54fd2 137215: 4b4d2f9 v: v3
1 parent 291982e commit 9545a10

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+425
-342
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ refs/heads/try3: 9387340aab40a73e8424c48fd42f0c521a4875c0
1313
refs/tags/release-0.3.1: 495bae036dfe5ec6ceafd3312b4dca48741e845b
1414
refs/tags/release-0.4: e828ea2080499553b97dfe33b3f4d472b4562ad7
1515
refs/tags/release-0.5: 7e3bcfbf21278251ee936ad53e92e9b719702d73
16-
refs/heads/auto: ba246100ca3b0c3bd0d68548677d75e6790c4f60
16+
refs/heads/auto: dae48a07f34dcf714b3b57029f4e03a0b95a269e
1717
refs/heads/servo: af82457af293e2a842ba6b7759b70288da276167
1818
refs/tags/release-0.6: b4ebcfa1812664df5e142f0134a5faea3918544c
1919
refs/tags/0.1: b19db808c2793fe2976759b85a355c3ad8c8b336

branches/auto/mk/docs.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
######################################################################
2828
DOCS := index intro tutorial guide guide-ffi guide-macros guide-lifetimes \
2929
guide-tasks guide-container guide-pointers guide-testing \
30-
guide-plugin complement-bugreport \
30+
guide-runtime guide-plugin complement-bugreport \
3131
complement-lang-faq complement-design-faq complement-project-faq rust \
3232
rustdoc guide-unsafe guide-strings reference
3333

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
% A Guide to the Rust Runtime
2+
3+
Rust includes two runtime libraries in the standard distribution, which provide
4+
a unified interface to primitives such as I/O, but the language itself does not
5+
require a runtime. The compiler is capable of generating code that works in all
6+
environments, even kernel environments. Neither does the Rust language need a
7+
runtime to provide memory safety; the type system itself is sufficient to write
8+
safe code, verified statically at compile time. The runtime merely uses the
9+
safety features of the language to build a number of convenient and safe
10+
high-level abstractions.
11+
12+
That being said, code without a runtime is often very limited in what it can do.
13+
As a result, Rust's standard libraries supply a set of functionality that is
14+
normally considered the Rust runtime. This guide will discuss Rust's user-space
15+
runtime, how to use it, and what it can do.
16+
17+
# What is the runtime?
18+
19+
The Rust runtime can be viewed as a collection of code which enables services
20+
like I/O, task spawning, TLS, etc. It's essentially an ephemeral collection of
21+
objects which enable programs to perform common tasks more easily. The actual
22+
implementation of the runtime itself is mostly a sparse set of opt-in primitives
23+
that are all self-contained and avoid leaking their abstractions into libraries.
24+
25+
The current runtime is the engine behind these features (not a comprehensive
26+
list):
27+
28+
* I/O
29+
* Task spawning
30+
* Message passing
31+
* Task synchronization
32+
* Task-local storage
33+
* Logging
34+
* Task unwinding
35+
36+
## What is the runtime accomplishing?
37+
38+
The runtime is designed with a few goals in mind:
39+
40+
* Rust libraries should work in a number of environments without having to worry
41+
about the exact details of the environment itself. Two commonly referred to
42+
environments are the M:N and 1:1 environments. Since the Rust runtime was
43+
first designed, it has supported M:N threading, and it has since gained 1:1
44+
support as well.
45+
46+
* The runtime should not enforce separate "modes of compilation" in order to
47+
work in multiple circumstances. It is an explicit goal that you compile a Rust
48+
library once and use it forever (in all environments).
49+
50+
* The runtime should be fast. There should be no architectural design barrier
51+
which is preventing programs from running at optimal speeds. It is not a goal
52+
for the runtime to be written "as fast as can be" at every moment in time. For
53+
example, no claims will be made that the current implementation of the runtime
54+
is the fastest it will ever be. This goal is simply to prevent any
55+
architectural roadblock from hindering performance.
56+
57+
* The runtime should be nearly invisible. The design of the runtime should not
58+
encourage direct interaction with it, and using the runtime should be
59+
essentially transparent to libraries. This does not mean it should be
60+
impossible to query the runtime, but rather it should be unconventional.
61+
62+
# Architecture of the runtime
63+
64+
This section explains the current architecture of the Rust runtime. It has
65+
evolved over the development of Rust through many iterations, and this is simply
66+
the documentation of the current iteration.
67+
68+
## A local task
69+
70+
The core abstraction of the Rust runtime is the task. A task represents a
71+
"thread" of execution of Rust code, but it does not necessarily correspond to an
72+
OS thread. Most runtime services are accessed through the local task, allowing
73+
for runtime policy decisions to be made on a per-task basis.
74+
75+
A consequence of this decision is to require all Rust code using the standard
76+
library to have a local `Task` structure available to them. This `Task` is
77+
stored in the OS's thread local storage (OS TLS) to allow for efficient access
78+
to it.
79+
80+
It has also been decided that the presence or non-presence of a local `Task` is
81+
essentially the *only* assumption that the runtime can make. Almost all runtime
82+
services are routed through this local structure.
83+
84+
This requirement of a local task is a core assumption on behalf of *all* code
85+
using the standard library, hence it is defined in the standard library itself.
86+
87+
## I/O
88+
89+
When dealing with I/O in general, there are a few flavors by which it can be
90+
dealt with, and not all flavors are right for all situations. I/O is also a
91+
tricky topic that is nearly impossible to get consistent across all
92+
environments. As a result, a Rust task is not guaranteed to have access to I/O,
93+
and it is not even guaranteed what the implementation of the I/O will be.
94+
95+
This conclusion implies that I/O *cannot* be defined in the standard library.
96+
The standard library does, however, provide the interface to I/O that all Rust
97+
tasks are able to consume.
98+
99+
This interface is implemented differently for various flavors of tasks, and is
100+
designed with a focus around synchronous I/O calls. This architecture does not
101+
fundamentally prevent other forms of I/O from being defined, but it is not done
102+
at this time.
103+
104+
The I/O interface that the runtime must provide can be found in the
105+
[std::rt::rtio](std/rt/rtio/trait.IoFactory.html) module. Note that this
106+
interface is *unstable*, and likely always will be.
107+
108+
## Task Spawning
109+
110+
A frequent operation performed by tasks is to spawn a child task to perform some
111+
work. This is the means by which parallelism is enabled in Rust. This decision
112+
of how to spawn a task is not a general decision, and is hence a local decision
113+
to the task (not defined in the standard library).
114+
115+
Task spawning is interpreted as "spawning a sibling" and is enabled through the
116+
high level interface in `std::task`. The child task can be configured
117+
accordingly, and runtime implementations must respect these options when
118+
spawning a new task.
119+
120+
Another local task operation is dealing with the runnable state of the task
121+
itself. This frequently comes up when the question is "how do I block a task?"
122+
or "how do I wake up a task?". These decisions are inherently local to the task
123+
itself, yet again implying that they are not defined in the standard library.
124+
125+
## The `Runtime` trait and the `Task` structure
126+
127+
The full complement of runtime features is defined by the [`Runtime`
128+
trait](std/rt/trait.Runtime.html) and the [`Task`
129+
struct](std/rt/task/struct.Task.html). A `Task` is constant among all runtime
130+
implementations, but each runtime has its own implementation of the
131+
`Runtime` trait.
132+
133+
The local `Task` stores the runtime value inside of itself, and then ownership
134+
dances ensue to invoke methods on the runtime.
135+
136+
# Implementations of the runtime
137+
138+
The Rust distribution provides two implementations of the runtime. These two
139+
implementations are generally known as 1:1 threading and M:N threading.
140+
141+
As with many problems in computer science, there is no right answer in this
142+
question of which implementation of the runtime to choose. Each implementation
143+
has its benefits and each has its drawbacks. The descriptions below are meant to
144+
inform programmers about what the implementation provides and what it doesn't
145+
provide in order to make an informed decision about which to choose.
146+
147+
## 1:1 - using `libnative`
148+
149+
The library `libnative` is an implementation of the runtime built upon native OS
150+
threads plus libc blocking I/O calls. This is called 1:1 threading because each
151+
user-space thread corresponds to exactly one kernel thread.
152+
153+
In this model, each Rust task corresponds to one OS thread, and each I/O object
154+
essentially corresponds to a file descriptor (or the equivalent of the platform
155+
you're running on).
156+
157+
Some benefits to using libnative are:
158+
159+
* Guaranteed interop with FFI bindings. If a C library you are using blocks the
160+
thread to do I/O (such as a database driver), then this will not interfere
161+
with other Rust tasks (because only the OS thread will be blocked).
162+
* Less I/O overhead as opposed to M:N in some cases. Not all M:N I/O is
163+
guaranteed to be "as fast as can be", and some things (like filesystem APIs)
164+
are not truly asynchronous on all platforms, meaning that the M:N
165+
implementation may incur more overhead than a 1:1 implementation.
166+
167+
## M:N - using `libgreen`
168+
169+
The library `libgreen` implements the runtime with "green threads" on top of the
170+
asynchronous I/O framework [libuv][libuv]. The M in M:N threading is the number
171+
of OS threads that a process has, and the N is the number of Rust tasks. In this
172+
model, N Rust tasks are multiplexed among M OS threads, and context switching is
173+
implemented in user-space.
174+
175+
The primary concern of an M:N runtime is that a Rust task cannot block itself in
176+
a syscall. If this happens, then the entire OS thread is frozen and unavailable
177+
for running more Rust tasks, making this a (M-1):N runtime (and you can see how
178+
this can reach 0/deadlock). By using asynchronous I/O under the hood (all I/O
179+
still looks synchronous in terms of code), OS threads are never blocked until
180+
the appropriate time comes.
181+
182+
Upon reading `libgreen`, you may notice that there is no I/O implementation
183+
inside of the library, but rather just the infrastructure for maintaining a set
184+
of green schedulers which switch among Rust tasks. The actual I/O implementation
185+
is found in `librustuv` which are the Rust bindings to libuv. This distinction
186+
is made to allow for other I/O implementations not built on libuv (but none
187+
exist at this time).
188+
189+
Some benefits of using libgreen are:
190+
191+
* Fast task spawning. When using M:N threading, spawning a new task can avoid
192+
executing a syscall entirely, which can lead to more efficient task spawning
193+
times.
194+
* Fast task switching. Because context switching is implemented in user-space,
195+
all task contention operations (mutexes, channels, etc) never execute
196+
syscalls, leading to much faster implementations and runtimes. An efficient
197+
context switch also leads to higher throughput servers than 1:1 threading
198+
because tasks can be switched out much more efficiently.
199+
200+
### Pools of Schedulers
201+
202+
M:N threading is built upon the concept of a pool of M OS threads (which
203+
libgreen refers to as schedulers), able to run N Rust tasks. This abstraction is
204+
encompassed in libgreen's [`SchedPool`](green/struct.SchedPool.html) type. This type allows for
205+
fine-grained control over the pool of schedulers which will be used to run Rust
206+
tasks.
207+
208+
In addition the `SchedPool` type is the *only* way through which a new M:N task
209+
can be spawned. Sibling tasks to Rust tasks themselves (created through
210+
`std::task::spawn`) will be spawned into the same pool of schedulers that the
211+
original task was home to. New tasks must previously have some form of handle
212+
into the pool of schedulers in order to spawn a new task.
213+
214+
## Which to choose?
215+
216+
With two implementations of the runtime available, a choice obviously needs to
217+
be made to see which will be used. The compiler itself will always by-default
218+
link to one of these runtimes.
219+
220+
Having a default decision made in the compiler is done out of necessity and
221+
convenience. The compiler's decision of runtime to link to is *not* an
222+
endorsement of one over the other. As always, this decision can be overridden.
223+
224+
For example, this program will be linked to "the default runtime". The current
225+
default runtime is to use libnative.
226+
227+
~~~{.rust}
228+
fn main() {}
229+
~~~
230+
231+
### Force booting with libgreen
232+
233+
In this example, the `main` function will be booted with I/O support powered by
234+
libuv. This is done by linking to the `rustuv` crate and specifying the
235+
`rustuv::event_loop` function as the event loop factory.
236+
237+
To create a pool of green tasks which have no I/O support, you may shed the
238+
`rustuv` dependency and use the `green::basic::event_loop` function instead of
239+
`rustuv::event_loop`. All tasks will have no I/O support, but they will still be
240+
able to deschedule/reschedule (use channels, locks, etc).
241+
242+
~~~{.ignore}
243+
extern crate green;
244+
extern crate rustuv;
245+
246+
#[start]
247+
fn start(argc: int, argv: *const *const u8) -> int {
248+
green::start(argc, argv, rustuv::event_loop, main)
249+
}
250+
251+
fn main() {}
252+
~~~
253+
254+
### Force booting with libnative
255+
256+
This program's `main` function will always be booted with libnative, running
257+
inside of an OS thread.
258+
259+
~~~{.rust}
260+
extern crate native;
261+
262+
#[start]
263+
fn start(argc: int, argv: *const *const u8) -> int {
264+
native::start(argc, argv, main)
265+
}
266+
267+
fn main() {}
268+
~~~
269+
270+
# Finding the runtime
271+
272+
The actual code for the runtime is spread out among a few locations:
273+
274+
* [std::rt][stdrt]
275+
* [libnative][libnative]
276+
* [libgreen][libgreen]
277+
* [librustuv][librustuv]
278+
279+
[libuv]: https://github.com/joyent/libuv/
280+
[stdrt]: std/rt/index.html
281+
[libnative]: native/index.html
282+
[libgreen]: green/index.html
283+
[librustuv]: rustuv/index.html

branches/auto/src/doc/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ a guide that can help you out:
6262
* [Writing Unsafe and Low-Level Code](guide-unsafe.html)
6363
* [Macros](guide-macros.html)
6464
* [Testing](guide-testing.html)
65+
* [Rust's Runtime](guide-runtime.html)
6566
* [Compiler Plugins](guide-plugin.html)
6667

6768
# Tools

branches/auto/src/doc/po4a.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
[type: text] src/doc/guide-macros.md $lang:doc/l10n/$lang/guide-macros.md
1616
[type: text] src/doc/guide-plugin.md $lang:doc/l10n/$lang/guide-plugin.md
1717
[type: text] src/doc/guide-pointers.md $lang:doc/l10n/$lang/guide-pointers.md
18+
[type: text] src/doc/guide-runtime.md $lang:doc/l10n/$lang/guide-runtime.md
1819
[type: text] src/doc/guide-strings.md $lang:doc/l10n/$lang/guide-strings.md
1920
[type: text] src/doc/guide-tasks.md $lang:doc/l10n/$lang/guide-tasks.md
2021
[type: text] src/doc/guide-testing.md $lang:doc/l10n/$lang/guide-testing.md

branches/auto/src/libcollections/string.rs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -928,29 +928,6 @@ impl<S: Str> Add<S, String> for String {
928928
}
929929
}
930930

931-
#[cfg(stage0)]
932-
impl ops::Slice<uint, str> for String {
933-
#[inline]
934-
fn as_slice_<'a>(&'a self) -> &'a str {
935-
self.as_slice()
936-
}
937-
938-
#[inline]
939-
fn slice_from_<'a>(&'a self, from: &uint) -> &'a str {
940-
self[][*from..]
941-
}
942-
943-
#[inline]
944-
fn slice_to_<'a>(&'a self, to: &uint) -> &'a str {
945-
self[][..*to]
946-
}
947-
948-
#[inline]
949-
fn slice_<'a>(&'a self, from: &uint, to: &uint) -> &'a str {
950-
self[][*from..*to]
951-
}
952-
}
953-
#[cfg(not(stage0))]
954931
impl ops::Slice<uint, str> for String {
955932
#[inline]
956933
fn as_slice_<'a>(&'a self) -> &'a str {

branches/auto/src/libcollections/trie.rs

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -389,15 +389,6 @@ macro_rules! bound {
389389

390390
impl<T> TrieMap<T> {
391391
// If `upper` is true then returns upper_bound else returns lower_bound.
392-
#[cfg(stage0)]
393-
#[inline]
394-
fn bound<'a>(&'a self, key: uint, upper: bool) -> Entries<'a, T> {
395-
bound!(Entries, self = self,
396-
key = key, is_upper = upper,
397-
slice_from = slice_from_, iter = iter,
398-
mutability = )
399-
}
400-
#[cfg(not(stage0))]
401392
#[inline]
402393
fn bound<'a>(&'a self, key: uint, upper: bool) -> Entries<'a, T> {
403394
bound!(Entries, self = self,
@@ -440,15 +431,6 @@ impl<T> TrieMap<T> {
440431
self.bound(key, true)
441432
}
442433
// If `upper` is true then returns upper_bound else returns lower_bound.
443-
#[cfg(stage0)]
444-
#[inline]
445-
fn bound_mut<'a>(&'a mut self, key: uint, upper: bool) -> MutEntries<'a, T> {
446-
bound!(MutEntries, self = self,
447-
key = key, is_upper = upper,
448-
slice_from = slice_from_mut_, iter = iter_mut,
449-
mutability = mut)
450-
}
451-
#[cfg(not(stage0))]
452434
#[inline]
453435
fn bound_mut<'a>(&'a mut self, key: uint, upper: bool) -> MutEntries<'a, T> {
454436
bound!(MutEntries, self = self,

0 commit comments

Comments
 (0)