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::<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!")
+}
-- 
cgit v1.2.3