diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs
index 2ffd3031d77c0666c84be158e1039fa337fbfbec..e2beea9cef8cb793268ff347f903623ce5ba577c 100644
--- a/redox-rt/src/signal.rs
+++ b/redox-rt/src/signal.rs
@@ -51,7 +51,15 @@ unsafe fn inner(stack: &mut SigStack) {
     // asm counts from 0
     stack.sig_num += 1;
 
-    let sigaction = SIGACTIONS.lock()[stack.sig_num];
+    let sigaction = {
+        let mut guard = SIGACTIONS.lock();
+        let action = guard[stack.sig_num];
+        if action.flags.contains(SigactionFlags::RESETHAND) {
+            // TODO: other things that must be set
+            guard[stack.sig_num].kind = SigactionKind::Default;
+        }
+        action
+    };
 
     let handler = match sigaction.kind {
         SigactionKind::Ignore => unreachable!(),
@@ -62,16 +70,73 @@ unsafe fn inner(stack: &mut SigStack) {
         SigactionKind::Handled { handler } => handler,
     };
 
+    let mut sigmask_inside = sigaction.mask;
+    if !sigaction.flags.contains(SigactionFlags::NODEFER) {
+        sigmask_inside &= !sig_bit(stack.sig_num);
+    }
+
+    let os = &Tcb::current().unwrap().os_specific;
+
+    // Set sigmask to sa_mask and unmark the signal as pending.
+    let lo = os.control.word[0].load(Ordering::Relaxed) >> 32;
+    let hi = os.control.word[1].load(Ordering::Relaxed) >> 32;
+    let prev_sigmask = lo | (hi << 32);
+
+    let sig_group = stack.sig_num / 32;
+
+    let prev_w0 = os.control.word[0].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| {
+        prev &= 0xffff_ffff;
+        if sig_group == 0 {
+            prev &= !sig_bit(stack.sig_num);
+        }
+        prev |= (sigmask_inside & 0xffff_ffff) << 32;
+        Some(prev)
+    }).unwrap();
+    let prev_w1 = os.control.word[1].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| {
+        prev &= 0xffff_ffff;
+        if sig_group == 1 {
+            prev &= !sig_bit(stack.sig_num);
+        }
+        prev |= (sigmask_inside >> 32) << 32;
+        Some(prev)
+    }).unwrap();
+
+    // TODO: If sa_mask caused signals to be unblocked, deliver one or all of those first?
+
     // Re-enable signals again.
-    let control_flags = &Tcb::current().unwrap().os_specific.control.control_flags;
+    let control_flags = &os.control.control_flags;
     control_flags.store(control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release);
     core::sync::atomic::compiler_fence(Ordering::Acquire);
 
+    // Call handler, either sa_handler or sa_siginfo depending on flag.
     if sigaction.flags.contains(SigactionFlags::SIGINFO) && let Some(sigaction) = handler.sigaction {
         sigaction(stack.sig_num as c_int, core::ptr::null_mut(), core::ptr::null_mut());
     } else if let Some(handler) = handler.handler {
         handler(stack.sig_num as c_int);
     }
+
+    // Disable signals while we modify the sigmask again
+    control_flags.store(control_flags.load(Ordering::Relaxed) | SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release);
+    core::sync::atomic::compiler_fence(Ordering::Acquire);
+
+    // Update sigmask again.
+    let prev_w0 = os.control.word[0].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| {
+        prev &= 0xffff_ffff;
+        prev |= lo << 32;
+        Some(prev)
+    }).unwrap();
+    let prev_w1 = os.control.word[1].fetch_update(Ordering::Relaxed, Ordering::Relaxed, |mut prev| {
+        prev &= 0xffff_ffff;
+        prev |= hi << 32;
+        Some(prev)
+    }).unwrap();
+
+    // TODO: If resetting the sigmask caused signals to be unblocked, then should they be delivered
+    // here? And would it be possible to tail-call-optimize that?
+
+    // And re-enable them again
+    control_flags.store(control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release);
+    core::sync::atomic::compiler_fence(Ordering::Acquire);
 }
 #[cfg(not(target_arch = "x86"))]
 pub(crate) unsafe extern "C" fn inner_c(stack: usize) {