fn snappy_max_compressed_length(source_length: size_t) -> size_t;
}
+#[fixed_stack_segment]
fn main() {
let x = unsafe { snappy_max_compressed_length(100) };
println(fmt!("max compressed length of a 100 byte buffer: %?", x));
valid for all possible inputs since the pointer could be dangling, and raw pointers fall outside of
Rust's safe memory model.
+Finally, the `#[fixed_stack_segment]` annotation that appears on
+`main()` instructs the Rust compiler that when `main()` executes, it
+should request a "very large" stack segment. More details on
+stack management can be found in the following sections.
+
When declaring the argument types to a foreign function, the Rust compiler will not check if the
declaration is correct, so specifying it correctly is part of keeping the binding correct at
runtime.
the allocated memory. The length is less than or equal to the capacity.
~~~~ {.xfail-test}
+#[fixed_stack_segment]
+#[inline(never)]
pub fn validate_compressed_buffer(src: &[u8]) -> bool {
unsafe {
snappy_validate_compressed_buffer(vec::raw::to_ptr(src), src.len() as size_t) == 0
guarantee that calling it is safe for all inputs by leaving off `unsafe` from the function
signature.
+The `validate_compressed_buffer` wrapper is also annotated with two
+attributes `#[fixed_stack_segment]` and `#[inline(never)]`. The
+purpose of these attributes is to guarantee that there will be
+sufficient stack for the C function to execute. This is necessary
+because Rust, unlike C, does not assume that the stack is allocated in
+one continuous chunk. Instead, we rely on a *segmented stack* scheme,
+in which the stack grows and shrinks as necessary. C code, however,
+expects one large stack, and so callers of C functions must request a
+large stack segment to ensure that the C routine will not run off the
+end of the stack.
+
+The compiler includes a lint mode that will report an error if you
+call a C function without a `#[fixed_stack_segment]` attribute. More
+details on the lint mode are given in a later section.
+
+You may be wondering why we include a `#[inline(never)]` directive.
+This directive informs the compiler never to inline this function.
+While not strictly necessary, it is usually a good idea to use an
+`#[inline(never)]` directive in concert with `#[fixed_stack_segment]`.
+The reason is that if a fn annotated with `fixed_stack_segment` is
+inlined, then its caller also inherits the `fixed_stack_segment`
+annotation. This means that rather than requesting a large stack
+segment only for the duration of the call into C, the large stack
+segment would be used for the entire duration of the caller. This is
+not necessarily *bad* -- it can for example be more efficient,
+particularly if `validate_compressed_buffer()` is called multiple
+times in a row -- but it does work against the purpose of the
+segmented stack scheme, which is to keep stacks small and thus
+conserve address space.
+
The `snappy_compress` and `snappy_uncompress` functions are more complex, since a buffer has to be
allocated to hold the output too.
~~~~ {.xfail-test}
pub fn compress(src: &[u8]) -> ~[u8] {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let srclen = src.len() as size_t;
let psrc = vec::raw::to_ptr(src);
~~~~ {.xfail-test}
pub fn uncompress(src: &[u8]) -> Option<~[u8]> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let srclen = src.len() as size_t;
let psrc = vec::raw::to_ptr(src);
For reference, the examples used here are also available as an [library on
GitHub](https://github.com/thestinger/rust-snappy).
+# Automatic wrappers
+
+Sometimes writing Rust wrappers can be quite tedious. For example, if
+function does not take any pointer arguments, often there is no need
+for translating types. In such cases, it is usually still a good idea
+to have a Rust wrapper so as to manage the segmented stacks, but you
+can take advantage of the (standard) `externfn!` macro to remove some
+of the tedium.
+
+In the initial section, we showed an extern block that added a call
+to a specific snappy API:
+
+~~~~ {.xfail-test}
+use std::libc::size_t;
+
+#[link_args = "-lsnappy"]
+extern {
+ fn snappy_max_compressed_length(source_length: size_t) -> size_t;
+}
+
+#[fixed_stack_segment]
+fn main() {
+ let x = unsafe { snappy_max_compressed_length(100) };
+ println(fmt!("max compressed length of a 100 byte buffer: %?", x));
+}
+~~~~
+
+To avoid the need to create a wrapper fn for `snappy_max_compressed_length()`,
+and also to avoid the need to think about `#[fixed_stack_segment]`, we
+could simply use the `externfn!` macro instead, as shown here:
+
+~~~~ {.xfail-test}
+use std::libc::size_t;
+
+externfn!(#[link_args = "-lsnappy"]
+ fn snappy_max_compressed_length(source_length: size_t) -> size_t)
+
+fn main() {
+ let x = unsafe { snappy_max_compressed_length(100) };
+ println(fmt!("max compressed length of a 100 byte buffer: %?", x));
+}
+~~~~
+
+As you can see from the example, `externfn!` replaces the extern block
+entirely. After macro expansion, it will create something like this:
+
+~~~~ {.xfail-test}
+use std::libc::size_t;
+
+// Automatically generated by
+// externfn!(#[link_args = "-lsnappy"]
+// fn snappy_max_compressed_length(source_length: size_t) -> size_t)
+unsafe fn snappy_max_compressed_length(source_length: size_t) -> size_t {
+ #[fixed_stack_segment]; #[inline(never)];
+ return snappy_max_compressed_length(source_length);
+
+ #[link_args = "-lsnappy"]
+ extern {
+ fn snappy_max_compressed_length(source_length: size_t) -> size_t;
+ }
+}
+
+fn main() {
+ let x = unsafe { snappy_max_compressed_length(100) };
+ println(fmt!("max compressed length of a 100 byte buffer: %?", x));
+}
+~~~~
+
+# Segmented stacks and the linter
+
+By default, whenever you invoke a non-Rust fn, the `cstack` lint will
+check that one of the following conditions holds:
+
+1. The call occurs inside of a fn that has been annotated with
+ `#[fixed_stack_segment]`;
+2. The call occurs inside of an `extern fn`;
+3. The call occurs within a stack closure created by some other
+ safe fn.
+
+All of these conditions ensure that you are running on a large stack
+segmented. However, they are sometimes too strict. If your application
+will be making many calls into C, it is often beneficial to promote
+the `#[fixed_stack_segment]` attribute higher up the call chain. For
+example, the Rust compiler actually labels main itself as requiring a
+`#[fixed_stack_segment]`. In such cases, the linter is just an
+annoyance, because all C calls that occur from within the Rust
+compiler are made on a large stack. Another situation where this
+frequently occurs is on a 64-bit architecture, where large stacks are
+the default. In cases, you can disable the linter by including a
+`#[allow(cstack)]` directive somewhere, which permits violations of
+the "cstack" rules given above (you can also use `#[warn(cstack)]` to
+convert the errors into warnings, if you prefer).
+
# Destructors
Foreign libraries often hand off ownership of resources to the calling code,
impl<T: Send> Unique<T> {
pub fn new(value: T) -> Unique<T> {
+ #[fixed_stack_segment];
+ #[inline(never)];
+
unsafe {
let ptr = malloc(std::sys::size_of::<T>() as size_t) as *mut T;
assert!(!ptr::is_null(ptr));
#[unsafe_destructor]
impl<T: Send> Drop for Unique<T> {
fn drop(&self) {
+ #[fixed_stack_segment];
+ #[inline(never)];
+
unsafe {
let x = intrinsics::init(); // dummy value to swap in
// moving the object out is needed to call the destructor
use std::libc;
fn malloc(n: size_t) -> CVec<u8> {
+ #[fixed_stack_segment];
+ #[inline(never)];
+
unsafe {
let mem = libc::malloc(n);
assert!(mem as int != 0);
- c_vec_with_dtor(mem as *mut u8, n as uint, || free(mem))
+ return c_vec_with_dtor(mem as *mut u8, n as uint, || f(mem));
+ }
+
+ fn f(mem: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { libc::free(mem) }
}
}
static TDEFL_WRITE_ZLIB_HEADER : c_int = 0x01000; // write zlib header and adler32 checksum
fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
+ #[fixed_stack_segment]; #[inline(never)];
+
do bytes.as_imm_buf |b, len| {
unsafe {
let mut outsz : size_t = 0;
}
fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
+ #[fixed_stack_segment]; #[inline(never)];
+
do bytes.as_imm_buf |b, len| {
unsafe {
let mut outsz : size_t = 0;
pub mod rustrt {
use std::libc::{c_char, c_int};
- extern {
- pub fn linenoise(prompt: *c_char) -> *c_char;
- pub fn linenoiseHistoryAdd(line: *c_char) -> c_int;
- pub fn linenoiseHistorySetMaxLen(len: c_int) -> c_int;
- pub fn linenoiseHistorySave(file: *c_char) -> c_int;
- pub fn linenoiseHistoryLoad(file: *c_char) -> c_int;
- pub fn linenoiseSetCompletionCallback(callback: *u8);
- pub fn linenoiseAddCompletion(completions: *(), line: *c_char);
+ #[cfg(stage0)]
+ mod macro_hack {
+ #[macro_escape];
+ macro_rules! externfn(
+ (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ )
+ )
}
+
+ externfn!(fn linenoise(prompt: *c_char) -> *c_char)
+ externfn!(fn linenoiseHistoryAdd(line: *c_char) -> c_int)
+ externfn!(fn linenoiseHistorySetMaxLen(len: c_int) -> c_int)
+ externfn!(fn linenoiseHistorySave(file: *c_char) -> c_int)
+ externfn!(fn linenoiseHistoryLoad(file: *c_char) -> c_int)
+ externfn!(fn linenoiseSetCompletionCallback(callback: *u8))
+ externfn!(fn linenoiseAddCompletion(completions: *(), line: *c_char))
}
/// Add a line to history
rustrt::linenoiseAddCompletion(completions, buf);
}
}
-}
+ }
}
}
}
fn usage(binary: &str, helpstr: &str) -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+
let message = fmt!("Usage: %s [OPTIONS] [FILTER]", binary);
println(groups::usage(message, optgroups()));
println("");
* nanoseconds since 1970-01-01T00:00:00Z.
*/
pub fn get_time() -> Timespec {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut sec = 0i64;
let mut nsec = 0i32;
* in nanoseconds since an unspecified epoch.
*/
pub fn precise_time_ns() -> u64 {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut ns = 0u64;
rustrt::precise_time_ns(&mut ns);
}
pub fn tzset() {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
rustrt::rust_tzset();
}
/// Returns the specified time in UTC
pub fn at_utc(clock: Timespec) -> Tm {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let Timespec { sec, nsec } = clock;
let mut tm = empty_tm();
/// Returns the specified time in the local timezone
pub fn at(clock: Timespec) -> Tm {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let Timespec { sec, nsec } = clock;
let mut tm = empty_tm();
impl Tm {
/// Convert time to the seconds from January 1, 1970
pub fn to_timespec(&self) -> Timespec {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let sec = match self.tm_gmtoff {
0_i32 => rustrt::rust_timegm(self),
}
pub fn main() {
+ #[fixed_stack_segment]; #[inline(never)];
+
let os_args = os::args();
if (os_args.len() > 1 && (os_args[1] == ~"-v" || os_args[1] == ~"--version")) {
}
debugging_opts |= this_bit;
}
+
if debugging_opts & session::debug_llvm != 0 {
- unsafe {
- llvm::LLVMSetDebug(1);
+ set_llvm_debug();
+
+ fn set_llvm_debug() {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { llvm::LLVMSetDebug(1); }
}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// LLVM wrappers are intended to be called from trans,
+// which already runs in a #[fixed_stack_segment]
+#[allow(cstack)];
+
use std::c_str::ToCStr;
use std::hashmap::HashMap;
use std::libc::{c_uint, c_ushort};
use middle::lint;
use middle::ty;
use syntax::ast;
+use syntax::ast_map;
use syntax::attr;
use syntax::codemap::span;
use visit = syntax::oldvisit;
fn stack_check_item(item: @ast::item,
(in_cx, v): (Context, visit::vt<Context>)) {
- let safe_stack = match item.node {
+ match item.node {
+ ast::item_fn(_, ast::extern_fn, _, _, _) => {
+ // an extern fn is already being called from C code...
+ let new_cx = Context {safe_stack: true, ..in_cx};
+ visit::visit_item(item, (new_cx, v));
+ }
ast::item_fn(*) => {
- attr::contains_name(item.attrs, "fixed_stack_segment")
+ let safe_stack = fixed_stack_segment(item.attrs);
+ let new_cx = Context {safe_stack: safe_stack, ..in_cx};
+ visit::visit_item(item, (new_cx, v));
+ }
+ ast::item_impl(_, _, _, ref methods) => {
+ // visit_method() would make this nicer
+ for &method in methods.iter() {
+ let safe_stack = fixed_stack_segment(method.attrs);
+ let new_cx = Context {safe_stack: safe_stack, ..in_cx};
+ visit::visit_method_helper(method, (new_cx, v));
+ }
}
_ => {
- false
+ visit::visit_item(item, (in_cx, v));
}
- };
- let new_cx = Context {
- tcx: in_cx.tcx,
- safe_stack: safe_stack
- };
- visit::visit_item(item, (new_cx, v));
+ }
+
+ fn fixed_stack_segment(attrs: &[ast::Attribute]) -> bool {
+ attr::contains_name(attrs, "fixed_stack_segment")
+ }
}
fn stack_check_fn<'a>(fk: &visit::fn_kind,
id: ast::NodeId,
(in_cx, v): (Context, visit::vt<Context>)) {
let safe_stack = match *fk {
- visit::fk_item_fn(*) => in_cx.safe_stack, // see stack_check_item above
- visit::fk_anon(*) | visit::fk_fn_block | visit::fk_method(*) => false,
- };
- let new_cx = Context {
- tcx: in_cx.tcx,
- safe_stack: safe_stack
+ visit::fk_method(*) | visit::fk_item_fn(*) => {
+ in_cx.safe_stack // see stack_check_item above
+ }
+ visit::fk_anon(*) | visit::fk_fn_block => {
+ match ty::get(ty::node_id_to_type(in_cx.tcx, id)).sty {
+ ty::ty_bare_fn(*) |
+ ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) |
+ ty::ty_closure(ty::ClosureTy {sigil: ast::ManagedSigil, _}) => {
+ false
+ }
+ _ => {
+ in_cx.safe_stack
+ }
+ }
+ }
};
+ let new_cx = Context {safe_stack: safe_stack, ..in_cx};
debug!("stack_check_fn(safe_stack=%b, id=%?)", safe_stack, id);
visit::visit_fn(fk, decl, body, sp, id, (new_cx, v));
}
match ty::get(callee_ty).sty {
ty::ty_bare_fn(ref fty) => {
if !fty.abis.is_rust() && !fty.abis.is_intrinsic() {
- cx.tcx.sess.add_lint(
- lint::cstack,
- callee.id,
- callee.span,
- fmt!("invoking non-Rust fn in fn without \
- #[fixed_stack_segment]"));
+ call_to_extern_fn(cx, callee);
}
}
_ => {}
}
visit::visit_expr(expr, (cx, v));
}
+
+fn call_to_extern_fn(cx: Context, callee: @ast::expr) {
+ // Permit direct calls to extern fns that are annotated with
+ // #[rust_stack]. This is naturally a horrible pain to achieve.
+ match callee.node {
+ ast::expr_path(*) => {
+ match cx.tcx.def_map.find(&callee.id) {
+ Some(&ast::def_fn(id, _)) if id.crate == ast::LOCAL_CRATE => {
+ match cx.tcx.items.find(&id.node) {
+ Some(&ast_map::node_foreign_item(item, _, _, _)) => {
+ if attr::contains_name(item.attrs, "rust_stack") {
+ return;
+ }
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+ }
+ _ => {}
+ }
+
+ cx.tcx.sess.add_lint(lint::cstack,
+ callee.id,
+ callee.span,
+ fmt!("invoking non-Rust fn in fn without \
+ #[fixed_stack_segment]"));
+}
register_method(ccx, id, pth, m)
}
- ast_map::node_foreign_item(ni, _, _, pth) => {
+ ast_map::node_foreign_item(ni, abis, _, pth) => {
let ty = ty::node_id_to_type(ccx.tcx, ni.id);
exprt = true;
match ni.node {
ast::foreign_item_fn(*) => {
let path = vec::append((*pth).clone(), [path_name(ni.ident)]);
- foreign::register_foreign_item_fn(ccx, abis, &path, ni);
+ foreign::register_foreign_item_fn(ccx, abis, &path, ni)
}
ast::foreign_item_static(*) => {
let ident = token::ident_to_str(&ni.ident);
#[license = "MIT/ASL2"];
#[crate_type = "lib"];
+// Rustc tasks always run on a fixed_stack_segment, so code in this
+// module can call C functions (in particular, LLVM functions) with
+// impunity.
+#[allow(cstack)];
+
extern mod extra;
extern mod syntax;
}
pub fn main() {
+ #[fixed_stack_segment]; #[inline(never)];
+
let args = os::args();
let input = io::stdin();
let out = io::stdout();
#[cfg(windows)]
pub fn link_exe(_src: &Path, _dest: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
/* FIXME (#1768): Investigate how to do this on win32
Node wraps symlinks by having a .bat,
but that won't work with minGW. */
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
pub fn link_exe(src: &Path, dest: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
use std::c_str::ToCStr;
use std::libc;
///
/// Fails if the CString is null.
pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
+ #[fixed_stack_segment]; #[inline(never)];
if self.buf.is_null() { fail!("CString is null!"); }
unsafe {
let len = libc::strlen(self.buf) as uint;
impl Drop for CString {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
if self.owns_buffer_ {
unsafe {
libc::free(self.buf as *libc::c_void)
impl<'self> ToCStr for &'self [u8] {
fn to_c_str(&self) -> CString {
+ #[fixed_stack_segment]; #[inline(never)];
let mut cs = unsafe { self.to_c_str_unchecked() };
do cs.with_mut_ref |buf| {
for i in range(0, self.len()) {
}
unsafe fn to_c_str_unchecked(&self) -> CString {
+ #[fixed_stack_segment]; #[inline(never)];
do self.as_imm_buf |self_buf, self_len| {
let buf = libc::malloc(self_len as libc::size_t + 1) as *mut u8;
if buf.is_null() {
#[test]
fn test_unwrap() {
+ #[fixed_stack_segment]; #[inline(never)];
+
let c_str = "hello".to_c_str();
unsafe { libc::free(c_str.unwrap() as *libc::c_void) }
}
#[test]
fn test_with_ref() {
+ #[fixed_stack_segment]; #[inline(never)];
+
let c_str = "hello".to_c_str();
let len = unsafe { c_str.with_ref(|buf| libc::strlen(buf)) };
assert!(!c_str.is_null());
impl Reader for *libc::FILE {
fn read(&self, bytes: &mut [u8], len: uint) -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do bytes.as_mut_buf |buf_p, buf_len| {
assert!(buf_len >= len);
}
}
fn read_byte(&self) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::fgetc(*self) as int
}
}
fn eof(&self) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
return libc::feof(*self) != 0 as c_int;
}
}
fn seek(&self, offset: int, whence: SeekStyle) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
assert!(libc::fseek(*self,
offset as c_long,
}
}
fn tell(&self) -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
return libc::ftell(*self) as uint;
}
impl Drop for FILERes {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::fclose(self.f);
}
* ~~~
*/
pub fn stdin() -> @Reader {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
@rustrt::rust_get_stdin() as @Reader
}
}
pub fn file_reader(path: &Path) -> Result<@Reader, ~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
let f = do path.with_c_str |pathbuf| {
do "rb".with_c_str |modebuf| {
unsafe { libc::fopen(pathbuf, modebuf as *libc::c_char) }
impl Writer for *libc::FILE {
fn write(&self, v: &[u8]) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do v.as_imm_buf |vbuf, len| {
let nout = libc::fwrite(vbuf as *c_void,
}
}
fn seek(&self, offset: int, whence: SeekStyle) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
assert!(libc::fseek(*self,
offset as c_long,
}
}
fn tell(&self) -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::ftell(*self) as uint
}
}
fn flush(&self) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::fflush(*self) as int
}
}
fn get_type(&self) -> WriterType {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let fd = libc::fileno(*self);
if libc::isatty(fd) == 0 { File }
impl Writer for fd_t {
fn write(&self, v: &[u8]) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut count = 0u;
do v.as_imm_buf |vbuf, len| {
}
fn flush(&self) -> int { 0 }
fn get_type(&self) -> WriterType {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
if libc::isatty(*self) == 0 { File } else { Screen }
}
impl Drop for FdRes {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::close(self.fd);
}
pub fn mk_file_writer(path: &Path, flags: &[FileFlag])
-> Result<@Writer, ~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
#[cfg(windows)]
fn wb() -> c_int {
(O_WRONLY | libc::consts::os::extra::O_BINARY) as c_int
// FIXME: fileflags // #2004
pub fn buffered_file_writer(path: &Path) -> Result<@Writer, ~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let f = do path.with_c_str |pathbuf| {
do "w".with_c_str |modebuf| {
blk: &fn(v: Res<*libc::FILE>)) {
blk(Res::new(Arg {
val: file.f, opt_level: opt_level,
- fsync_fn: |file, l| {
- unsafe {
- os::fsync_fd(libc::fileno(*file), l) as int
- }
- }
+ fsync_fn: |file, l| fsync_fd(fileno(*file), l)
}));
+
+ fn fileno(stream: *libc::FILE) -> libc::c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { libc::fileno(stream) }
+ }
}
// fsync fd after executing blk
blk: &fn(v: Res<fd_t>)) {
blk(Res::new(Arg {
val: fd.fd, opt_level: opt_level,
- fsync_fn: |fd, l| os::fsync_fd(*fd, l) as int
+ fsync_fn: |fd, l| fsync_fd(*fd, l)
}));
}
+ fn fsync_fd(fd: libc::c_int, level: Level) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ os::fsync_fd(fd, level) as int
+ }
+
// Type of objects that may want to fsync
pub trait FSyncable { fn fsync(&self, l: Level) -> int; }
// doesn't link it correctly on i686, so we're going
// through a C function that mysteriously does work.
pub unsafe fn opendir(dirname: *c_char) -> *DIR {
+ #[fixed_stack_segment]; #[inline(never)];
rust_opendir(dirname)
}
pub unsafe fn readdir(dirp: *DIR) -> *dirent_t {
+ #[fixed_stack_segment]; #[inline(never)];
rust_readdir(dirp)
}
use unstable::intrinsics;
$(
- #[inline]
+ #[inline] #[fixed_stack_segment] #[inline(never)]
pub fn $name($( $arg : $arg_ty ),*) -> $rv {
unsafe {
$bound_name($( $arg ),*)
use unstable::intrinsics;
$(
- #[inline]
+ #[inline] #[fixed_stack_segment] #[inline(never)]
pub fn $name($( $arg : $arg_ty ),*) -> $rv {
unsafe {
$bound_name($( $arg ),*)
/// Delegates to the libc close() function, returning the same return value.
pub fn close(fd: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::close(fd)
}
static BUF_BYTES : uint = 2048u;
pub fn getcwd() -> Path {
+ #[fixed_stack_segment]; #[inline(never)];
let mut buf = [0 as libc::c_char, ..BUF_BYTES];
do buf.as_mut_buf |buf, len| {
unsafe {
pub fn fill_utf16_buf_and_decode(f: &fn(*mut u16, DWORD) -> DWORD)
-> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut n = TMPBUF_SZ as DWORD;
let mut res = None;
}
}
+#[cfg(stage0)]
+mod macro_hack {
+#[macro_escape];
+macro_rules! externfn(
+ (fn $name:ident ()) => (
+ extern {
+ fn $name();
+ }
+ )
+)
+}
+
/*
Accessing environment variables is not generally threadsafe.
Serialize access through a global lock.
};
}
- extern {
- #[fast_ffi]
- fn rust_take_env_lock();
- #[fast_ffi]
- fn rust_drop_env_lock();
- }
+ externfn!(fn rust_take_env_lock());
+ externfn!(fn rust_drop_env_lock());
}
/// Returns a vector of (variable, value) pairs for all the environment
unsafe {
#[cfg(windows)]
unsafe fn get_env_pairs() -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::funcs::extra::kernel32::{
GetEnvironmentStringsA,
FreeEnvironmentStringsA
}
#[cfg(unix)]
unsafe fn get_env_pairs() -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
+
extern {
fn rust_env_pairs() -> **libc::c_char;
}
/// Fetches the environment variable `n` from the current process, returning
/// None if the variable isn't set.
pub fn getenv(n: &str) -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
let s = do n.with_c_str |buf| {
/// Fetches the environment variable `n` from the current process, returning
/// None if the variable isn't set.
pub fn getenv(n: &str) -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do with_env_lock {
use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
/// Sets the environment variable `n` to the value `v` for the currently running
/// process
pub fn setenv(n: &str, v: &str) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
do n.with_c_str |nbuf| {
/// Sets the environment variable `n` to the value `v` for the currently running
/// process
pub fn setenv(n: &str, v: &str) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do with_env_lock {
use os::win32::as_utf16_p;
pub fn unsetenv(n: &str) {
#[cfg(unix)]
fn _unsetenv(n: &str) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
do n.with_c_str |nbuf| {
}
#[cfg(windows)]
fn _unsetenv(n: &str) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do with_env_lock {
use os::win32::as_utf16_p;
}
pub fn fdopen(fd: c_int) -> *FILE {
+ #[fixed_stack_segment]; #[inline(never)];
do "r".with_c_str |modebuf| {
unsafe {
libc::fdopen(fd, modebuf)
#[cfg(windows)]
pub fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::extra::msvcrt::*;
return commit(fd);
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::posix01::unistd::*;
match level {
#[cfg(target_os = "macos")]
pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
use libc::consts::os::extra::*;
use libc::funcs::posix88::fcntl::*;
#[cfg(target_os = "freebsd")]
pub fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
use libc::funcs::posix01::unistd::*;
return fsync(fd);
#[cfg(unix)]
pub fn pipe() -> Pipe {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
let mut fds = Pipe {input: 0 as c_int,
out: 0 as c_int };
#[cfg(windows)]
pub fn pipe() -> Pipe {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
// Windows pipes work subtly differently than unix pipes, and their
// inheritance has to be handled in a different way that I do not
}
fn dup2(src: c_int, dst: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::dup2(src, dst)
}
#[cfg(target_os = "freebsd")]
fn load_self() -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::bsd44::*;
use libc::consts::os::extra::*;
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn load_self() -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use libc::funcs::posix01::unistd::readlink;
#[cfg(target_os = "macos")]
fn load_self() -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do fill_charp_buf() |buf, sz| {
let mut sz = sz as u32;
#[cfg(windows)]
fn load_self() -> Option<~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::fill_utf16_buf_and_decode;
do fill_utf16_buf_and_decode() |buf, sz| {
/// Indicates whether a path represents a directory
pub fn path_is_dir(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do p.with_c_str |buf| {
rustrt::rust_path_is_dir(buf) != 0 as c_int
/// Indicates whether a path exists
pub fn path_exists(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do p.with_c_str |buf| {
rustrt::rust_path_exists(buf) != 0 as c_int
#[cfg(windows)]
fn mkdir(p: &Path, _mode: c_int) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
// FIXME: turn mode into something useful? #2623
#[cfg(unix)]
fn mkdir(p: &Path, mode: c_int) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
do p.with_c_str |buf| {
unsafe {
libc::mkdir(buf, mode as libc::mode_t) == (0 as c_int)
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
unsafe fn get_list(p: &Path) -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::{dirent_t};
use libc::{opendir, readdir, closedir};
extern {
}
#[cfg(windows)]
unsafe fn get_list(p: &Path) -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::consts::os::extra::INVALID_HANDLE_VALUE;
use libc::{wcslen, free};
use libc::funcs::extra::kernel32::{
#[cfg(windows)]
fn rmdir(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(p.to_str()) |buf| {
#[cfg(unix)]
fn rmdir(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
do p.with_c_str |buf| {
unsafe {
libc::rmdir(buf) == (0 as c_int)
#[cfg(windows)]
fn chdir(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(p.to_str()) |buf| {
#[cfg(unix)]
fn chdir(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
do p.with_c_str |buf| {
unsafe {
libc::chdir(buf) == (0 as c_int)
#[cfg(windows)]
fn do_copy_file(from: &Path, to: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(from.to_str()) |fromp| {
#[cfg(unix)]
fn do_copy_file(from: &Path, to: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
let istream = do from.with_c_str |fromp| {
do "rb".with_c_str |modebuf| {
#[cfg(windows)]
fn unlink(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
use os::win32::as_utf16_p;
return do as_utf16_p(p.to_str()) |buf| {
#[cfg(unix)]
fn unlink(p: &Path) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do p.with_c_str |buf| {
libc::unlink(buf) == (0 as c_int)
#[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")]
fn errno_location() -> *c_int {
+ #[fixed_stack_segment]; #[inline(never)];
#[nolink]
extern {
fn __error() -> *c_int;
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn errno_location() -> *c_int {
+ #[fixed_stack_segment]; #[inline(never)];
#[nolink]
extern {
fn __errno_location() -> *c_int;
#[cfg(windows)]
/// Returns the platform-specific value of errno
pub fn errno() -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::DWORD;
#[link_name = "kernel32"]
#[cfg(target_os = "freebsd")]
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
-> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
#[nolink]
extern {
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
// So we just use __xpg_strerror_r which is always POSIX compliant
#[cfg(target_os = "linux")]
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
#[nolink]
extern {
fn __xpg_strerror_r(errnum: c_int,
#[cfg(windows)]
fn strerror() -> ~str {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::types::os::arch::extra::DWORD;
use libc::types::os::arch::extra::LPSTR;
use libc::types::os::arch::extra::LPVOID;
*/
#[cfg(target_os = "macos")]
pub fn real_args() -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let (argc, argv) = (*_NSGetArgc() as c_int,
*_NSGetArgv() as **c_char);
#[cfg(windows)]
pub fn real_args() -> ~[~str] {
+ #[fixed_stack_segment]; #[inline(never)];
+
let mut nArgs: c_int = 0;
let lpArgCount: *mut c_int = &mut nArgs;
let lpCmdLine = unsafe { GetCommandLineW() };
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
pub fn glob(pattern: &str) -> ~[Path] {
+ #[fixed_stack_segment]; #[inline(never)];
+
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
fn default_glob_t () -> libc::glob_t {
#[cfg(unix)]
pub fn page_size() -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
libc::sysconf(libc::_SC_PAGESIZE) as uint
}
#[cfg(windows)]
pub fn page_size() -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let mut info = libc::SYSTEM_INFO::new();
libc::GetSystemInfo(&mut info);
#[cfg(unix)]
impl MemoryMap {
pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::off_t;
let mut addr: *c_void = ptr::null();
#[cfg(unix)]
impl Drop for MemoryMap {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
match libc::munmap(self.data as *c_void, self.len) {
0 => (),
#[cfg(windows)]
impl MemoryMap {
pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
let mut lpAddress: LPVOID = ptr::mut_null();
#[cfg(windows)]
impl Drop for MemoryMap {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
use libc::types::os::arch::extra::{LPCVOID, HANDLE};
unsafe {
#[test]
fn copy_file_ok() {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let tempdir = getcwd(); // would like to use $TMPDIR,
// doesn't seem to work on Linux
#[test]
fn memory_map_file() {
+ #[fixed_stack_segment]; #[inline(never)];
+
use result::{Ok, Err};
use os::*;
use libc::*;
#[cfg(unix)]
+ #[fixed_stack_segment]
+ #[inline(never)]
fn lseek_(fd: c_int, size: uint) {
unsafe {
assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
}
}
#[cfg(windows)]
+ #[fixed_stack_segment]
+ #[inline(never)]
fn lseek_(fd: c_int, size: uint) {
unsafe {
assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
#[cfg(target_os = "win32")]
impl WindowsPath {
pub fn stat(&self) -> Option<libc::stat> {
+ #[fixed_stack_segment]; #[inline(never)];
do self.with_c_str |buf| {
let mut st = stat::arch::default_stat();
match unsafe { libc::stat(buf, &mut st) } {
#[cfg(not(target_os = "win32"))]
impl PosixPath {
pub fn stat(&self) -> Option<libc::stat> {
+ #[fixed_stack_segment]; #[inline(never)];
do self.with_c_str |buf| {
let mut st = stat::arch::default_stat();
match unsafe { libc::stat(buf as *libc::c_char, &mut st) } {
#[cfg(unix)]
impl PosixPath {
pub fn lstat(&self) -> Option<libc::stat> {
+ #[fixed_stack_segment]; #[inline(never)];
do self.with_c_str |buf| {
let mut st = stat::arch::default_stat();
match unsafe { libc::lstat(buf, &mut st) } {
}
pub fn extract_drive_prefix(s: &str) -> Option<(~str,~str)> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
if (s.len() > 1 &&
libc::isalpha(s[0] as libc::c_int) != 0 &&
impl XorShiftRng {
/// Create an xor shift random number generator with a random seed.
pub fn new() -> XorShiftRng {
+ #[fixed_stack_segment]; #[inline(never)];
+
// generate seeds the same way as seed(), except we have a spceific size
let mut s = [0u8, ..16];
loop {
/// Create a new random seed.
pub fn seed() -> ~[u8] {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let n = rustrt::rand_seed_size() as uint;
let mut s = vec::from_elem(n, 0_u8);
#[test]
fn compare_isaac_implementation() {
+ #[fixed_stack_segment]; #[inline(never)];
+
// This is to verify that the implementation of the ISAAC rng is
// correct (i.e. matches the output of the upstream implementation,
// which is in the runtime)
args
}
- extern {
- fn rust_take_global_args_lock();
- fn rust_drop_global_args_lock();
- fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>;
+ #[cfg(stage0)]
+ mod macro_hack {
+ #[macro_escape];
+ macro_rules! externfn(
+ (fn $name:ident () $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name() $(-> $ret_ty),*;
+ }
+ )
+ )
}
+ externfn!(fn rust_take_global_args_lock())
+ externfn!(fn rust_drop_global_args_lock())
+ externfn!(fn rust_get_global_args_ptr() -> *mut Option<~~[~str]>)
+
#[cfg(test)]
mod tests {
use option::{Some, None};
}
unsafe fn write_cstr(&self, p: *c_char) {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::strlen;
use vec;
}
/// A wrapper around libc::malloc, aborting on out-of-memory
-#[inline]
pub unsafe fn malloc_raw(size: uint) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
let p = malloc(size as size_t);
if p.is_null() {
// we need a non-allocating way to print an error here
}
/// A wrapper around libc::realloc, aborting on out-of-memory
-#[inline]
pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
let p = realloc(ptr, size as size_t);
if p.is_null() {
// we need a non-allocating way to print an error here
exchange_free(ptr)
}
-#[inline]
pub unsafe fn exchange_free(ptr: *c_char) {
+ #[fixed_stack_segment]; #[inline(never)];
+
free(ptr as *c_void);
}
}
impl LocalHeap {
+ #[fixed_stack_segment] #[inline(never)]
pub fn new() -> LocalHeap {
unsafe {
// Don't need synchronization for the single-threaded local heap
}
}
+ #[fixed_stack_segment] #[inline(never)]
pub fn alloc(&mut self, td: *TypeDesc, size: uint) -> *OpaqueBox {
unsafe {
return rust_boxed_region_malloc(self.boxed_region, td, size as size_t);
}
}
+ #[fixed_stack_segment] #[inline(never)]
pub fn realloc(&mut self, ptr: *OpaqueBox, size: uint) -> *OpaqueBox {
unsafe {
return rust_boxed_region_realloc(self.boxed_region, ptr, size as size_t);
}
}
+ #[fixed_stack_segment] #[inline(never)]
pub fn free(&mut self, box: *OpaqueBox) {
unsafe {
return rust_boxed_region_free(self.boxed_region, box);
}
impl Drop for LocalHeap {
+ #[fixed_stack_segment] #[inline(never)]
fn drop(&self) {
unsafe {
rust_delete_boxed_region(self.boxed_region);
use tls = rt::thread_local_storage;
/// Initialize the TLS key. Other ops will fail if this isn't executed first.
+#[fixed_stack_segment]
+#[inline(never)]
pub fn init_tls_key() {
unsafe {
rust_initialize_rt_tls_key();
}
}
+#[fixed_stack_segment]
+#[inline(never)]
fn maybe_tls_key() -> Option<tls::Key> {
unsafe {
let key: *mut c_void = rust_get_rt_tls_key();
}
extern {
- #[fast_ffi]
fn rust_get_rt_tls_key() -> *mut c_void;
}
-
}
/// Configure logging by traversing the crate map and setting the
/// per-module global logging flags based on the logging spec
+#[fixed_stack_segment] #[inline(never)]
pub fn init(crate_map: *u8) {
use c_str::ToCStr;
use os;
}
}
+#[fixed_stack_segment] #[inline(never)]
pub fn console_on() { unsafe { rust_log_console_on() } }
+
+#[fixed_stack_segment] #[inline(never)]
pub fn console_off() { unsafe { rust_log_console_off() } }
+
+#[fixed_stack_segment] #[inline(never)]
fn should_log_console() -> bool { unsafe { rust_should_log_console() != 0 } }
extern {
return exit_code;
}
+#[cfg(stage0)]
+mod macro_hack {
+#[macro_escape];
+macro_rules! externfn(
+ (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ )
+)
+}
+
/// One-time runtime initialization.
///
/// Initializes global state, including frobbing
rust_update_gc_metadata(crate_map);
}
- extern {
- fn rust_update_gc_metadata(crate_map: *u8);
- }
+ externfn!(fn rust_update_gc_metadata(crate_map: *u8));
}
/// One-time runtime cleanup.
impl StackSegment {
pub fn new(size: uint) -> StackSegment {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
// Crate a block of uninitialized values
let mut stack = vec::with_capacity(size);
impl Drop for StackSegment {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
// XXX: Using the FFI to call a C macro. Slow
rust_valgrind_stack_deregister(self.valgrind_id);
}
pub fn begin_unwind(&mut self) -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+
self.unwinding = true;
unsafe {
rust_begin_unwind(UNWIND_TOKEN);
static RLIMIT_NOFILE: libc::c_int = 8;
pub unsafe fn raise_fd_limit() {
+ #[fixed_stack_segment]; #[inline(never)];
+
// The strategy here is to fetch the current resource limits, read the kern.maxfilesperproc
// sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value.
use ptr::{to_unsafe_ptr, to_mut_unsafe_ptr, mut_null};
}
/// Get a port number, starting at 9600, for use in tests
+#[fixed_stack_segment] #[inline(never)]
pub fn next_test_port() -> u16 {
unsafe {
return rust_dbg_next_port(base_port() as libc::uintptr_t) as u16;
impl Thread {
pub fn start(main: ~fn()) -> Thread {
fn substart(main: &~fn()) -> *raw_thread {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe { rust_raw_thread_start(main) }
}
let raw = substart(&main);
}
pub fn join(self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
assert!(!self.joined);
let mut this = self;
unsafe { rust_raw_thread_join(this.raw_thread); }
impl Drop for Thread {
fn drop(&self) {
+ #[fixed_stack_segment]; #[inline(never)];
+
assert!(self.joined);
unsafe { rust_raw_thread_delete(self.raw_thread) }
}
pub type Key = pthread_key_t;
#[cfg(unix)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn create(key: &mut Key) {
assert_eq!(0, pthread_key_create(key, null()));
}
#[cfg(unix)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn set(key: Key, value: *mut c_void) {
assert_eq!(0, pthread_setspecific(key, value));
}
#[cfg(unix)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn get(key: Key) -> *mut c_void {
pthread_getspecific(key)
}
pub type Key = DWORD;
#[cfg(windows)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn create(key: &mut Key) {
static TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF;
*key = TlsAlloc();
}
#[cfg(windows)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn set(key: Key, value: *mut c_void) {
assert!(0 != TlsSetValue(key, value))
}
#[cfg(windows)]
+#[fixed_stack_segment]
+#[inline(never)]
pub unsafe fn get(key: Key) -> *mut c_void {
TlsGetValue(key)
}
/// Get the number of cores available
pub fn num_cpus() -> uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
return rust_get_num_cpus();
}
rterrln!("%s", "");
rterrln!("fatal runtime error: %s", msg);
- unsafe { libc::abort(); }
+ abort();
+
+ fn abort() -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+ unsafe { libc::abort() }
+ }
}
pub fn set_exit_status(code: int) {
-
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
return rust_set_exit_status_newrt(code as libc::uintptr_t);
}
}
pub fn get_exit_status() -> int {
-
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
return rust_get_exit_status_newrt() as int;
}
/// Transmute an owned vector to a Buf
pub fn vec_to_uv_buf(v: ~[u8]) -> Buf {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let data = malloc(v.len() as size_t) as *u8;
assert!(data.is_not_null());
/// Transmute a Buf that was once a ~[u8] back to ~[u8]
pub fn vec_from_uv_buf(buf: Buf) -> Option<~[u8]> {
+ #[fixed_stack_segment]; #[inline(never)];
+
if !(buf.len == 0 && buf.base.is_null()) {
let v = unsafe { vec::from_buf(buf.base, buf.len as uint) };
unsafe { free(buf.base as *c_void) };
fn socket_name<T, U: Watcher + NativeHandle<*T>>(sk: SocketNameKind,
handle: U) -> Result<SocketAddr, IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
let getsockname = match sk {
TcpPeer => uvll::rust_uv_tcp_getpeername,
}
fn accept_simultaneously(&mut self) -> Result<(), IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
let r = unsafe {
uvll::rust_uv_tcp_simultaneous_accepts(self.watcher.native_handle(), 1 as c_int)
};
}
fn dont_accept_simultaneously(&mut self) -> Result<(), IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
let r = unsafe {
uvll::rust_uv_tcp_simultaneous_accepts(self.watcher.native_handle(), 0 as c_int)
};
}
fn control_congestion(&mut self) -> Result<(), IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
let r = unsafe {
uvll::rust_uv_tcp_nodelay(self.native_handle(), 0 as c_int)
};
}
fn nodelay(&mut self) -> Result<(), IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
let r = unsafe {
uvll::rust_uv_tcp_nodelay(self.native_handle(), 1 as c_int)
};
}
fn keepalive(&mut self, delay_in_seconds: uint) -> Result<(), IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
let r = unsafe {
uvll::rust_uv_tcp_keepalive(self.native_handle(), 1 as c_int,
delay_in_seconds as c_uint)
}
fn letdie(&mut self) -> Result<(), IoError> {
+ #[fixed_stack_segment]; #[inline(never)];
+
let r = unsafe {
uvll::rust_uv_tcp_keepalive(self.native_handle(), 0 as c_int, 0 as c_uint)
};
}
pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
assert!(handle != UV_UNKNOWN_HANDLE && handle != UV_HANDLE_TYPE_MAX);
let size = rust_uv_handle_size(handle as uint);
let p = malloc(size);
}
pub unsafe fn free_handle(v: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
free(v)
}
pub unsafe fn malloc_req(req: uv_req_type) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
assert!(req != UV_UNKNOWN_REQ && req != UV_REQ_TYPE_MAX);
let size = rust_uv_req_size(req as uint);
let p = malloc(size);
}
pub unsafe fn free_req(v: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
free(v)
}
#[test]
fn handle_sanity_check() {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
assert_eq!(UV_HANDLE_TYPE_MAX as uint, rust_uv_handle_type_max());
}
}
#[test]
+#[fixed_stack_segment]
+#[inline(never)]
fn request_sanity_check() {
unsafe {
assert_eq!(UV_REQ_TYPE_MAX as uint, rust_uv_req_type_max());
}
pub unsafe fn loop_new() -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_loop_new();
}
pub unsafe fn loop_delete(loop_handle: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_loop_delete(loop_handle);
}
pub unsafe fn run(loop_handle: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_run(loop_handle);
}
pub unsafe fn close<T>(handle: *T, cb: *u8) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_close(handle as *c_void, cb);
}
pub unsafe fn walk(loop_handle: *c_void, cb: *u8, arg: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_walk(loop_handle, cb, arg);
}
pub unsafe fn idle_new() -> *uv_idle_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_new()
}
pub unsafe fn idle_delete(handle: *uv_idle_t) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_delete(handle)
}
pub unsafe fn idle_init(loop_handle: *uv_loop_t, handle: *uv_idle_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_init(loop_handle, handle)
}
pub unsafe fn idle_start(handle: *uv_idle_t, cb: uv_idle_cb) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_start(handle, cb)
}
pub unsafe fn idle_stop(handle: *uv_idle_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_idle_stop(handle)
}
pub unsafe fn udp_init(loop_handle: *uv_loop_t, handle: *uv_udp_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_init(loop_handle, handle);
}
pub unsafe fn udp_bind(server: *uv_udp_t, addr: *sockaddr_in, flags: c_uint) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_bind(server, addr, flags);
}
pub unsafe fn udp_bind6(server: *uv_udp_t, addr: *sockaddr_in6, flags: c_uint) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_bind6(server, addr, flags);
}
pub unsafe fn udp_send<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
addr: *sockaddr_in, cb: uv_udp_send_cb) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = buf_in.len() as i32;
return rust_uv_udp_send(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb);
pub unsafe fn udp_send6<T>(req: *uv_udp_send_t, handle: *T, buf_in: &[uv_buf_t],
addr: *sockaddr_in6, cb: uv_udp_send_cb) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = buf_in.len() as i32;
return rust_uv_udp_send6(req, handle as *c_void, buf_ptr, buf_cnt, addr, cb);
pub unsafe fn udp_recv_start(server: *uv_udp_t, on_alloc: uv_alloc_cb,
on_recv: uv_udp_recv_cb) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_recv_start(server, on_alloc, on_recv);
}
pub unsafe fn udp_recv_stop(server: *uv_udp_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_recv_stop(server);
}
pub unsafe fn get_udp_handle_from_send_req(send_req: *uv_udp_send_t) -> *uv_udp_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_udp_handle_from_send_req(send_req);
}
pub unsafe fn udp_get_sockname(handle: *uv_udp_t, name: *sockaddr_storage) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_getsockname(handle, name);
}
pub unsafe fn udp_set_membership(handle: *uv_udp_t, multicast_addr: *c_char,
interface_addr: *c_char, membership: uv_membership) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_membership(handle, multicast_addr, interface_addr, membership as c_int);
}
pub unsafe fn udp_set_multicast_loop(handle: *uv_udp_t, on: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_multicast_loop(handle, on);
}
pub unsafe fn udp_set_multicast_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_multicast_ttl(handle, ttl);
}
pub unsafe fn udp_set_ttl(handle: *uv_udp_t, ttl: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_ttl(handle, ttl);
}
pub unsafe fn udp_set_broadcast(handle: *uv_udp_t, on: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_udp_set_broadcast(handle, on);
}
pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_init(loop_handle, handle);
}
pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
addr_ptr: *sockaddr_in, after_connect_cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
}
pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
addr_ptr: *sockaddr_in6, after_connect_cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
}
pub unsafe fn tcp_bind(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_bind(tcp_server_ptr, addr_ptr);
}
pub unsafe fn tcp_bind6(tcp_server_ptr: *uv_tcp_t, addr_ptr: *sockaddr_in6) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_bind6(tcp_server_ptr, addr_ptr);
}
pub unsafe fn tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_storage) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_getpeername(tcp_handle_ptr, name);
}
pub unsafe fn tcp_getsockname(handle: *uv_tcp_t, name: *sockaddr_storage) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_getsockname(handle, name);
}
pub unsafe fn tcp_nodelay(handle: *uv_tcp_t, enable: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_nodelay(handle, enable);
}
pub unsafe fn tcp_keepalive(handle: *uv_tcp_t, enable: c_int, delay: c_uint) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_keepalive(handle, enable, delay);
}
pub unsafe fn tcp_simultaneous_accepts(handle: *uv_tcp_t, enable: c_int) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_tcp_simultaneous_accepts(handle, enable);
}
pub unsafe fn listen<T>(stream: *T, backlog: c_int, cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_listen(stream as *c_void, backlog, cb);
}
pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_accept(server as *c_void, client as *c_void);
}
pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = buf_in.len() as i32;
return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb);
}
pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: uv_alloc_cb, on_read: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_read_start(stream as *c_void, on_alloc, on_read);
}
pub unsafe fn read_stop(stream: *uv_stream_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_read_stop(stream as *c_void);
}
pub unsafe fn last_error(loop_handle: *c_void) -> uv_err_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_last_error(loop_handle);
}
pub unsafe fn strerror(err: *uv_err_t) -> *c_char {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_strerror(err);
}
pub unsafe fn err_name(err: *uv_err_t) -> *c_char {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_err_name(err);
}
pub unsafe fn async_init(loop_handle: *c_void, async_handle: *uv_async_t, cb: *u8) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_async_init(loop_handle, async_handle, cb);
}
pub unsafe fn async_send(async_handle: *uv_async_t) {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_async_send(async_handle);
}
pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
let out_buf = uv_buf_t { base: ptr::null(), len: 0 as size_t };
let out_buf_ptr = ptr::to_unsafe_ptr(&out_buf);
rust_uv_buf_init(out_buf_ptr, input, len as size_t);
}
pub unsafe fn timer_init(loop_ptr: *c_void, timer_ptr: *uv_timer_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_timer_init(loop_ptr, timer_ptr);
}
pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: u64,
repeat: u64) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_timer_start(timer_ptr, cb, timeout, repeat);
}
pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_timer_stop(timer_ptr);
}
pub unsafe fn is_ip4_addr(addr: *sockaddr) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
match rust_uv_is_ipv4_sockaddr(addr) { 0 => false, _ => true }
}
pub unsafe fn is_ip6_addr(addr: *sockaddr) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
match rust_uv_is_ipv6_sockaddr(addr) { 0 => false, _ => true }
}
pub unsafe fn malloc_ip4_addr(ip: &str, port: int) -> *sockaddr_in {
+ #[fixed_stack_segment]; #[inline(never)];
do ip.with_c_str |ip_buf| {
rust_uv_ip4_addrp(ip_buf as *u8, port as libc::c_int)
}
}
pub unsafe fn malloc_ip6_addr(ip: &str, port: int) -> *sockaddr_in6 {
+ #[fixed_stack_segment]; #[inline(never)];
do ip.with_c_str |ip_buf| {
rust_uv_ip6_addrp(ip_buf as *u8, port as libc::c_int)
}
}
pub unsafe fn malloc_sockaddr_storage() -> *sockaddr_storage {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_malloc_sockaddr_storage()
}
pub unsafe fn free_sockaddr_storage(ss: *sockaddr_storage) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_free_sockaddr_storage(ss);
}
pub unsafe fn free_ip4_addr(addr: *sockaddr_in) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_free_ip4_addr(addr);
}
pub unsafe fn free_ip6_addr(addr: *sockaddr_in6) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_free_ip6_addr(addr);
}
pub unsafe fn ip4_name(addr: *sockaddr_in, dst: *u8, size: size_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_ip4_name(addr, dst, size);
}
pub unsafe fn ip6_name(addr: *sockaddr_in6, dst: *u8, size: size_t) -> c_int {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_ip6_name(addr, dst, size);
}
pub unsafe fn ip4_port(addr: *sockaddr_in) -> c_uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_ip4_port(addr);
}
pub unsafe fn ip6_port(addr: *sockaddr_in6) -> c_uint {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_ip6_port(addr);
}
// data access helpers
pub unsafe fn get_loop_for_uv_handle<T>(handle: *T) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_loop_for_uv_handle(handle as *c_void);
}
pub unsafe fn get_stream_handle_from_connect_req(connect: *uv_connect_t) -> *uv_stream_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_stream_handle_from_connect_req(connect);
}
pub unsafe fn get_stream_handle_from_write_req(write_req: *uv_write_t) -> *uv_stream_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_stream_handle_from_write_req(write_req);
}
pub unsafe fn get_data_for_uv_loop(loop_ptr: *c_void) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_get_data_for_uv_loop(loop_ptr)
}
pub unsafe fn set_data_for_uv_loop(loop_ptr: *c_void, data: *c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_set_data_for_uv_loop(loop_ptr, data);
}
pub unsafe fn get_data_for_uv_handle<T>(handle: *T) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_data_for_uv_handle(handle as *c_void);
}
pub unsafe fn set_data_for_uv_handle<T, U>(handle: *T, data: *U) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_set_data_for_uv_handle(handle as *c_void, data as *c_void);
}
pub unsafe fn get_data_for_req<T>(req: *T) -> *c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_data_for_req(req as *c_void);
}
pub unsafe fn set_data_for_req<T, U>(req: *T, data: *U) {
+ #[fixed_stack_segment]; #[inline(never)];
+
rust_uv_set_data_for_req(req as *c_void, data as *c_void);
}
pub unsafe fn get_base_from_buf(buf: uv_buf_t) -> *u8 {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_base_from_buf(buf);
}
pub unsafe fn get_len_from_buf(buf: uv_buf_t) -> size_t {
+ #[fixed_stack_segment]; #[inline(never)];
+
return rust_uv_get_len_from_buf(buf);
}
pub unsafe fn get_last_err_info(uv_loop: *c_void) -> ~str {
* * options - Options to configure the environment of the process,
* the working directory and the standard IO streams.
*/
- pub fn new(prog: &str, args: &[~str], options: ProcessOptions)
+ pub fn new(prog: &str, args: &[~str],
+ options: ProcessOptions)
-> Process {
+ #[fixed_stack_segment]; #[inline(never)];
+
let (in_pipe, in_fd) = match options.in_fd {
None => {
let pipe = os::pipe();
* method does nothing.
*/
pub fn close_input(&mut self) {
+ #[fixed_stack_segment]; #[inline(never)];
match self.input {
Some(-1) | None => (),
Some(fd) => {
}
fn close_outputs(&mut self) {
+ #[fixed_stack_segment]; #[inline(never)];
fclose_and_null(&mut self.output);
fclose_and_null(&mut self.error);
fn fclose_and_null(f_opt: &mut Option<*libc::FILE>) {
+ #[allow(cstack)]; // fixed_stack_segment declared on enclosing fn
match *f_opt {
Some(f) if !f.is_null() => {
unsafe {
#[cfg(windows)]
fn killpid(pid: pid_t, _force: bool) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::funcs::extra::kernel32::TerminateProcess(
cast::transmute(pid), 1);
#[cfg(unix)]
fn killpid(pid: pid_t, force: bool) {
+ #[fixed_stack_segment]; #[inline(never)];
+
let signal = if force {
libc::consts::os::posix88::SIGKILL
} else {
env: Option<~[(~str, ~str)]>,
dir: Option<&Path>,
in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO};
use libc::consts::os::extra::{
env: Option<~[(~str, ~str)]>,
dir: Option<&Path>,
in_fd: c_int, out_fd: c_int, err_fd: c_int) -> SpawnProcessResult {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp};
use libc::funcs::bsd44::getdtablesize;
#[cfg(windows)]
fn free_handle(handle: *()) {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
libc::funcs::extra::kernel32::CloseHandle(cast::transmute(handle));
}
#[cfg(windows)]
fn waitpid_os(pid: pid_t) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::types::os::arch::extra::DWORD;
use libc::consts::os::extra::{
#[cfg(unix)]
fn waitpid_os(pid: pid_t) -> int {
+ #[fixed_stack_segment]; #[inline(never)];
use libc::funcs::posix01::wait::*;
}
fn readclose(fd: c_int) -> ~str {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
let file = os::fdopen(fd);
let reader = io::FILE_reader(file, false);
}
fn running_on_valgrind() -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe { rust_running_on_valgrind() != 0 }
}
pub use fmt;
pub use to_bytes;
}
+
#[test]
fn test_map() {
+ #[fixed_stack_segment]; #[inline(never)];
assert_eq!(~"", "".map_chars(|c| unsafe {libc::toupper(c as c_char)} as char));
assert_eq!(~"YMCA", "ymca".map_chars(|c| unsafe {libc::toupper(c as c_char)} as char));
}
// above.
let data = match util::replace(entry, None) {
Some((_, data, _)) => data,
- None => libc::abort(),
+ None => abort(),
};
// Move `data` into transmute to get out the memory that it
}
}
}
- _ => libc::abort()
+ _ => abort()
}
// n.b. 'data' and 'loans' are both invalid pointers at the point
if return_loan {
match map[i] {
Some((_, _, ref mut loan)) => { *loan = NoLoan; }
- None => { libc::abort(); }
+ None => { abort(); }
}
}
return ret;
}
}
+fn abort() -> ! {
+ #[fixed_stack_segment]; #[inline(never)];
+
+ unsafe { libc::abort() }
+}
+
pub unsafe fn local_set<T: 'static>(handle: Handle,
key: local_data::Key<T>,
data: T) {
mod testrt {
use libc;
- #[nolink]
- extern {
- pub fn rust_dbg_lock_create() -> *libc::c_void;
- pub fn rust_dbg_lock_destroy(lock: *libc::c_void);
- pub fn rust_dbg_lock_lock(lock: *libc::c_void);
- pub fn rust_dbg_lock_unlock(lock: *libc::c_void);
- pub fn rust_dbg_lock_wait(lock: *libc::c_void);
- pub fn rust_dbg_lock_signal(lock: *libc::c_void);
- }
+ externfn!(fn rust_dbg_lock_create() -> *libc::c_void)
+ externfn!(fn rust_dbg_lock_destroy(lock: *libc::c_void))
+ externfn!(fn rust_dbg_lock_lock(lock: *libc::c_void))
+ externfn!(fn rust_dbg_lock_unlock(lock: *libc::c_void))
+ externfn!(fn rust_dbg_lock_wait(lock: *libc::c_void))
+ externfn!(fn rust_dbg_lock_signal(lock: *libc::c_void))
}
#[test]
use result::*;
pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
do filename.with_c_str |raw_name| {
dlopen(raw_name, Lazy as libc::c_int)
}
}
pub unsafe fn open_internal() -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
dlopen(ptr::null(), Lazy as libc::c_int)
}
pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
+ #[fixed_stack_segment]; #[inline(never)];
+
unsafe {
do atomically {
let _old_error = dlerror();
}
pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
+
dlsym(handle, symbol)
}
pub unsafe fn close(handle: *libc::c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
+
dlclose(handle); ()
}
use result::*;
pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
do os::win32::as_utf16_p(filename.to_str()) |raw_name| {
LoadLibraryW(raw_name)
}
}
pub unsafe fn open_internal() -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
let handle = ptr::null();
GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &handle as **libc::c_void);
handle
}
pub fn check_for_errors_in<T>(f: &fn()->T) -> Result<T, ~str> {
+ #[fixed_stack_segment]; #[inline(never)];
unsafe {
do atomically {
SetLastError(0);
}
}
pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
+ #[fixed_stack_segment]; #[inline(never)];
GetProcAddress(handle, symbol)
}
pub unsafe fn close(handle: *libc::c_void) {
+ #[fixed_stack_segment]; #[inline(never)];
FreeLibrary(handle); ()
}
/// can lead to deadlock. Calling change_dir_locked recursively will
/// also deadlock.
pub fn change_dir_locked(p: &Path, action: &fn()) -> bool {
+ #[fixed_stack_segment]; #[inline(never)];
+
use os;
use os::change_dir;
use unstable::sync::atomically;
}
}
- #[inline]
pub unsafe fn lock<T>(&self, f: &fn() -> T) -> T {
do atomically {
rust_lock_little_lock(self.l);
}
}
-extern {
- fn rust_create_little_lock() -> rust_little_lock;
- fn rust_destroy_little_lock(lock: rust_little_lock);
- fn rust_lock_little_lock(lock: rust_little_lock);
- fn rust_unlock_little_lock(lock: rust_little_lock);
+#[cfg(stage0)]
+mod macro_hack {
+#[macro_escape];
+macro_rules! externfn(
+ (fn $name:ident () $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name() $(-> $ret_ty),*;
+ }
+ );
+ (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ )
+)
}
+externfn!(fn rust_create_little_lock() -> rust_little_lock)
+externfn!(fn rust_destroy_little_lock(lock: rust_little_lock))
+externfn!(fn rust_lock_little_lock(lock: rust_little_lock))
+externfn!(fn rust_unlock_little_lock(lock: rust_little_lock))
+
#[cfg(test)]
mod tests {
use cell::Cell;
pub static $name: ::std::local_data::Key<$ty> = &::std::local_data::Key;
)
)
+
+ // externfn! declares a wrapper for an external function.
+ // It is intended to be used like:
+ //
+ // externfn!(#[nolink]
+ // #[abi = \"cdecl\"]
+ // fn memcmp(cx: *u8, ct: *u8, n: u32) -> u32)
+ //
+ // Due to limitations in the macro parser, this pattern must be
+ // implemented with 4 distinct patterns (with attrs / without
+ // attrs CROSS with args / without ARGS).
+ //
+ // Also, this macro grammar allows for any number of return types
+ // because I couldn't figure out the syntax to specify at most one.
+ macro_rules! externfn(
+ (fn $name:ident () $(-> $ret_ty:ty),*) => (
+ pub unsafe fn $name() $(-> $ret_ty),* {
+ // Note: to avoid obscure bug in macros, keep these
+ // attributes *internal* to the fn
+ #[fixed_stack_segment];
+ #[inline(never)];
+ #[allow(missing_doc)];
+
+ return $name();
+
+ extern {
+ fn $name() $(-> $ret_ty),*;
+ }
+ }
+ );
+ (fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ pub unsafe fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),* {
+ // Note: to avoid obscure bug in macros, keep these
+ // attributes *internal* to the fn
+ #[fixed_stack_segment];
+ #[inline(never)];
+ #[allow(missing_doc)];
+
+ return $name($($arg_name),*);
+
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ }
+ );
+ ($($attrs:attr)* fn $name:ident () $(-> $ret_ty:ty),*) => (
+ pub unsafe fn $name() $(-> $ret_ty),* {
+ // Note: to avoid obscure bug in macros, keep these
+ // attributes *internal* to the fn
+ #[fixed_stack_segment];
+ #[inline(never)];
+ #[allow(missing_doc)];
+
+ return $name();
+
+ $($attrs)*
+ extern {
+ fn $name() $(-> $ret_ty),*;
+ }
+ }
+ );
+ ($($attrs:attr)* fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
+ pub unsafe fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),* {
+ // Note: to avoid obscure bug in macros, keep these
+ // attributes *internal* to the fn
+ #[fixed_stack_segment];
+ #[inline(never)];
+ #[allow(missing_doc)];
+
+ return $name($($arg_name),*);
+
+ $($attrs)*
+ extern {
+ fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
+ }
+ }
+ )
+ )
+
}";
}
}
}
+#[fixed_stack_segment] #[inline(never)]
pub fn fact(n: uint) -> uint {
unsafe {
info!("n = %?", n);
// Exercise the unused_unsafe attribute in some positive and negative cases
+#[allow(cstack)];
#[deny(unused_unsafe)];
mod foo {
}
}
}
+
unsafe fn good3() { foo::bar() }
fn good4() { unsafe { foo::bar() } }
use anonexternmod::*;
+#[fixed_stack_segment]
pub fn main() {
unsafe {
rust_get_test_int();
fn rust_get_test_int() -> libc::intptr_t;
}
+#[fixed_stack_segment]
pub fn main() {
unsafe {
let _ = rust_get_test_int();
}
}
+#[fixed_stack_segment]
fn atol(s: ~str) -> int {
s.with_c_str(|x| unsafe { libc::atol(x) as int })
}
+#[fixed_stack_segment]
fn atoll(s: ~str) -> i64 {
s.with_c_str(|x| unsafe { libc::atoll(x) as i64 })
}
}
}
+#[fixed_stack_segment]
fn count(n: uint) -> uint {
unsafe {
info!("n = %?", n);
}
}
+#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
info!("n = %?", n);
}
}
+#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
info!("n = %?", n);
}
}
+#[fixed_stack_segment] #[inline(never)]
fn fact(n: uint) -> uint {
unsafe {
info!("n = %?", n);
extern mod externcallback(vers = "0.1");
+#[fixed_stack_segment] #[inline(never)]
fn fact(n: uint) -> uint {
unsafe {
info!("n = %?", n);
pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let x = TwoU32s {one: 22, two: 23};
pub fn rust_dbg_extern_identity_TwoU64s(u: TwoU64s) -> TwoU64s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let x = TwoU64s {one: 22, two: 23};
pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let x = TwoU64s {one: 22, two: 23};
pub fn rust_dbg_extern_identity_u8(v: u8) -> u8;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22_u8, rust_dbg_extern_identity_u8(22_u8));
pub fn rust_dbg_extern_identity_double(v: f64) -> f64;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22.0_f64, rust_dbg_extern_identity_double(22.0_f64));
pub fn rust_dbg_extern_identity_u32(v: u32) -> u32;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22_u32, rust_dbg_extern_identity_u32(22_u32));
pub fn rust_dbg_extern_identity_u64(v: u64) -> u64;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
assert_eq!(22_u64, rust_dbg_extern_identity_u64(22_u64));
pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU16s();
pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU32s();
pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU64s();
pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s;
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let y = rust_dbg_extern_return_TwoU8s();
}
}
+#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
rustrt::rust_dbg_call(cb, n)
}
}
+#[fixed_stack_segment] #[inline(never)]
fn count(n: uint) -> uint {
unsafe {
task::deschedule();
use std::libc;
use std::unstable::run_in_bare_thread;
-extern {
- pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t) -> libc::uintptr_t;
-}
+externfn!(fn rust_dbg_call(cb: *u8, data: libc::uintptr_t) -> libc::uintptr_t)
pub fn main() {
unsafe {
}
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
rustrt1::rust_get_test_int();
}
}
+#[fixed_stack_segment] #[inline(never)]
fn strlen(str: ~str) -> uint {
// C string is terminated with a zero
do str.with_c_str |buf| {
}
}
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
rustrt::rust_get_test_int();
extern mod foreign_lib;
+#[fixed_stack_segment] #[inline(never)]
pub fn main() {
unsafe {
let _foo = foreign_lib::rustrt::rust_get_test_int();
}
}
+#[fixed_stack_segment] #[inline(never)]
fn lgamma(n: c_double, value: &mut int) -> c_double {
unsafe {
return m::lgamma(n, to_c_int(value));
pub struct Fd(c_int);
impl Drop for Fd {
+ #[fixed_stack_segment] #[inline(never)]
fn drop(&self) {
unsafe {
libc::close(**self);
}
}
+#[fixed_stack_segment] #[inline(never)]
fn main() {
unsafe {
a::free(transmute(0));
x: int
}
+#[fixed_stack_segment] #[inline(never)]
fn alloc<'a>(_bcx : &'a arena) -> &'a Bcx<'a> {
unsafe {
cast::transmute(libc::malloc(sys::size_of::<Bcx<'blk>>()
return alloc(bcx.fcx.arena);
}
+#[fixed_stack_segment] #[inline(never)]
fn g(fcx : &Fcx) {
let bcx = Bcx { fcx: fcx };
let bcx2 = h(&bcx);
*a = 3;
}
+#[fixed_stack_segment] #[inline(never)]
unsafe fn run() {
assert!(debug_static_mut == 3);
debug_static_mut = 4;
}
}
+#[fixed_stack_segment] #[inline(never)]
fn test1() {
unsafe {
let q = Quad { a: 0xaaaa_aaaa_aaaa_aaaa_u64,
}
#[cfg(target_arch = "x86_64")]
+#[fixed_stack_segment]
+#[inline(never)]
fn test2() {
unsafe {
let f = Floats { a: 1.234567890e-15_f64,
#[cfg(target_os = "win32")]
+#[fixed_stack_segment]
pub fn main() {
let heap = unsafe { kernel32::GetProcessHeap() };
let mem = unsafe { kernel32::HeapAlloc(heap, 0u32, 100u32) };