about summary refs log tree commit diff
path: root/src/libstd/sys/windows/stack_overflow.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-12-19 08:28:52 +0000
committerbors <bors@rust-lang.org>2014-12-19 08:28:52 +0000
commit0efafac398ff7f28c5f0fe756c15b9008b3e0534 (patch)
tree2e8279b94829b65868049d2e3df0b9a6c3365a8f /src/libstd/sys/windows/stack_overflow.rs
parent6bdce25e155d846bb9252fa4a18baef7e74cf8bf (diff)
parent903c5a8f69714382ec9fc22745f902c3e219cb68 (diff)
auto merge of #19654 : aturon/rust/merge-rt, r=alexcrichton
This PR substantially narrows the notion of a "runtime" in Rust, and allows calling into Rust code directly without any setup or teardown. 

After this PR, the basic "runtime support" in Rust will consist of:

* Unwinding and backtrace support
* Stack guards

Other support, such as helper threads for timers or the notion of a "current thread" are initialized automatically upon first use.

When using Rust in an embedded context, it should now be possible to call a Rust function directly as a C function with absolutely no setup, though in that case panics will cause the process to abort. In this regard, the C/Rust interface will look much like the C/C++ interface.

In more detail, this PR:

* Merges `librustrt` back into `std::rt`, undoing the facade. While doing so, it removes a substantial amount of redundant functionality (such as mutexes defined in the `rt` module). Code using `librustrt` can now call into `std::rt` to e.g. start executing Rust code with unwinding support.

* Allows all runtime data to be initialized lazily, including the "current thread", the "at_exit" infrastructure, and the "args" storage.

* Deprecates and largely removes `std::task` along with the widespread requirement that there be a "current task" for many APIs in `std`. The entire task infrastructure is replaced with `std::thread`, which provides a more standard API for manipulating and creating native OS threads. In particular, it's possible to join on a created thread, and to get a handle to the currently-running thread. In addition, threads are equipped with some basic blocking support in the form of `park`/`unpark` operations (following a tradition in some OSes as well as the JVM). See the `std::thread` documentation for more details.

* Channels are refactored to use a new internal blocking infrastructure that itself sits on top of `park`/`unpark`.

One important change here is that a Rust program ends when its main thread does, following most threading models. On the other hand, threads will often be created with an RAII-style join handle that will re-institute blocking semantics naturally (and with finer control).

This is very much a:

[breaking-change]

Closes #18000
r? @alexcrichton 
Diffstat (limited to 'src/libstd/sys/windows/stack_overflow.rs')
-rw-r--r--src/libstd/sys/windows/stack_overflow.rs115
1 files changed, 115 insertions, 0 deletions
diff --git a/src/libstd/sys/windows/stack_overflow.rs b/src/libstd/sys/windows/stack_overflow.rs
new file mode 100644
index 00000000000..bdf2e0bccb1
--- /dev/null
+++ b/src/libstd/sys/windows/stack_overflow.rs
@@ -0,0 +1,115 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rt::util::report_overflow;
+use core::prelude::*;
+use ptr;
+use mem;
+use libc;
+use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL};
+use sys_common::{stack, thread_info};
+
+pub struct Handler {
+    _data: *mut libc::c_void
+}
+
+impl Handler {
+    pub unsafe fn new() -> Handler {
+        make_handler()
+    }
+}
+
+impl Drop for Handler {
+    fn drop(&mut self) {}
+}
+
+// get_task_info is called from an exception / signal handler.
+// It returns the guard page of the current task or 0 if that
+// guard page doesn't exist. None is returned if there's currently
+// no local task.
+unsafe fn get_task_guard_page() -> uint {
+    thread_info::stack_guard()
+}
+
+// This is initialized in init() and only read from after
+static mut PAGE_SIZE: uint = 0;
+
+#[no_stack_check]
+extern "system" fn vectored_handler(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG {
+    unsafe {
+        let rec = &(*(*ExceptionInfo).ExceptionRecord);
+        let code = rec.ExceptionCode;
+
+        if code != EXCEPTION_STACK_OVERFLOW {
+            return EXCEPTION_CONTINUE_SEARCH;
+        }
+
+        // We're calling into functions with stack checks,
+        // however stack checks by limit should be disabled on Windows
+        stack::record_sp_limit(0);
+
+        report_overflow();
+
+        EXCEPTION_CONTINUE_SEARCH
+    }
+}
+
+pub unsafe fn init() {
+    let mut info = mem::zeroed();
+    libc::GetSystemInfo(&mut info);
+    PAGE_SIZE = info.dwPageSize as uint;
+
+    if AddVectoredExceptionHandler(0, vectored_handler) == ptr::null_mut() {
+        panic!("failed to install exception handler");
+    }
+
+    mem::forget(make_handler());
+}
+
+pub unsafe fn cleanup() {
+}
+
+pub unsafe fn make_handler() -> Handler {
+    if SetThreadStackGuarantee(&mut 0x5000) == 0 {
+        panic!("failed to reserve stack space for exception handling");
+    }
+
+    Handler { _data: 0i as *mut libc::c_void }
+}
+
+pub struct EXCEPTION_RECORD {
+    pub ExceptionCode: DWORD,
+    pub ExceptionFlags: DWORD,
+    pub ExceptionRecord: *mut EXCEPTION_RECORD,
+    pub ExceptionAddress: LPVOID,
+    pub NumberParameters: DWORD,
+    pub ExceptionInformation: [LPVOID, ..EXCEPTION_MAXIMUM_PARAMETERS]
+}
+
+pub struct EXCEPTION_POINTERS {
+    pub ExceptionRecord: *mut EXCEPTION_RECORD,
+    pub ContextRecord: LPVOID
+}
+
+pub type PVECTORED_EXCEPTION_HANDLER = extern "system"
+        fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG;
+
+pub type ULONG = libc::c_ulong;
+
+const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
+const EXCEPTION_MAXIMUM_PARAMETERS: uint = 15;
+const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
+
+extern "system" {
+    fn AddVectoredExceptionHandler(FirstHandler: ULONG,
+                                   VectoredHandler: PVECTORED_EXCEPTION_HANDLER)
+                                  -> LPVOID;
+    fn SetThreadStackGuarantee(StackSizeInBytes: *mut ULONG) -> BOOL;
+}