From 67cdcc2e12118becb823e20a40cc2687f2b8425a Mon Sep 17 00:00:00 2001 From: Adam Carpenter <53hornet@gmail.com> Date: Wed, 27 Mar 2019 15:32:37 -0400 Subject: Started Rust in Action MEAP. --- meap/meap-code/ch10/ch10-sjlj/Cargo.toml | 7 ++ meap/meap-code/ch10/ch10-sjlj/Dockerfile | 37 +++++++++++ meap/meap-code/ch10/ch10-sjlj/Makefile | 2 + meap/meap-code/ch10/ch10-sjlj/src/main.rs | 105 ++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 meap/meap-code/ch10/ch10-sjlj/Cargo.toml create mode 100644 meap/meap-code/ch10/ch10-sjlj/Dockerfile create mode 100644 meap/meap-code/ch10/ch10-sjlj/Makefile create mode 100644 meap/meap-code/ch10/ch10-sjlj/src/main.rs (limited to 'meap/meap-code/ch10/ch10-sjlj') diff --git a/meap/meap-code/ch10/ch10-sjlj/Cargo.toml b/meap/meap-code/ch10/ch10-sjlj/Cargo.toml new file mode 100644 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 "] + +[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 100644 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 100644 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 100644 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::() * 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!") +} -- cgit v1.2.3