// Copyright (c) 2023 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
// Use of this source is governed by Apache-2.0 License that can be found
// in the LICENSE file.

//! From `sys/signalvar.h`
//! Kernel signal definitions and data structures.

use crate::{
    osigset_t, sighandler_t, sigmask, sigset_t, SIGCONT, SIGKILL, SIGSTOP, SIGTSTP, SIGTTIN,
    SIGTTOU, _SIG_BIT, _SIG_WORD, _SIG_WORDS,
};

/// No zombies if child dies
pub const PS_NOCLDWAIT: i32 = 0x0001;
/// No SIGCHLD when children stop.
pub const PS_NOCLDSTOP: i32 = 0x0002;
/// The SIGCHLD handler is SIG_IGN.
pub const PS_CLDSIGIGN: i32 = 0x0004;

/// additional signal action values, used only temporarily/internally
pub const SIG_CATCH: sighandler_t = 2;
// #define SIG_HOLD        ((__sighandler_t *)3) See signal.h

/// sigset_t manipulation functions.
pub fn SIGADDSET(set: &mut sigset_t, signo: i32) {
    set.bits[_SIG_WORD(signo)] |= _SIG_BIT(signo);
}

pub fn SIGDELSET(set: &mut sigset_t, signo: i32) {
    set.bits[_SIG_WORD(signo)] &= !_SIG_BIT(signo);
}

pub fn SIGEMPTYSET(set: &mut sigset_t) {
    for i in 0.._SIG_WORDS {
        set.bits[i] = 0;
    }
}

pub fn SIGFILLSET(set: &mut sigset_t) {
    for i in 0.._SIG_WORDS {
        set.bits[i] = !0;
    }
}

pub const fn SIGISMEMBER(set: &sigset_t, signo: i32) -> bool {
    set.bits[_SIG_WORD(signo)] & _SIG_BIT(signo) != 0
}

pub const fn SIGISEMPTY(set: &sigset_t) -> bool {
    __sigisempty(&(set))
}

pub const fn SIGNOTEMPTY(set: &sigset_t) -> bool {
    !SIGISEMPTY(set)
}

pub const fn SIGSETEQ(set1: &sigset_t, set2: &sigset_t) -> bool {
    __sigseteq(&(set1), &(set2))
}

pub const fn SIGSETNEQ(set1: &sigset_t, set2: &sigset_t) -> bool {
    !SIGSETEQ(set1, set2)
}

pub fn SIGSETOR(set1: &mut sigset_t, set2: &sigset_t) {
    for i in 0.._SIG_WORDS {
        set1.bits[i] = set2.bits[i];
    }
}

pub fn SIGSETAND(set1: &mut sigset_t, set2: &sigset_t) {
    for i in 0.._SIG_WORDS {
        set1.bits[i] &= set2.bits[i];
    }
}

pub fn SIGSETNAND(set1: &mut sigset_t, set2: &sigset_t) {
    for i in 0.._SIG_WORDS {
        set1.bits[i] &= !set2.bits[i];
    }
}

pub fn SIGSETLO(set1: &mut sigset_t, set2: &sigset_t) {
    set1.bits[0] = set2.bits[0];
}
pub fn SIGSETOLD(set: &mut sigset_t, oset: osigset_t) {
    set.bits[0] = oset;
}

pub fn SIG_CANTMASK(set: &mut sigset_t) {
    SIGDELSET(set, SIGKILL);
    SIGDELSET(set, SIGSTOP);
}

pub fn SIG_STOPSIGMASK(set: &mut sigset_t) {
    SIGDELSET(set, SIGSTOP);
    SIGDELSET(set, SIGTSTP);
    SIGDELSET(set, SIGTTIN);
    SIGDELSET(set, SIGTTOU);
}

pub fn SIG_CONTSIGMASK(set: &mut sigset_t) {
    SIGDELSET(set, SIGCONT);
}

pub const SIGCANTMASK: i32 = sigmask(SIGKILL) | sigmask(SIGSTOP);

pub fn SIG2OSIG(sig: &sigset_t, osig: &mut osigset_t) {
    *osig = sig.bits[0];
}

pub fn OSIG2SIG(osig: osigset_t, sig: &mut sigset_t) {
    SIGEMPTYSET(sig);
    sig.bits[0] = osig;
}

const fn __sigisempty(set: &sigset_t) -> bool {
    let mut i = 0;
    while i < _SIG_WORDS {
        if set.bits[i] != 0 {
            return false;
        }
        i += 1;
    }
    return true;
}

const fn __sigseteq(set1: &sigset_t, set2: &sigset_t) -> bool {
    let mut i = 0;
    while i < _SIG_WORDS {
        if set1.bits[i] != set2.bits[i] {
            return false;
        }
        i += 1;
    }
    return true;
}

/// bits for ksi_flags
/// Generated by trap.
pub const KSI_TRAP: i32 = 0x01;
/// Externally managed ksi.
pub const KSI_EXT: i32 = 0x02;
/// Directly insert ksi, not the copy
pub const KSI_INS: i32 = 0x04;
/// Generated by sigqueue, might ret EAGAIN.
pub const KSI_SIGQ: i32 = 0x08;
/// Insert into head, not tail.
pub const KSI_HEAD: i32 = 0x10;
/// Generated by ptrace.
pub const KSI_PTRACE: i32 = 0x20;
pub const KSI_COPYMASK: i32 = KSI_TRAP | KSI_SIGQ | KSI_PTRACE;

/// Flags for ksi_flags
pub const SQ_INIT: i32 = 0x01;

/// Fast_sigblock
pub const SIGFASTBLOCK_SETPTR: i32 = 1;
pub const SIGFASTBLOCK_UNBLOCK: i32 = 2;
pub const SIGFASTBLOCK_UNSETPTR: i32 = 3;

pub const SIGFASTBLOCK_PEND: i32 = 0x1;
pub const SIGFASTBLOCK_FLAGS: i32 = 0xf;
pub const SIGFASTBLOCK_INC: i32 = 0x10;

/// Flags for kern_sigprocmask().
pub const SIGPROCMASK_OLD: i32 = 0x0001;
pub const SIGPROCMASK_PROC_LOCKED: i32 = 0x0002;
pub const SIGPROCMASK_PS_LOCKED: i32 = 0x0004;
pub const SIGPROCMASK_FASTBLK: i32 = 0x0008;

/*
 * Modes for sigdeferstop().  Manages behaviour of
 * thread_suspend_check() in the region delimited by
 * sigdeferstop()/sigallowstop().  Must be restored to
 * SIGDEFERSTOP_OFF before returning to userspace.
 */
/// continue doing whatever is done now
pub const SIGDEFERSTOP_NOP: i32 = 0;
/// stop ignoring STOPs
pub const SIGDEFERSTOP_OFF: i32 = 1;
/// silently ignore STOPs
pub const SIGDEFERSTOP_SILENT: i32 = 2;
/// ignore STOPs, return EINTR
pub const SIGDEFERSTOP_EINTR: i32 = 3;
/// ignore STOPs, return ERESTART
pub const SIGDEFERSTOP_ERESTART: i32 = 4;
