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/src/main.rs | 105 ++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 meap/meap-code/ch10/ch10-sjlj/src/main.rs (limited to 'meap/meap-code/ch10/ch10-sjlj/src') 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