/* This file is part of Fennix Kernel. Fennix Kernel is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Fennix Kernel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Fennix Kernel. If not, see . */ #ifndef __FENNIX_KERNEL_SIGNAL_H__ #define __FENNIX_KERNEL_SIGNAL_H__ #include #include #include #include #include #include enum Signals : int { SIG_NULL = 0, /* Process abort signal. */ SIGABRT = 1, /* Alarm clock. */ SIGALRM = 2, /* Access to an undefined portion of a memory object. */ SIGBUS = 3, /* Child process terminated, stopped, or continued. */ SIGCHLD = 4, /* Continue executing, if stopped. */ SIGCONT = 5, /* Erroneous arithmetic operation. */ SIGFPE = 6, /* Hangup. */ SIGHUP = 7, /* Illegal instruction. */ SIGILL = 8, /* Terminal interrupt signal. */ SIGINT = 9, /* Kill (cannot be caught or ignored). */ SIGKILL = 10, /* Write on a pipe with no one to read it. */ SIGPIPE = 11, /* Terminal quit signal. */ SIGQUIT = 12, /* Invalid memory reference. */ SIGSEGV = 13, /* Stop executing (cannot be caught or ignored). */ SIGSTOP = 14, /* Termination signal. */ SIGTERM = 15, /* Terminal stop signal. */ SIGTSTP = 16, /* Background process attempting read. */ SIGTTIN = 17, /* Background process attempting write. */ SIGTTOU = 18, /* User-defined signal 1. */ SIGUSR1 = 19, /* User-defined signal 2. */ SIGUSR2 = 20, /* Pollable event. */ SIGPOLL = 21, /* Profiling timer expired. */ SIGPROF = 22, /* Bad system call. */ SIGSYS = 23, /* Trace/breakpoint trap. */ SIGTRAP = 24, /* High bandwidth data is available at a socket. */ SIGURG = 25, /* Virtual timer expired. */ SIGVTALRM = 26, /* CPU time limit exceeded. */ SIGXCPU = 27, /* File size limit exceeded. */ SIGXFSZ = 28, /** * Reserved * These are just to match Linux's signal numbers. */ SIGCOMP1 = 29, SIGCOMP2 = 30, SIGCOMP3 = 31, /* Real-time signals. */ SIGRTMIN = 32, SIGRT_1 = 33, SIGRT_2 = 34, SIGRT_3 = 35, SIGRT_4 = 36, SIGRT_5 = 37, SIGRT_6 = 38, SIGRT_7 = 39, SIGRT_8 = 40, SIGRT_9 = 41, SIGRT_10 = 42, SIGRT_11 = 43, SIGRT_12 = 44, SIGRT_13 = 45, SIGRT_14 = 46, SIGRT_15 = 47, SIGRT_16 = 48, SIGRT_17 = 49, SIGRT_18 = 50, SIGRT_19 = 51, SIGRT_20 = 52, SIGRT_21 = 53, SIGRT_22 = 54, SIGRT_23 = 55, SIGRT_24 = 56, SIGRT_25 = 57, SIGRT_26 = 58, SIGRT_27 = 59, SIGRT_28 = 60, SIGRT_29 = 61, SIGRT_30 = 62, SIGRT_31 = 63, SIGRTMAX = 64, /* Maximum signal number. */ SIGNAL_MAX = SIGRTMAX }; enum SignalDispositions { /** * Terminate the process. */ SIG_TERM, /** * Ignore the signal. */ SIG_IGN, /** * Dump core. */ SIG_CORE, /** * Stop the process. */ SIG_STOP, /** * Continue the process. */ SIG_CONT }; enum SignalActions { SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK }; enum SignalActionDisposition : long { SAD_ERR = -1, SAD_DFL = 0, SAD_IGN = 1, }; #define SA_NOCLDSTOP 1 #define SA_NOCLDWAIT 2 #define SA_SIGINFO 4 #define SA_RESTORER 0x04000000 #define SA_ONSTACK 0x08000000 #define SA_RESTART 0x10000000 #define SA_NODEFER 0x40000000 #define SA_RESETHAND 0x80000000 #define __SI_PAD_SIZE \ (128 - 2 * sizeof(int) - sizeof(long)) typedef unsigned long sigset_t; union sigval { int sival_int; void *sival_ptr; }; struct sched_param { int sched_priority; }; struct pthread_attr_t { uint64_t sig; size_t guard_sz; bool detach; sched_param sched; }; struct sigevent { int sigev_notify; int sigev_signo; union sigval sigev_value; void (*sigev_notify_function)(union sigval); pthread_attr_t *sigev_notify_attributes; }; typedef struct { int si_signo; int si_errno; int si_code; union { char __pad[__SI_PAD_SIZE]; struct { union { struct { pid_t si_pid; uid_t si_uid; } __piduid; struct { int si_timerid; int si_overrun; } __timer; } __first; union { union sigval si_value; struct { int si_status; clock_t si_utime, si_stime; } __sigchld; } __second; } __si_common; struct { void *si_addr; short si_addr_lsb; union { struct { void *si_lower; void *si_upper; } __addr_bnd; unsigned si_pkey; } __first; } __sigfault; struct { long si_band; int si_fd; } __sigpoll; struct { void *si_call_addr; int si_syscall; unsigned si_arch; } __sigsys; } __si_fields; } siginfo_t; struct SignalAction { union { void (*Handler)(int); void (*Action)(int, siginfo_t *, void *); sigset_t Disposition; } sa_handler; std::bitset<64> Mask; unsigned long Flags; void (*Restorer)(void); }; namespace Tasking { class Signal { private: struct SignalInfo { int sig = SIG_NULL; union sigval val { 0 }; pid_t tid = -1; }; struct StackInfo { #ifdef a64 CPU::x64::FXState fx; CPU::x64::SchedulerFrame tf; uintptr_t GSBase, FSBase, ShadowGSBase; #else CPU::x32::FXState fx; CPU::x32::SchedulerFrame tf; uintptr_t GSBase, FSBase; #endif sigset_t SignalMask; int Compatibility; #ifdef DEBUG // For debugging purposes char dbg[6] = {'S', 'I', 'G', 'N', 'A', 'L'}; #endif } __aligned(16) __packed; NewLock(SignalLock); void *ctx; Signals LastSignal = SIG_NULL; // Signal trampoline void *TrampAddr = nullptr; size_t TrampSz = 0; std::list Queue; SignalAction sa[64 + 1]{}; // std::bitset GlobalMask; // SignalDispositions Disposition[SIGNAL_MAX]; std::list Watchers; std::unordered_map Disposition = { {SIGHUP, SIG_TERM}, {SIGINT, SIG_TERM}, {SIGQUIT, SIG_TERM}, {SIGILL, SIG_CORE}, {SIGTRAP, SIG_CORE}, {SIGABRT, SIG_CORE}, {SIGBUS, SIG_CORE}, {SIGFPE, SIG_CORE}, {SIGKILL, SIG_TERM}, {SIGUSR1, SIG_TERM}, {SIGSEGV, SIG_CORE}, {SIGUSR2, SIG_TERM}, {SIGPIPE, SIG_TERM}, {SIGALRM, SIG_TERM}, {SIGTERM, SIG_TERM}, {SIGCOMP1, SIG_IGN}, {SIGCHLD, SIG_IGN}, {SIGCONT, SIG_CONT}, {SIGSTOP, SIG_STOP}, {SIGTSTP, SIG_STOP}, {SIGTTIN, SIG_STOP}, {SIGTTOU, SIG_STOP}, {SIGURG, SIG_IGN}, {SIGXCPU, SIG_CORE}, {SIGXFSZ, SIG_CORE}, {SIGVTALRM, SIG_TERM}, {SIGPROF, SIG_TERM}, {SIGCOMP2, SIG_IGN}, {SIGPOLL, SIG_TERM}, {SIGCOMP3, SIG_IGN}, {SIGSYS, SIG_CORE}, {SIGRTMIN, SIG_IGN}, {SIGRT_1, SIG_IGN}, {SIGRT_2, SIG_IGN}, {SIGRT_3, SIG_IGN}, {SIGRT_4, SIG_IGN}, {SIGRT_5, SIG_IGN}, {SIGRT_6, SIG_IGN}, {SIGRT_7, SIG_IGN}, {SIGRT_8, SIG_IGN}, {SIGRT_9, SIG_IGN}, {SIGRT_10, SIG_IGN}, {SIGRT_11, SIG_IGN}, {SIGRT_12, SIG_IGN}, {SIGRT_13, SIG_IGN}, {SIGRT_14, SIG_IGN}, {SIGRT_15, SIG_IGN}, {SIGRT_16, SIG_IGN}, {SIGRT_17, SIG_IGN}, {SIGRT_18, SIG_IGN}, {SIGRT_19, SIG_IGN}, {SIGRT_20, SIG_IGN}, {SIGRT_21, SIG_IGN}, {SIGRT_22, SIG_IGN}, {SIGRT_23, SIG_IGN}, {SIGRT_24, SIG_IGN}, {SIGRT_25, SIG_IGN}, {SIGRT_26, SIG_IGN}, {SIGRT_27, SIG_IGN}, {SIGRT_28, SIG_IGN}, {SIGRT_29, SIG_IGN}, {SIGRT_30, SIG_IGN}, {SIGRT_31, SIG_IGN}, {SIGRTMAX, SIG_IGN}}; bool LinuxSig(); int MakeExitCode(Signals sig); void InitTrampoline(); SignalInfo GetAvailableSignal(void *thread); public: void *GetContext() { return ctx; } Signals GetLastSignal() { return LastSignal; } int AddWatcher(Signal *who, Signals sig); int RemoveWatcher(Signal *who, Signals sig); int AddSignal(Signals sig, union sigval val = {0}, pid_t tid = -1); int RemoveSignal(Signals sig); bool HandleSignal(CPU::SchedulerFrame *tf, void *thread); void RestoreHandleSignal(SyscallsFrame *tf, void *thread); int SetAction(Signals sig, const SignalAction *act); int GetAction(Signals sig, SignalAction *act); /** * Send a signal to the process * * @param sig The signal to send * (compatibility specific) * @param val The value to send * @param tid The thread ID to send the signal to * * @return 0 on success, -errno on error */ int SendSignal(Signals sig, sigval val = {0}, pid_t tid = -1); int WaitAnySignal(); bool HasPendingSignal() { return !Queue.empty(); } /** * Wait for a signal * * @param sig The signal to wait for * @param val The value to wait for * * @return 0 on success, -errno on error */ int WaitSignal(Signals sig, union sigval *val); /** * Wait for a signal with a timeout * * @param sig The signal to wait for * @param val The value to wait for * @param timeout The timeout to wait for * * @return 0 on success, -errno on error */ int WaitSignalTimeout(Signals sig, union sigval *val, uint64_t timeout); Signal(void *ctx); ~Signal(); friend class ThreadSignal; }; class ThreadSignal { private: Signal &pSig; public: std::bitset<64> Mask = 0; sigset_t Block(sigset_t sig); sigset_t Unblock(sigset_t sig); sigset_t SetMask(sigset_t sig); sigset_t GetMask(); ThreadSignal(Signal &sig) : pSig(sig) {} }; } #endif // !__FENNIX_KERNEL_SIGNAL_H__