diff options
author | Adam Carpenter <gitlab@53hor.net> | 2019-07-09 15:14:04 -0400 |
---|---|---|
committer | Adam Carpenter <gitlab@53hor.net> | 2019-07-09 15:14:04 -0400 |
commit | 7e8ee5ed9cad6484e9f13f81731b102ced58402e (patch) | |
tree | 5395402ab07bbb5a659dbd68c701e22a1227202f /meap/meap-code/ch10/ch10-sjlj | |
download | learning-rust-7e8ee5ed9cad6484e9f13f81731b102ced58402e.tar.xz learning-rust-7e8ee5ed9cad6484e9f13f81731b102ced58402e.zip |
Init.
Diffstat (limited to 'meap/meap-code/ch10/ch10-sjlj')
-rwxr-xr-x | meap/meap-code/ch10/ch10-sjlj/Cargo.toml | 7 | ||||
-rwxr-xr-x | meap/meap-code/ch10/ch10-sjlj/Dockerfile | 37 | ||||
-rwxr-xr-x | meap/meap-code/ch10/ch10-sjlj/Makefile | 2 | ||||
-rwxr-xr-x | meap/meap-code/ch10/ch10-sjlj/src/main.rs | 105 |
4 files changed, 151 insertions, 0 deletions
diff --git a/meap/meap-code/ch10/ch10-sjlj/Cargo.toml b/meap/meap-code/ch10/ch10-sjlj/Cargo.toml new file mode 100755 index 0000000..c9eab65 --- /dev/null +++ b/meap/meap-code/ch10/ch10-sjlj/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "ch10-sjlj" +version = "0.1.0" +authors = ["Tim McNamara <code@timmcnamara.co.nz>"] + +[dependencies] +libc = "0.2"
\ No newline at end of file diff --git a/meap/meap-code/ch10/ch10-sjlj/Dockerfile b/meap/meap-code/ch10/ch10-sjlj/Dockerfile new file mode 100755 index 0000000..ba5e1f0 --- /dev/null +++ b/meap/meap-code/ch10/ch10-sjlj/Dockerfile @@ -0,0 +1,37 @@ +# build strategy sourced from:
+# - https://www.fpcomplete.com/blog/2018/07/deploying-rust-with-docker-and-kubernetes
+# - http://whitfin.io/speeding-up-rust-docker-builds/
+
+# This image will build all dependencies before you
+# introducing the project's source code, which means
+# they'll be cached most of the time.
+
+FROM rust:latest as intermediate
+RUN rustup toolchain install nightly
+RUN rustup default nightly
+RUN rustup target add x86_64-unknown-linux-musl
+
+ENV PATH $PATH:/root/.cargo/bin
+ENV PKG_CONFIG_ALLOW_CROSS=1
+
+# fetch dependencies using a minimal project,
+# enabling the docker image to be cached with dependencies installed
+RUN USER=root cargo new --bin project
+WORKDIR /project
+
+COPY ./Cargo.lock ./Cargo.lock
+COPY ./Cargo.toml ./Cargo.toml
+
+#RUN cargo -v build --target x86_64-unknown-linux-musl
+
+# build actual project
+#RUN rm src/*.rs
+COPY ./src ./src
+RUN cargo +nightly -v check
+RUN cargo +nightly -v build --target x86_64-unknown-linux-musl
+RUN ls -R /project/target
+
+FROM alpine
+COPY --from=intermediate /project/target/x86_64-unknown-linux-musl/debug/ch10-sjlj /
+
+CMD /ch10-sjlj
diff --git a/meap/meap-code/ch10/ch10-sjlj/Makefile b/meap/meap-code/ch10/ch10-sjlj/Makefile new file mode 100755 index 0000000..d68912d --- /dev/null +++ b/meap/meap-code/ch10/ch10-sjlj/Makefile @@ -0,0 +1,2 @@ +container:
+ docker build -t ria-ch10-sjlj .
\ No newline at end of file diff --git a/meap/meap-code/ch10/ch10-sjlj/src/main.rs b/meap/meap-code/ch10/ch10-sjlj/src/main.rs new file mode 100755 index 0000000..baac669 --- /dev/null +++ b/meap/meap-code/ch10/ch10-sjlj/src/main.rs @@ -0,0 +1,105 @@ +#![feature(link_llvm_intrinsics)] +#![allow(non_camel_case_types)] +#![cfg(not(windows))] + +extern crate libc; + +use libc::{SIGUSR1, SIGALRM, SIGHUP, SIGQUIT, SIGTERM}; +use std::mem; + +const JMP_BUF_WIDTH: usize = mem::size_of::<usize>() * 8; +type jmp_buf = [i8; JMP_BUF_WIDTH]; + +static mut SHUT_DOWN: bool = false; +static mut RETURN_HERE: jmp_buf = [0; JMP_BUF_WIDTH]; +const MOCK_SIGNAL_AT: usize = 3; + +extern "C" { + #[link_name = "llvm.setjmp"] + pub fn setjmp(a: *mut i8) -> i32; + + #[link_name = "llvm.longjmp"] + pub fn longjmp(a: *mut i8, b: i32) -> (); +} + +#[inline] +fn ptr_to_jmp_buf() -> *mut i8 { + unsafe { &RETURN_HERE as *const i8 as *mut i8 } +} + +#[inline] +fn return_early() { + let franken_pointer = ptr_to_jmp_buf(); + unsafe { longjmp(franken_pointer, 1) }; +} + +fn register_signal_handler() { + unsafe { + libc::signal(SIGUSR1, handle_signals as usize); // <4> + } +} + +#[allow(dead_code)] // <5> +fn handle_signals(sig: i32) { + register_signal_handler(); // Immediately re-registering the signal handler minimizes the chances of a missing a signal. + + let should_shut_down = match sig { + SIGHUP => false, // <7> + SIGALRM => false, // <7> + SIGTERM => true, // <7> + SIGQUIT => true, // <7> + SIGUSR1 => true, + _ => false, // <7> + }; + + unsafe { + // This unsafe block is required because we are modifying a global static variable. + SHUT_DOWN = should_shut_down; + } + + return_early(); +} + +fn print_depth(depth: usize) { + for _ in 0..depth { + print!("#"); + } + println!(""); +} + +fn dive(depth: usize, max_depth: usize) { + unsafe { + if SHUT_DOWN == true { + println!("!"); + return; + } + } + print_depth(depth); + + if depth >= max_depth { + return; + } else if depth == MOCK_SIGNAL_AT { + unsafe { + libc::raise(SIGUSR1); + } + } else { + dive(depth + 1, max_depth); + } + print_depth(depth); +} + +fn main() { + const JUMP_SET: i32 = 0; + + register_signal_handler(); + + let return_point = ptr_to_jmp_buf(); + let rc = unsafe { setjmp(return_point) }; + if rc == JUMP_SET { + dive(0, 10); + } else { + println!("early return!"); + } + + println!("finishing!") +} |