Skip to content

Commit bca0fe2

Browse files
committed
---
yaml --- r: 91644 b: refs/heads/auto c: 61f76a5 h: refs/heads/master v: v3
1 parent 223bf40 commit bca0fe2

File tree

209 files changed

+6917
-3961
lines changed

Some content is hidden

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

209 files changed

+6917
-3961
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: 0966ec01dcb0ff90e6d483706820794ef8e16c2e
16+
refs/heads/auto: 61f76a51300fd61369255850a41e04720681fcf8
1717
refs/heads/servo: af82457af293e2a842ba6b7759b70288da276167
1818
refs/tags/release-0.6: b4ebcfa1812664df5e142f0134a5faea3918544c
1919
refs/tags/0.1: b19db808c2793fe2976759b85a355c3ad8c8b336

branches/auto/.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
*.cps
3131
*.log
3232
*.pdf
33-
*.epub
3433
*.html
3534
*.pg
3635
*.toc

branches/auto/doc/tutorial-ffi.md

Lines changed: 143 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ extern {
1919
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
2020
}
2121
22+
#[fixed_stack_segment]
2223
fn main() {
2324
let x = unsafe { snappy_max_compressed_length(100) };
24-
println!("max compressed length of a 100 byte buffer: {}", x);
25+
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
2526
}
2627
~~~~
2728

@@ -35,6 +36,11 @@ interfaces that aren't thread-safe, and almost any function that takes a pointer
3536
valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of
3637
Rust's safe memory model.
3738

39+
Finally, the `#[fixed_stack_segment]` annotation that appears on
40+
`main()` instructs the Rust compiler that when `main()` executes, it
41+
should request a "very large" stack segment. More details on
42+
stack management can be found in the following sections.
43+
3844
When declaring the argument types to a foreign function, the Rust compiler will not check if the
3945
declaration is correct, so specifying it correctly is part of keeping the binding correct at
4046
runtime.
@@ -75,6 +81,8 @@ length is number of elements currently contained, and the capacity is the total
7581
the allocated memory. The length is less than or equal to the capacity.
7682

