@@ -19,7 +19,6 @@ extern {
19
19
fn snappy_max_compressed_length(source_length: size_t) -> size_t;
20
20
}
21
21
22
- #[fixed_stack_segment]
23
22
fn main() {
24
23
let x = unsafe { snappy_max_compressed_length(100) };
25
24
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
@@ -36,11 +35,6 @@ interfaces that aren't thread-safe, and almost any function that takes a pointer
36
35
valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of
37
36
Rust's safe memory model.
38
37
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
-
44
38
When declaring the argument types to a foreign function, the Rust compiler will not check if the
45
39
declaration is correct, so specifying it correctly is part of keeping the binding correct at
46
40
runtime.
@@ -81,8 +75,6 @@ length is number of elements currently contained, and the capacity is the total
81
75
the allocated memory. The length is less than or equal to the capacity.
82
76
83
77
~~~~ {.xfail-test}
84
- #[fixed_stack_segment]
85
- #[inline(never)]
86
78
pub fn validate_compressed_buffer(src: &[u8]) -> bool {
87
79
unsafe {
88
80
snappy_validate_compressed_buffer(vec::raw::to_ptr(src), src.len() as size_t) == 0
@@ -94,36 +86,6 @@ The `validate_compressed_buffer` wrapper above makes use of an `unsafe` block, b
94
86
guarantee that calling it is safe for all inputs by leaving off ` unsafe ` from the function
95
87
signature.
96
88
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
-
127
89
The ` snappy_compress ` and ` snappy_uncompress ` functions are more complex, since a buffer has to be
128
90
allocated to hold the output too.
129
91
@@ -134,8 +96,6 @@ the true length after compression for setting the length.
134
96
135
97
~~~~ {.xfail-test}
136
98
pub fn compress(src: &[u8]) -> ~[u8] {
137
- #[fixed_stack_segment]; #[inline(never)];
138
-
139
99
unsafe {
140
100
let srclen = src.len() as size_t;
141
101
let psrc = vec::raw::to_ptr(src);
@@ -156,8 +116,6 @@ format and `snappy_uncompressed_length` will retrieve the exact buffer size requ
156
116
157
117
~~~~ {.xfail-test}
158
118
pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
159
- #[fixed_stack_segment]; #[inline(never)];
160
-
161
119
unsafe {
162
120
let srclen = src.len() as size_t;
163
121
let psrc = vec::raw::to_ptr(src);
@@ -181,99 +139,6 @@ pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
181
139
For reference, the examples used here are also available as an [ library on
182
140
GitHub] ( https://github.com/thestinger/rust-snappy ) .
183
141
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
- segmented. 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).
276
-
277
142
# Destructors
278
143
279
144
Foreign libraries often hand off ownership of resources to the calling code,
@@ -296,9 +161,6 @@ pub struct Unique<T> {
296
161
297
162
impl<T: Send> Unique<T> {
298
163
pub fn new(value: T) -> Unique<T> {
299
- #[fixed_stack_segment];
300
- #[inline(never)];
301
-
302
164
unsafe {
303
165
let ptr = malloc(std::sys::size_of::<T>() as size_t) as *mut T;
304
166
assert!(!ptr::is_null(ptr));
@@ -322,9 +184,6 @@ impl<T: Send> Unique<T> {
322
184
#[unsafe_destructor]
323
185
impl<T: Send> Drop for Unique<T> {
324
186
fn drop(&self) {
325
- #[fixed_stack_segment];
326
- #[inline(never)];
327
-
328
187
unsafe {
329
188
let x = intrinsics::init(); // dummy value to swap in
330
189
// moving the object out is needed to call the destructor
0 commit comments