diff options
Diffstat (limited to 'meap/meap-code/ch10')
19 files changed, 478 insertions, 0 deletions
diff --git a/meap/meap-code/ch10/Vagrantfile b/meap/meap-code/ch10/Vagrantfile new file mode 100644 index 0000000..b306dd1 --- /dev/null +++ b/meap/meap-code/ch10/Vagrantfile @@ -0,0 +1,29 @@ +VAGRANTFILE_VERSION = "2"
+
+$provision_external = <<SCRIPT
+sudo apt-get -qq update
+sudo apt-get install -q -y curl
+
+curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain nightly
+SCRIPT
+
+# $provision_internal = <<SCRIPT
+# cd ~
+# mkdir code
+# sudo mount -t vboxsf code ./code
+# SCRIPT
+
+
+Vagrant.configure(VAGRANTFILE_VERSION) do |config|
+
+ config.vm.provider "virtualbox" do |v|
+ v.name = "rust_in_action"
+ v.linked_clone = true
+ end
+
+ config.vm.box = "bento/ubuntu-17.04-i386"
+ config.vm.synced_folder ".", "/ch10/"
+ config.vm.post_up_message = "Hope that you're enjoying Rust in Action!\n-TS McNamara"
+ config.vm.provision "shell", inline: $provision_external
+ #config.vm.provision "shell", inline: $provision_internal
+end
\ No newline at end of file diff --git a/meap/meap-code/ch10/ch10-basic-handler/Cargo.toml b/meap/meap-code/ch10/ch10-basic-handler/Cargo.toml new file mode 100644 index 0000000..7cc2735 --- /dev/null +++ b/meap/meap-code/ch10/ch10-basic-handler/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "basic-handler" +version = "0.1.0" +authors = ["Tim McNamara <code@timmcnamara.co.nz>"] + +[dependencies] + +[target.'cfg(not(windows))'.dependencies] +libc = "0.2"
\ No newline at end of file diff --git a/meap/meap-code/ch10/ch10-basic-handler/Dockerfile b/meap/meap-code/ch10/ch10-basic-handler/Dockerfile new file mode 100644 index 0000000..cc17065 --- /dev/null +++ b/meap/meap-code/ch10/ch10-basic-handler/Dockerfile @@ -0,0 +1,36 @@ +# 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 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 -v check
+RUN cargo -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/basic-handler /
+
+CMD /basic-handler
diff --git a/meap/meap-code/ch10/ch10-basic-handler/Makefile b/meap/meap-code/ch10/ch10-basic-handler/Makefile new file mode 100644 index 0000000..9d1a25f --- /dev/null +++ b/meap/meap-code/ch10/ch10-basic-handler/Makefile @@ -0,0 +1,2 @@ +container:
+ docker build -t ria-ch10-simple-handler .
\ No newline at end of file diff --git a/meap/meap-code/ch10/ch10-basic-handler/src/main.rs b/meap/meap-code/ch10/ch10-basic-handler/src/main.rs new file mode 100644 index 0000000..a7ecb33 --- /dev/null +++ b/meap/meap-code/ch10/ch10-basic-handler/src/main.rs @@ -0,0 +1,58 @@ +#![cfg(not(windows))] // <1> + +extern crate libc; + +use std::mem; +use std::time; +use std::thread::{sleep}; +use libc::{SIGTERM, SIGALRM, SIGHUP, SIGQUIT}; + +static mut SHUT_DOWN: bool = false; + +fn register_signal_handler() { + let fn_ptr: fn(i32) -> () = handle_signals; // <2> + + unsafe { + let fn_ptr_as_usize: usize = mem::transmute(fn_ptr); // <3> + libc::signal(SIGTERM, fn_ptr_as_usize); // <4> + } +} + +#[allow(dead_code)] // <5> +fn handle_signals(sig: i32) { + register_signal_handler(); + + unsafe { // <6> + SHUT_DOWN = match sig { // <7> + SIGHUP => false, // <7> + SIGALRM => false, // <7> + SIGTERM => true, // <7> + SIGQUIT => true, // <7> + _ => false, // <7> + }; + } +} + +fn main() { + + register_signal_handler(); + let delay = time::Duration::from_secs(1); + + for i in 1_usize.. { // <7> + unsafe { // <7> + if SHUT_DOWN { + println!(); // only print a newline character + return; + } + } + + sleep(delay); + print!("{} ", i); + + if i > 10 { + unsafe { + libc::raise(SIGTERM); + } + } + } +}
\ No newline at end of file diff --git a/meap/meap-code/ch10/ch10-callstack/Cargo.toml b/meap/meap-code/ch10/ch10-callstack/Cargo.toml new file mode 100644 index 0000000..af00325 --- /dev/null +++ b/meap/meap-code/ch10/ch10-callstack/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "ch10-callstack" +version = "0.1.0" +authors = ["Tim McNamara <code@timmcnamara.co.nz>"] + +[dependencies] diff --git a/meap/meap-code/ch10/ch10-callstack/src/main.rs b/meap/meap-code/ch10/ch10-callstack/src/main.rs new file mode 100644 index 0000000..cbb56e3 --- /dev/null +++ b/meap/meap-code/ch10/ch10-callstack/src/main.rs @@ -0,0 +1,21 @@ +fn print_depth(depth:usize) { + for _ in 0..depth { + print!("#"); + } + println!(""); +} + +fn dive(depth: usize, max_depth: usize) { + print_depth(depth); + if depth >= max_depth { + return; + + } else { + dive(depth+1, max_depth); + } + print_depth(depth); +} + +fn main() { + dive(0, 5); +}
\ No newline at end of file diff --git a/meap/meap-code/ch10/ch10-handle/Cargo.toml b/meap/meap-code/ch10/ch10-handle/Cargo.toml new file mode 100644 index 0000000..95fa6c0 --- /dev/null +++ b/meap/meap-code/ch10/ch10-handle/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "ch10-handle" +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-handle/src/main.rs b/meap/meap-code/ch10/ch10-handle/src/main.rs new file mode 100644 index 0000000..d40e329 --- /dev/null +++ b/meap/meap-code/ch10/ch10-handle/src/main.rs @@ -0,0 +1,48 @@ +extern crate libc; // 0.2.42 + +use std::time::{Duration}; +use std::thread::{sleep}; +use libc::{signal,raise}; +use libc::{SIG_DFL, SIG_IGN, SIGTERM, SIGHUP}; + +type handler_ptr = extern "C" fn(i32) -> (); + +static mut ABORT: bool = false; + +#[inline(never)] +extern "C" fn handle_signals(sig: i32) { // rustc will warn that that this code is never run + let handle_signals_ptr: handler_ptr = handle_signals; + unsafe { // set the signal handler again, to prevent it resetting to SIG_DFL + signal(SIGTERM, std::mem::transmute(handle_signals_ptr)); + } + + let should_abort = match sig { + SIGTERM => true, + SIGHUP => false, + _ => false, + }; + + unsafe { // make a quick update here, and defer the real work to somewhere else + ABORT = should_abort; + } +} + +fn main() { + let delay = Duration::from_secs(1); + + // "main loop" + for i in 1..=60 { + unsafe { // at every step, check to see if a signal has been sent + if ABORT { + break; + } + } + + sleep(delay); + println!(". {}", i); + + if i > 2 { + unsafe { raise(SIGTERM); } + } + } +}
\ No newline at end of file diff --git a/meap/meap-code/ch10/ch10-handler/Cargo.toml b/meap/meap-code/ch10/ch10-handler/Cargo.toml new file mode 100644 index 0000000..7c8ed67 --- /dev/null +++ b/meap/meap-code/ch10/ch10-handler/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "ch10-handler" +version = "0.1.0" +authors = ["Tim McNamara <code@timmcnamara.co.nz>"] + +[dependencies] +libc = "0.2" diff --git a/meap/meap-code/ch10/ch10-handler/src/main.rs b/meap/meap-code/ch10/ch10-handler/src/main.rs new file mode 100644 index 0000000..088c9e6 --- /dev/null +++ b/meap/meap-code/ch10/ch10-handler/src/main.rs @@ -0,0 +1,58 @@ +#![cfg(not(windows))] + +extern crate libc; + +use std::mem; +use std::time; +use std::thread::{sleep}; +use libc::{SIGTERM, SIGALRM, SIGHUP, SIGQUIT}; + +static mut SHUT_DOWN: bool = false; + +#[inline] +fn register_signal_handler() { + let fn_ptr: fn(i32) -> () = handle_signals; // <1> hardcoding for simplicity + + unsafe { + let fn_ptr_as_usize: usize = mem::transmute(fn_ptr); // <2> + libc::signal(SIGTERM, fn_ptr_as_usize); // <3> + } +} + +#[allow(dead_code)] // <4> +fn handle_signals(sig: i32) { + register_signal_handler(); + + unsafe { // <4> + SHUT_DOWN = match sig { // <5> + SIGALRM => false, // <5> + SIGHUP => false, // <5> + SIGTERM => true, // <5> + SIGQUIT => true, // <5> + _ => false, // <5> + }; + } +} + +fn main() { + register_signal_handler(); + let delay = time::Duration::from_secs(1); + + for i in 1.. { // <6> + unsafe { // <6> + if SHUT_DOWN { + println!(); // only print a newline character + return; + } + } + + sleep(delay); + print!("."); + + if i > 3 { + unsafe { + libc::raise(SIGTERM); + } + } + } +}
\ No newline at end of file diff --git a/meap/meap-code/ch10/ch10-ignore/Cargo.toml b/meap/meap-code/ch10/ch10-ignore/Cargo.toml new file mode 100644 index 0000000..0184c84 --- /dev/null +++ b/meap/meap-code/ch10/ch10-ignore/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "ch10-ignore" +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-ignore/src/main.rs b/meap/meap-code/ch10/ch10-ignore/src/main.rs new file mode 100644 index 0000000..9f68362 --- /dev/null +++ b/meap/meap-code/ch10/ch10-ignore/src/main.rs @@ -0,0 +1,18 @@ +extern crate libc; // 0.2.42 + +use libc::{signal,raise}; +use libc::{SIG_DFL, SIG_IGN, SIGTERM}; + +fn main() { + unsafe { + signal(SIGTERM, SIG_IGN); + raise(SIGTERM); + } + println!("ok"); + + unsafe { + signal(SIGTERM, SIG_DFL); + raise(SIGTERM); + } + println!("not ok"); +}
\ No newline at end of file diff --git a/meap/meap-code/ch10/ch10-sixty/Cargo.toml b/meap/meap-code/ch10/ch10-sixty/Cargo.toml new file mode 100644 index 0000000..a0ad51e --- /dev/null +++ b/meap/meap-code/ch10/ch10-sixty/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "ch10-sixty" +version = "0.1.0" +authors = ["Tim McNamara <code@timmcnamara.co.nz>"] + +[dependencies] diff --git a/meap/meap-code/ch10/ch10-sixty/src/main.rs b/meap/meap-code/ch10/ch10-sixty/src/main.rs new file mode 100644 index 0000000..74ffa90 --- /dev/null +++ b/meap/meap-code/ch10/ch10-sixty/src/main.rs @@ -0,0 +1,15 @@ +use std::time; +use std::process; +use std::thread::sleep; + +fn main() { + let delay = time::Duration::from_secs(1); + + let pid = process::id(); + println!("{}", pid); + + for i in 1..=60 { + sleep(delay); + println!(". {}", i); + } +} 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 <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 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::<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!") +} |