7783
~~~~ {.xfail-test}
84+
#[fixed_stack_segment]
85+
#[inline(never)]
7886
pub fn validate_compressed_buffer(src: &[u8]) -> bool {
7987
unsafe {
8088
snappy_validate_compressed_buffer(vec::raw::to_ptr(src), src.len() as size_t) == 0
@@ -86,6 +94,36 @@ The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, b
8694
guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
8795
signature.
8896

97+
The `validate_compressed_buffer` wrapper is also annotated with two
98+
attributes `#[fixed_stack_segment]` and `#[inline(never)]`. The
99+
purpose of these attributes is to guarantee that there will be
100+
sufficient stack for the C function to execute. This is necessary
101+
because Rust, unlike C, does not assume that the stack is allocated in
102+
one continuous chunk. Instead, we rely on a *segmented stack* scheme,
103+
in which the stack grows and shrinks as necessary. C code, however,
104+
expects one large stack, and so callers of C functions must request a
105+
large stack segment to ensure that the C routine will not run off the
106+
end of the stack.
107+
108+
The compiler includes a lint mode that will report an error if you
109+
call a C function without a `#[fixed_stack_segment]` attribute. More
110+
details on the lint mode are given in a later section.
111+
112+
You may be wondering why we include a `#[inline(never)]` directive.
113+
This directive informs the compiler never to inline this function.
114+
While not strictly necessary, it is usually a good idea to use an
115+
`#[inline(never)]` directive in concert with `#[fixed_stack_segment]`.
116+
The reason is that if a fn annotated with `fixed_stack_segment` is
117+
inlined, then its caller also inherits the `fixed_stack_segment`
118+
annotation. This means that rather than requesting a large stack
119+
segment only for the duration of the call into C, the large stack
120+
segment would be used for the entire duration of the caller. This is
121+
not necessarily *bad* -- it can for example be more efficient,
122+
particularly if `validate_compressed_buffer()` is called multiple
123+
times in a row -- but it does work against the purpose of the
124+
segmented stack scheme, which is to keep stacks small and thus
125+
conserve address space.
126+
89127
The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be
90128
allocated to hold the output too.
91129

@@ -96,6 +134,8 @@ the true length after compression for setting the length.
96134

97135
~~~~ {.xfail-test}
98136
pub fn compress(src: &[u8]) -> ~[u8] {
137+
#[fixed_stack_segment]; #[inline(never)];
138+
99139
unsafe {
100140
let srclen = src.len() as size_t;
101141
let psrc = vec::raw::to_ptr(src);
@@ -116,6 +156,8 @@ format and `snappy_uncompressed_length` will retrieve the exact buffer size requ
116156

117157
~~~~ {.xfail-test}
118158
pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
159+
#[fixed_stack_segment]; #[inline(never)];
160+
119161
unsafe {
120162
let srclen = src.len() as size_t;
121163
let psrc = vec::raw::to_ptr(src);
@@ -139,28 +181,98 @@ pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
139181
For reference, the examples used here are also available as an [library on
140182
GitHub](https://github.com/thestinger/rust-snappy).
141183

142-
# Stack management
143-
144-
Rust tasks by default run on a "large stack". This is actually implemented as a
145-
reserving a large segment of the address space and then lazily mapping in pages
146-
as they are needed. When calling an external C function, the code is invoked on
147-
the same stack as the rust stack. This means that there is no extra
148-
stack-switching mechanism in place because it is assumed that the large stack
149-
for the rust task is plenty for the C function to have.
150-
151-
A planned future improvement (net yet implemented at the time of this writing)
152-
is to have a guard page at the end of every rust stack. No rust function will
153-
hit this guard page (due to rust's usage of LLVM's __morestack). The intention
154-
for this unmapped page is to prevent infinite recursion in C from overflowing
155-
onto other rust stacks. If the guard page is hit, then the process will be
156-
terminated with a message saying that the guard page was hit.
157-
158-
For normal external function usage, this all means that there shouldn't be any
159-
need for any extra effort on a user's perspective. The C stack naturally
160-
interleaves with the rust stack, and it's "large enough" for both to
161-
interoperate. If, however, it is determined that a larger stack is necessary,
162-
there are appropriate functions in the task spawning API to control the size of
163-
the stack of the task which is spawned.
184+
# Automatic wrappers
185+
186+
Sometimes writing Rust wrappers can be quite tedious. For example, if
187+
function does not take any pointer arguments, often there is no need
188+
for translating types. In such cases, it is usually still a good idea
189+
to have a Rust wrapper so as to manage the segmented stacks, but you
190+
can take advantage of the (standard) `externfn!` macro to remove some
191+
of the tedium.
192+
193+
In the initial section, we showed an extern block that added a call
194+
to a specific snappy API:
195+
196+
~~~~ {.xfail-test}
197+
use std::libc::size_t;
198+
199+
#[link_args = "-lsnappy"]
200+
extern {
201+
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
202+
}
203+
204+
#[fixed_stack_segment]
205+
fn main() {
206+
let x = unsafe { snappy_max_compressed_length(100) };
207+
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
208+
}
209+
~~~~
210+
211+
To avoid the need to create a wrapper fn for `snappy_max_compressed_length()`,
212+
and also to avoid the need to think about `#[fixed_stack_segment]`, we
213+
could simply use the `externfn!` macro instead, as shown here:
214+
215+
~~~~ {.xfail-test}
216+
use std::libc::size_t;
217+
218+
externfn!(#[link_args = "-lsnappy"]
219+
fn snappy_max_compressed_length(source_length: size_t) -> size_t)
220+
221+
fn main() {
222+
let x = unsafe { snappy_max_compressed_length(100) };
223+
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
224+
}
225+
~~~~
226+
227+
As you can see from the example, `externfn!` replaces the extern block
228+
entirely. After macro expansion, it will create something like this:
229+
230+
~~~~ {.xfail-test}
231+
use std::libc::size_t;
232+
233+
// Automatically generated by
234+
// externfn!(#[link_args = "-lsnappy"]
235+
// fn snappy_max_compressed_length(source_length: size_t) -> size_t)
236+
unsafe fn snappy_max_compressed_length(source_length: size_t) -> size_t {
237+
#[fixed_stack_segment]; #[inline(never)];
238+
return snappy_max_compressed_length(source_length);
239+
240+
#[link_args = "-lsnappy"]
241+
extern {
242+
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
243+
}
244+
}
245+
246+
fn main() {
247+
let x = unsafe { snappy_max_compressed_length(100) };
248+
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
249+
}
250+
~~~~
251+
252+
# Segmented stacks and the linter
253+
254+
By default, whenever you invoke a non-Rust fn, the `cstack` lint will
255+
check that one of the following conditions holds:
256+
257+
1. The call occurs inside of a fn that has been annotated with
258+
`#[fixed_stack_segment]`;
259+
2. The call occurs inside of an `extern fn`;
260+
3. The call occurs within a stack closure created by some other
261+
safe fn.
262+
263+
All of these conditions ensure that you are running on a large stack
264+
segment. However, they are sometimes too strict. If your application
265+
will be making many calls into C, it is often beneficial to promote
266+
the `#[fixed_stack_segment]` attribute higher up the call chain. For
267+
example, the Rust compiler actually labels main itself as requiring a
268+
`#[fixed_stack_segment]`. In such cases, the linter is just an
269+
annoyance, because all C calls that occur from within the Rust
270+
compiler are made on a large stack. Another situation where this
271+
frequently occurs is on a 64-bit architecture, where large stacks are
272+
the default. In cases, you can disable the linter by including a
273+
`#[allow(cstack)]` directive somewhere, which permits violations of
274+
the "cstack" rules given above (you can also use `#[warn(cstack)]` to
275+
convert the errors into warnings, if you prefer).
164276

165277
# Destructors
166278

@@ -184,6 +296,9 @@ pub struct Unique<T> {
184296
185297
impl<T: Send> Unique<T> {
186298
pub fn new(value: T) -> Unique<T> {
299+
#[fixed_stack_segment];
300+
#[inline(never)];
301+
187302
unsafe {
188303
let ptr = malloc(std::mem::size_of::<T>() as size_t) as *mut T;
189304
assert!(!ptr::is_null(ptr));
@@ -207,6 +322,9 @@ impl<T: Send> Unique<T> {
207322
#[unsafe_destructor]
208323
impl<T: Send> Drop for Unique<T> {
209324
fn drop(&mut self) {
325+
#[fixed_stack_segment];
326+
#[inline(never)];
327+
210328
unsafe {
211329
let x = intrinsics::init(); // dummy value to swap in
212330
// moving the object out is needed to call the destructor
@@ -266,8 +384,8 @@ extern {
266384
}
267385
268386
fn main() {
269-
println!("You have readline version {} installed.",
270-
rl_readline_version as int);
387+
println(fmt!("You have readline version %d installed.",
388+
rl_readline_version as int));
271389
}
272390
~~~
273391

branches/auto/mk/clean.mk

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ clean-misc:
5353
$(Q)rm -Rf tmp/*
5454
$(Q)rm -Rf rust-stage0-*.tar.bz2 $(PKG_NAME)-*.tar.gz dist
5555
$(Q)rm -Rf $(foreach ext, \
56-
html aux cp fn ky log pdf pg toc tp vr cps epub, \
56+
html aux cp fn ky log pdf pg toc tp vr cps, \
5757
$(wildcard doc/*.$(ext)))
5858
$(Q)find doc/std doc/extra -mindepth 1 | xargs rm -Rf
5959
$(Q)rm -Rf doc/version.md

branches/auto/mk/docs.mk

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,6 @@ doc/rust.tex: rust.md doc/version.md
6464
--from=markdown --to=latex \
6565
--output=$@
6666

67-
DOCS += doc/rust.epub
68-
doc/rust.epub: rust.md doc/version_info.html doc/rust.css doc/manual.inc
69-
@$(call E, pandoc: $@)
70-
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
71-
"$(CFG_PANDOC)" \
72-
--standalone --toc \
73-
--section-divs \
74-
--number-sections \
75-
--from=markdown --to=epub \
76-
--css=rust.css --include-in-header=doc/manual.inc \
77-
--include-before-body=doc/version_info.html \
78-
--output=$@
79-
80-
8167
DOCS += doc/tutorial.tex
8268
doc/tutorial.tex: tutorial.md doc/version.md
8369
@$(call E, pandoc: $@)
@@ -112,17 +98,6 @@ doc/tutorial.html: tutorial.md doc/version_info.html doc/rust.css
11298
--include-before-body=doc/version_info.html \
11399
--output=$@
114100

115-
DOCS += doc/tutorial.epub
116-
doc/tutorial.epub: tutorial.md doc/version_info.html doc/rust.css
117-
@$(call E, pandoc: $@)
118-
$(Q)$(CFG_NODE) $(S)doc/prep.js --highlight $< | \
119-
$(CFG_PANDOC) --standalone --toc \
120-
--section-divs --number-sections \
121-
--from=markdown --to=epub --css=rust.css \
122-
--include-before-body=doc/version_info.html \
123-
--output=$@
124-
125-
126101
DOCS_L10N += doc/l10n/ja/tutorial.html
127102
doc/l10n/ja/tutorial.html: doc/l10n/ja/tutorial.md doc/version_info.html doc/rust.css
128103
@$(call E, pandoc: $@)

branches/auto/mk/rt.mk

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ LIBUV_MAKEFILE_$(1) := $$(CFG_BUILD_DIR)$$(RT_OUTPUT_DIR_$(1))/libuv/Makefile
207207

208208
$$(LIBUV_MAKEFILE_$(1)): $$(LIBUV_DEPS)
209209
(cd $(S)src/libuv/ && \
210-
$$(CFG_PYTHON) ./gyp_uv.py -f make -Dtarget_arch=$$(LIBUV_ARCH_$(1)) \
210+
$$(CFG_PYTHON) ./gyp_uv -f make -Dtarget_arch=$$(LIBUV_ARCH_$(1)) \
211211
-D ninja \
212212
-DOS=$$(LIBUV_OSTYPE_$(1)) \
213213
-Goutput_dir=$$(@D) --generator-output $$(@D))
@@ -218,7 +218,7 @@ $$(LIBUV_MAKEFILE_$(1)): $$(LIBUV_DEPS)
218218
ifdef CFG_WINDOWSY_$(1)
219219
$$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS)
220220
$$(Q)$$(MAKE) -C $$(S)src/libuv -f Makefile.mingw \
221-
CC="$$(CC) $$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
221+
CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \
222222
AR="$$(AR_$(1))" \
223223
V=$$(VERBOSE)
224224
$$(Q)cp $$(S)src/libuv/libuv.a $$@

branches/auto/src/libextra/c_vec.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ mod tests {
162162
}
163163

164164
impl Runnable for LibcFree {
165+
#[fixed_stack_segment]
165166
fn run(~self) {
166167
unsafe {
167168
libc::free(self.mem)
@@ -170,6 +171,9 @@ mod tests {
170171
}
171172

172173
fn malloc(n: size_t) -> CVec<u8> {
174+
#[fixed_stack_segment];
175+
#[inline(never)];
176+
173177
unsafe {
174178
let mem = libc::malloc(n);
175179

branches/auto/src/libextra/flate.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ static TINFL_FLAG_PARSE_ZLIB_HEADER : c_int = 0x1; // parse zlib header and adle
4747
static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum
4848

4949
fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
50+
#[fixed_stack_segment]; #[inline(never)];
51+
5052
do bytes.as_imm_buf |b, len| {
5153
unsafe {
5254
let mut outsz : size_t = 0;
@@ -73,6 +75,8 @@ pub fn deflate_bytes_zlib(bytes: &[u8]) -> ~[u8] {
7375
}
7476

7577
fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
78+
#[fixed_stack_segment]; #[inline(never)];
79+
7680
do bytes.as_imm_buf |b, len| {
7781
unsafe {
7882
let mut outsz : size_t = 0;

branches/auto/src/libextra/getopts.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,7 @@ pub struct Matches {
142142
}
143143

144144
/// The type returned when the command line does not conform to the
145-
/// expected format. Call the `to_err_msg` method to retrieve the
146-
/// error as a string.
145+
/// expected format. Pass this value to <fail_str> to get an error message.
147146
#[deriving(Clone, Eq, ToStr)]
148147
#[allow(missing_doc)]
149148
pub enum Fail_ {

branches/auto/src/libextra/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ Rust extras are part of the standard Rust distribution.
3838

3939
#[deny(non_camel_case_types)];
4040
#[deny(missing_doc)];
41-
#[allow(unrecognized_lint)]; // NOTE: remove after the next snapshot
42-
#[allow(cstack)]; // NOTE: remove after the next snapshot.
4341

4442
use std::str::{StrSlice, OwnedStr};
4543

branches/auto/src/libextra/test.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ fn optgroups() -> ~[getopts::groups::OptGroup] {
220220
}
221221

222222
fn usage(binary: &str, helpstr: &str) {
223+
#[fixed_stack_segment]; #[inline(never)];
224+
223225
let message = format!("Usage: {} [OPTIONS] [FILTER]", binary);
224226
println(groups::usage(message, optgroups()));
225227
println("");

0 commit comments

Comments
 (0)