Rework signal handling code

This commit is contained in:
EnderIce2 2024-03-25 23:21:27 +02:00
parent 3b1bd58a36
commit 3d1ecc3db0
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
10 changed files with 1040 additions and 711 deletions

View File

@ -169,15 +169,15 @@ nsa bool UserModeExceptionHandler(CPU::ExceptionFrame *Frame)
return true; return true;
} }
proc->Signals->SendSignal(SIGSEGV, proc->Signals.SendSignal(SIGSEGV,
{Tasking::KILL_CRASH}); {Tasking::KILL_CRASH});
break; break;
} }
case CPU::x86::Debug: case CPU::x86::Debug:
case CPU::x86::Breakpoint: case CPU::x86::Breakpoint:
{ {
proc->Signals->SendSignal(SIGTRAP, proc->Signals.SendSignal(SIGTRAP,
{Tasking::KILL_CRASH}); {Tasking::KILL_CRASH});
break; break;
} }
case CPU::x86::DivideByZero: case CPU::x86::DivideByZero:
@ -186,21 +186,21 @@ nsa bool UserModeExceptionHandler(CPU::ExceptionFrame *Frame)
case CPU::x86::x87FloatingPoint: case CPU::x86::x87FloatingPoint:
case CPU::x86::SIMDFloatingPoint: case CPU::x86::SIMDFloatingPoint:
{ {
proc->Signals->SendSignal(SIGFPE, proc->Signals.SendSignal(SIGFPE,
{Tasking::KILL_CRASH}); {Tasking::KILL_CRASH});
break; break;
} }
case CPU::x86::InvalidOpcode: case CPU::x86::InvalidOpcode:
case CPU::x86::GeneralProtectionFault: case CPU::x86::GeneralProtectionFault:
{ {
proc->Signals->SendSignal(SIGILL, proc->Signals.SendSignal(SIGILL,
{Tasking::KILL_CRASH}); {Tasking::KILL_CRASH});
break; break;
} }
case CPU::x86::DeviceNotAvailable: case CPU::x86::DeviceNotAvailable:
{ {
proc->Signals->SendSignal(SIGBUS, proc->Signals.SendSignal(SIGBUS,
{Tasking::KILL_CRASH}); {Tasking::KILL_CRASH});
break; break;
} }
case CPU::x86::NonMaskableInterrupt: case CPU::x86::NonMaskableInterrupt:

View File

@ -18,171 +18,121 @@
#ifndef __FENNIX_KERNEL_SIGNAL_H__ #ifndef __FENNIX_KERNEL_SIGNAL_H__
#define __FENNIX_KERNEL_SIGNAL_H__ #define __FENNIX_KERNEL_SIGNAL_H__
#include <unordered_map>
#include <syscalls.hpp> #include <syscalls.hpp>
#include <lock.hpp> #include <lock.hpp>
#include <types.h> #include <types.h>
#include <bitset>
#include <list> #include <list>
#include <syscall/linux/signals.hpp>
enum Signals : int enum Signals : int
{ {
SIG_NULL = 0, SIG_NULL = 0,
/* Process abort signal. */
/** SIGABRT = 1,
* Process abort signal. /* Alarm clock. */
*/ SIGALRM = 2,
SIGABRT, /* Access to an undefined portion of a memory object. */
SIGBUS = 3,
/** /* Child process terminated, stopped, or continued. */
* Alarm clock. SIGCHLD = 4,
*/ /* Continue executing, if stopped. */
SIGALRM, SIGCONT = 5,
/* Erroneous arithmetic operation. */
/** SIGFPE = 6,
* Access to an undefined portion of a memory object. /* Hangup. */
*/ SIGHUP = 7,
SIGBUS, /* Illegal instruction. */
SIGILL = 8,
/** /* Terminal interrupt signal. */
* Child process terminated, stopped, or continued. SIGINT = 9,
*/ /* Kill (cannot be caught or ignored). */
SIGCHLD, SIGKILL = 10,
/* Write on a pipe with no one to read it. */
/** SIGPIPE = 11,
* Continue executing, if stopped. /* Terminal quit signal. */
*/ SIGQUIT = 12,
SIGCONT, /* Invalid memory reference. */
SIGSEGV = 13,
/** /* Stop executing (cannot be caught or ignored). */
* Erroneous arithmetic operation. SIGSTOP = 14,
*/ /* Termination signal. */
SIGFPE, SIGTERM = 15,
/* Terminal stop signal. */
/** SIGTSTP = 16,
* Hangup. /* Background process attempting read. */
*/ SIGTTIN = 17,
SIGHUP, /* Background process attempting write. */
SIGTTOU = 18,
/** /* User-defined signal 1. */
* Illegal instruction. SIGUSR1 = 19,
*/ /* User-defined signal 2. */
SIGILL, SIGUSR2 = 20,
/* Pollable event. */
/** SIGPOLL = 21,
* Terminal interrupt signal. /* Profiling timer expired. */
*/ SIGPROF = 22,
SIGINT, /* Bad system call. */
SIGSYS = 23,
/** /* Trace/breakpoint trap. */
* Kill (cannot be caught or ignored). SIGTRAP = 24,
*/ /* High bandwidth data is available at a socket. */
SIGKILL, SIGURG = 25,
/* Virtual timer expired. */
/** SIGVTALRM = 26,
* Write on a pipe with no one to read it. /* CPU time limit exceeded. */
*/ SIGXCPU = 27,
SIGPIPE, /* File size limit exceeded. */
SIGXFSZ = 28,
/**
* Terminal quit signal.
*/
SIGQUIT,
/**
* Invalid memory reference.
*/
SIGSEGV,
/**
* Stop executing (cannot be caught or ignored).
*/
SIGSTOP,
/**
* Termination signal.
*/
SIGTERM,
/**
* Terminal stop signal.
*/
SIGTSTP,
/**
* Background process attempting read.
*/
SIGTTIN,
/**
* Background process attempting write.
*/
SIGTTOU,
/**
* User-defined signal 1.
*/
SIGUSR1,
/**
* User-defined signal 2.
*/
SIGUSR2,
/**
* Pollable event.
*/
SIGPOLL,
/**
* Profiling timer expired.
*/
SIGPROF,
/**
* Bad system call.
*/
SIGSYS,
/**
* Trace/breakpoint trap.
*/
SIGTRAP,
/**
* High bandwidth data is available at a socket.
*/
SIGURG,
/**
* Virtual timer expired.
*/
SIGVTALRM,
/**
* CPU time limit exceeded.
*/
SIGXCPU,
/**
* File size limit exceeded.
*/
SIGXFSZ,
/** /**
* Reserved * Reserved
*
* These are just to match Linux's signal numbers. * These are just to match Linux's signal numbers.
*/ */
SIGRSV1, SIGCOMP1 = 29,
SIGRSV2, SIGCOMP2 = 30,
SIGCOMP3 = 31,
/** /* Real-time signals. */
* Maximum signal number. SIGRTMIN = 32,
*/ SIGRT_1 = 33,
SIGNAL_MAX 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 SignalDisposition enum SignalDispositions
{ {
/** /**
* Terminate the process. * Terminate the process.
@ -210,21 +160,28 @@ enum SignalDisposition
SIG_CONT SIG_CONT
}; };
enum SignalAction enum SignalActions
{ {
SIG_BLOCK, SIG_BLOCK,
SIG_UNBLOCK, SIG_UNBLOCK,
SIG_SETMASK SIG_SETMASK
}; };
enum SignalActionDisposition : long
{
SAD_ERR = -1,
SAD_DFL = 0,
SAD_IGN = 1,
};
#define SA_NOCLDSTOP 1 #define SA_NOCLDSTOP 1
#define SA_NOCLDWAIT 2 #define SA_NOCLDWAIT 2
#define SA_SIGINFO 4 #define SA_SIGINFO 4
#define SA_RESTORER 0x04000000
#define SA_ONSTACK 0x08000000 #define SA_ONSTACK 0x08000000
#define SA_RESTART 0x10000000 #define SA_RESTART 0x10000000
#define SA_NODEFER 0x40000000 #define SA_NODEFER 0x40000000
#define SA_RESETHAND 0x80000000 #define SA_RESETHAND 0x80000000
#define SA_RESTORER 0x04000000
#define __SI_PAD_SIZE \ #define __SI_PAD_SIZE \
(128 - 2 * sizeof(int) - sizeof(long)) (128 - 2 * sizeof(int) - sizeof(long))
@ -323,41 +280,32 @@ typedef struct
} __si_fields; } __si_fields;
} siginfo_t; } siginfo_t;
struct sigaction struct SignalAction
{ {
union union
{ {
void (*sa_handler)(int); void (*Handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *); void (*Action)(int, siginfo_t *, void *);
} __sa_handler; sigset_t Disposition;
sigset_t sa_mask; } sa_handler;
int sa_flags; std::bitset<64> Mask;
void (*sa_restorer)(void); unsigned long Flags;
void (*Restorer)(void);
}; };
namespace Tasking namespace Tasking
{ {
__no_sanitize("shift") inline __always_inline
sigset_t
ToFlag(sigset_t sig)
{
return 1 << (sig - 1);
}
inline __always_inline
sigset_t
ToSig(sigset_t flag)
{
return __builtin_ctzl(flag) + 1;
}
class Signal class Signal
{ {
private: private:
struct SignalInfo struct SignalInfo
{ {
int sig; int sig = SIG_NULL;
union sigval val; union sigval val
{
0
};
pid_t tid = -1;
}; };
struct StackInfo struct StackInfo
@ -388,109 +336,97 @@ namespace Tasking
void *TrampAddr = nullptr; void *TrampAddr = nullptr;
size_t TrampSz = 0; size_t TrampSz = 0;
std::list<SignalInfo> SignalQueue; std::list<SignalInfo> Queue;
std::atomic<sigset_t> SignalMask = 0; SignalAction sa[64 + 1]{};
sigaction SignalAction[SIGNAL_MAX]{}; // std::bitset<SIGNAL_MAX> GlobalMask;
SignalDisposition sigDisp[SIGNAL_MAX]; // SignalDispositions Disposition[SIGNAL_MAX];
std::list<SignalInfo> Watchers; std::list<SignalInfo> Watchers;
std::unordered_map<Signals, SignalDispositions> 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(); bool LinuxSig();
int MakeExitCode(Signals sig);
int ConvertToLinuxIfNecessary(int sig);
int ConvertToNativeIfNecessary(int sig);
sigset_t ConvertSigsetToLinuxIfNecessary(sigset_t sig);
sigset_t ConvertSigsetToNativeIfNecessary(sigset_t sig);
int MakeExitCode(int sig);
void InitTrampoline(); void InitTrampoline();
SignalInfo GetAvailableSignal(void *thread);
const sigset_t nMasks = ToFlag(SIGKILL) |
ToFlag(SIGSTOP) |
ToFlag(SIGCONT) |
ToFlag(SIGSEGV) |
ToFlag(SIGBUS) |
ToFlag(SIGILL) |
ToFlag(SIGFPE);
const sigset_t lMasks = ToFlag(linux_SIGKILL) |
ToFlag(linux_SIGSTOP) |
ToFlag(linux_SIGCONT) |
ToFlag(linux_SIGSEGV) |
ToFlag(linux_SIGBUS) |
ToFlag(linux_SIGILL) |
ToFlag(linux_SIGFPE);
void RemoveUnmaskable(sigset_t *sig)
{
if (LinuxSig())
*sig &= ~lMasks;
else
*sig &= ~nMasks;
}
bool CanHaveHandler(sigset_t sig)
{
switch (sig)
{
case SIGKILL:
case SIGSTOP:
case SIGCONT:
return false;
default:
return true;
}
}
public: public:
void *GetContext() { return ctx; } void *GetContext() { return ctx; }
Signals GetLastSignal() { return LastSignal; } Signals GetLastSignal() { return LastSignal; }
int AddWatcher(Signal *who, int sig); int AddWatcher(Signal *who, Signals sig);
int RemoveWatcher(Signal *who, int sig); int RemoveWatcher(Signal *who, Signals sig);
int AddSignal(int sig, union sigval val); int AddSignal(Signals sig, union sigval val = {0}, pid_t tid = -1);
int RemoveSignal(int sig); int RemoveSignal(Signals sig);
/** bool HandleSignal(CPU::TrapFrame *tf, void *thread);
* For scheduler use only void RestoreHandleSignal(SyscallsFrame *tf, void *thread);
* @return True if there is a signal to handle
*/
bool HandleSignal(CPU::TrapFrame *tf);
void RestoreHandleSignal(SyscallsFrame *tf);
/** int SetAction(Signals sig, const SignalAction *act);
* Mask a signal int GetAction(Signals sig, SignalAction *act);
*
* @param sig The signal to set
*
* @return Old mask
*/
sigset_t Block(sigset_t sig);
/**
* Unmask a signal
*
* @param sig The signal to set
*
* @return Old mask
*/
sigset_t Unblock(sigset_t sig);
/**
* Set the signal mask
*
* @param sig The signal to set
*
* @return Old mask
*/
sigset_t SetMask(sigset_t sig);
sigset_t GetMask() { return SignalMask.load(); }
int SetAction(int sig, const sigaction act);
int GetAction(int sig, sigaction *act);
/** /**
* Send a signal to the process * Send a signal to the process
@ -498,39 +434,56 @@ namespace Tasking
* @param sig The signal to send * @param sig The signal to send
* (compatibility specific) * (compatibility specific)
* @param val The value to send * @param val The value to send
* @param tid The thread ID to send the signal to
* *
* @return 0 on success, -errno on error * @return 0 on success, -errno on error
*/ */
int SendSignal(int sig, union sigval val = {0}); int SendSignal(Signals sig, sigval val = {0}, pid_t tid = -1);
int WaitAnySignal(); int WaitAnySignal();
bool HasPendingSignal(); bool HasPendingSignal() { return !Queue.empty(); }
/** /**
* Wait for a signal * Wait for a signal
* *
* @param sig The signal to wait for * @param sig The signal to wait for
* (compatibility specific)
* @param val The value to wait for * @param val The value to wait for
* *
* @return 0 on success, -errno on error * @return 0 on success, -errno on error
*/ */
int WaitSignal(int sig, union sigval *val); int WaitSignal(Signals sig, union sigval *val);
/** /**
* Wait for a signal with a timeout * Wait for a signal with a timeout
* *
* @param sig The signal to wait for * @param sig The signal to wait for
* (compatibility specific)
* @param val The value to wait for * @param val The value to wait for
* @param timeout The timeout to wait for * @param timeout The timeout to wait for
* *
* @return 0 on success, -errno on error * @return 0 on success, -errno on error
*/ */
int WaitSignalTimeout(int sig, union sigval *val, uint64_t timeout); int WaitSignalTimeout(Signals sig, union sigval *val, uint64_t timeout);
Signal(void *ctx); Signal(void *ctx);
~Signal(); ~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) {}
}; };
} }

View File

@ -170,6 +170,8 @@
#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2 #define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2
#define LINUX_REBOOT_CMD_KEXEC 0x45584543 #define LINUX_REBOOT_CMD_KEXEC 0x45584543
#define SA_IMMUTABLE 0x00800000
typedef long __kernel_old_time_t; typedef long __kernel_old_time_t;
typedef long __kernel_suseconds_t; typedef long __kernel_suseconds_t;
typedef int clockid_t; typedef int clockid_t;

View File

@ -20,6 +20,8 @@
#include <types.h> #include <types.h>
#define linux_NSIG 64
#define linux_SIGHUP 1 #define linux_SIGHUP 1
#define linux_SIGINT 2 #define linux_SIGINT 2
#define linux_SIGQUIT 3 #define linux_SIGQUIT 3
@ -53,4 +55,14 @@
#define linux_SIGSYS 31 #define linux_SIGSYS 31
#define linux_SIGUNUSED linux_SIGSYS #define linux_SIGUNUSED linux_SIGSYS
#define linux_SIGRTMIN 32
#define linux_SIGRTMAX linux_NSIG
struct k_sigaction
{
void (*handler)(int);
unsigned long flags;
void (*restorer)(void);
unsigned mask[2];
};
#endif // !__FENNIX_KERNEL_LINUX_SIGNALS_H__ #endif // !__FENNIX_KERNEL_LINUX_SIGNALS_H__

View File

@ -333,6 +333,9 @@ namespace Tasking
Memory::VirtualMemoryArea *vma; Memory::VirtualMemoryArea *vma;
Memory::StackGuard *Stack; Memory::StackGuard *Stack;
/* Signal */
ThreadSignal Signals;
/* CPU state */ /* CPU state */
#if defined(a64) #if defined(a64)
CPU::x64::TrapFrame Registers{}; CPU::x64::TrapFrame Registers{};
@ -361,6 +364,7 @@ namespace Tasking
{ {
int *set_child_tid{}; int *set_child_tid{};
int *clear_child_tid{}; int *clear_child_tid{};
pid_t tgid = 0;
} Linux{}; } Linux{};
int SendSignal(int sig); int SendSignal(int sig);
@ -437,6 +441,8 @@ namespace Tasking
uint16_t UserID = UINT16_MAX; uint16_t UserID = UINT16_MAX;
uint16_t GroupID = UINT16_MAX; uint16_t GroupID = UINT16_MAX;
} Real, Effective; } Real, Effective;
pid_t ProcessGroupID = 0;
pid_t SessionID = 0;
} Security{}; } Security{};
TaskInfo Info{}; TaskInfo Info{};
ThreadLocalStorage TLS{}; ThreadLocalStorage TLS{};
@ -457,7 +463,7 @@ namespace Tasking
Memory::ProgramBreak *ProgramBreak; Memory::ProgramBreak *ProgramBreak;
/* Other */ /* Other */
Signal *Signals; Signal Signals;
/* Threads & Children */ /* Threads & Children */
std::list<TCB *> Threads; std::list<TCB *> Threads;

View File

@ -39,13 +39,288 @@
using Tasking::PCB; using Tasking::PCB;
using Tasking::TCB; using Tasking::TCB;
static_assert(linux_SIGRTMIN == SIGRTMIN);
static_assert(linux_SIGRTMAX == SIGRTMAX);
struct SyscallData struct SyscallData
{ {
const char *Name; const char *Name;
void *Handler; void *Handler;
}; };
void linux_fork_return(void *tableAddr) #ifdef DEBUG
const char *lSigStr[] = {
"INVALID",
"SIGHUP",
"SIGINT",
"SIGQUIT",
"SIGILL",
"SIGTRAP",
"SIGABRT",
"SIGBUS",
"SIGFPE",
"SIGKILL",
"SIGUSR1",
"SIGSEGV",
"SIGUSR2",
"SIGPIPE",
"SIGALRM",
"SIGTERM",
"SIGSTKFLT",
"SIGCHLD",
"SIGCONT",
"SIGSTOP",
"SIGTSTP",
"SIGTTIN",
"SIGTTOU",
"SIGURG",
"SIGXCPU",
"SIGXFSZ",
"SIGVTALRM",
"SIGPROF",
"SIGWINCH",
"SIGPOLL",
"SIGPWR",
"SIGSYS",
"SIGRTMIN",
"SIGRT_1",
"SIGRT_2",
"SIGRT_3",
"SIGRT_4",
"SIGRT_5",
"SIGRT_6",
"SIGRT_7",
"SIGRT_8",
"SIGRT_9",
"SIGRT_10",
"SIGRT_11",
"SIGRT_12",
"SIGRT_13",
"SIGRT_14",
"SIGRT_15",
"SIGRT_16",
"SIGRT_17",
"SIGRT_18",
"SIGRT_19",
"SIGRT_20",
"SIGRT_21",
"SIGRT_22",
"SIGRT_23",
"SIGRT_24",
"SIGRT_25",
"SIGRT_26",
"SIGRT_27",
"SIGRT_28",
"SIGRT_29",
"SIGRT_30",
"SIGRT_31",
"SIGRTMAX",
};
#endif
const char *rlimitStr[] = {
"RLIMIT_CPU",
"RLIMIT_FSIZE",
"RLIMIT_DATA",
"RLIMIT_STACK",
"RLIMIT_CORE",
"RLIMIT_RSS",
"RLIMIT_NPROC",
"RLIMIT_NOFILE",
"RLIMIT_MEMLOCK",
"RLIMIT_AS",
"RLIMIT_LOCKS",
"RLIMIT_SIGPENDING",
"RLIMIT_MSGQUEUE",
"RLIMIT_NICE",
"RLIMIT_RTPRIO",
"RLIMIT_RTTIME",
"RLIMIT_NLIMITS",
};
static const struct
{
int linuxSignal;
Signals nativeSignal;
SignalDispositions nativeDisposition;
} signalMapping[] = {
{linux_SIGHUP, SIGHUP, SIG_TERM},
{linux_SIGINT, SIGINT, SIG_TERM},
{linux_SIGQUIT, SIGQUIT, SIG_TERM},
{linux_SIGILL, SIGILL, SIG_CORE},
{linux_SIGTRAP, SIGTRAP, SIG_CORE},
{linux_SIGABRT, SIGABRT, SIG_CORE},
{linux_SIGBUS, SIGBUS, SIG_CORE},
{linux_SIGFPE, SIGFPE, SIG_CORE},
{linux_SIGKILL, SIGKILL, SIG_TERM},
{linux_SIGUSR1, SIGUSR1, SIG_TERM},
{linux_SIGSEGV, SIGSEGV, SIG_CORE},
{linux_SIGUSR2, SIGUSR2, SIG_TERM},
{linux_SIGPIPE, SIGPIPE, SIG_TERM},
{linux_SIGALRM, SIGALRM, SIG_TERM},
{linux_SIGTERM, SIGTERM, SIG_TERM},
{linux_SIGSTKFLT, SIGCOMP1, SIG_IGN},
{linux_SIGCHLD, SIGCHLD, SIG_IGN},
{linux_SIGCONT, SIGCONT, SIG_CONT},
{linux_SIGSTOP, SIGSTOP, SIG_STOP},
{linux_SIGTSTP, SIGTSTP, SIG_STOP},
{linux_SIGTTIN, SIGTTIN, SIG_STOP},
{linux_SIGTTOU, SIGTTOU, SIG_STOP},
{linux_SIGURG, SIGURG, SIG_IGN},
{linux_SIGXCPU, SIGXCPU, SIG_CORE},
{linux_SIGXFSZ, SIGXFSZ, SIG_CORE},
{linux_SIGVTALRM, SIGVTALRM, SIG_TERM},
{linux_SIGPROF, SIGPROF, SIG_TERM},
{linux_SIGWINCH, SIGCOMP2, SIG_IGN},
{linux_SIGPOLL, SIGPOLL, SIG_TERM},
{linux_SIGPWR, SIGCOMP3, SIG_IGN},
{linux_SIGSYS, SIGSYS, SIG_CORE},
{linux_SIGRTMIN, SIGRTMIN, SIG_IGN},
{linux_SIGRTMIN + 1, SIGRT_1, SIG_IGN},
{linux_SIGRTMIN + 2, SIGRT_2, SIG_IGN},
{linux_SIGRTMIN + 3, SIGRT_3, SIG_IGN},
{linux_SIGRTMIN + 4, SIGRT_4, SIG_IGN},
{linux_SIGRTMIN + 5, SIGRT_5, SIG_IGN},
{linux_SIGRTMIN + 6, SIGRT_6, SIG_IGN},
{linux_SIGRTMIN + 7, SIGRT_7, SIG_IGN},
{linux_SIGRTMIN + 8, SIGRT_8, SIG_IGN},
{linux_SIGRTMIN + 9, SIGRT_9, SIG_IGN},
{linux_SIGRTMIN + 10, SIGRT_10, SIG_IGN},
{linux_SIGRTMIN + 11, SIGRT_11, SIG_IGN},
{linux_SIGRTMIN + 12, SIGRT_12, SIG_IGN},
{linux_SIGRTMIN + 13, SIGRT_13, SIG_IGN},
{linux_SIGRTMIN + 14, SIGRT_14, SIG_IGN},
{linux_SIGRTMIN + 15, SIGRT_15, SIG_IGN},
{linux_SIGRTMIN + 16, SIGRT_16, SIG_IGN},
{linux_SIGRTMIN + 17, SIGRT_17, SIG_IGN},
{linux_SIGRTMIN + 18, SIGRT_18, SIG_IGN},
{linux_SIGRTMIN + 19, SIGRT_19, SIG_IGN},
{linux_SIGRTMIN + 20, SIGRT_20, SIG_IGN},
{linux_SIGRTMIN + 21, SIGRT_21, SIG_IGN},
{linux_SIGRTMIN + 22, SIGRT_22, SIG_IGN},
{linux_SIGRTMIN + 23, SIGRT_23, SIG_IGN},
{linux_SIGRTMIN + 24, SIGRT_24, SIG_IGN},
{linux_SIGRTMIN + 25, SIGRT_25, SIG_IGN},
{linux_SIGRTMIN + 26, SIGRT_26, SIG_IGN},
{linux_SIGRTMIN + 27, SIGRT_27, SIG_IGN},
{linux_SIGRTMIN + 28, SIGRT_28, SIG_IGN},
{linux_SIGRTMIN + 29, SIGRT_29, SIG_IGN},
{linux_SIGRTMIN + 30, SIGRT_30, SIG_IGN},
{linux_SIGRTMIN + 31, SIGRT_31, SIG_IGN},
{linux_SIGRTMAX, SIGRTMAX, SIG_IGN}};
int ConvertSignalToLinux(Signals sig)
{
if (sig >= SIGRTMIN && sig <= SIGRTMAX)
return sig; /* We ignore for now */
foreach (auto &mapping in signalMapping)
{
if (mapping.nativeSignal == sig)
{
// debug("Converted \"%s\"(%d) to \"%s\"(%d)",
// sigStr[mapping.nativeSignal], sig,
// lSigStr[mapping.linuxSignal], mapping.linuxSignal);
return mapping.linuxSignal;
}
}
debug("Unknown signal %d", sig);
// assert(!"Unknown signal");
return SIG_NULL;
}
Signals ConvertSignalToNative(int sig)
{
if (sig >= linux_SIGRTMIN && sig <= linux_SIGRTMAX)
return (Signals)sig; /* We ignore for now */
foreach (auto &mapping in signalMapping)
{
if (mapping.linuxSignal == sig)
{
// debug("Converted \"%s\"(%d) to \"%s\"(%d)",
// lSigStr[mapping.linuxSignal], sig,
// sigStr[mapping.nativeSignal], mapping.nativeSignal);
return mapping.nativeSignal;
}
}
debug("Unknown signal %d", sig);
// assert(!"Unknown signal");
return SIG_NULL;
}
unsigned long ConvertMaskToNative(unsigned long mask)
{
unsigned long ret = 0;
for (int i = 0; i < 64; i++)
{
if (mask & (1ul << i))
{
int sig = ConvertSignalToNative(i + 1);
if (unlikely(sig == SIG_NULL))
continue;
ret |= 1ul << (sig - 1);
}
}
return ret;
// std::bitset<SIGNAL_MAX + 1> bitMask(mask);
// for (int i = 0; i < SIGNAL_MAX + 1; i++)
// {
// if (bitMask.test(i))
// ret |= 1 << (ConvertSignalToNative(i + 1) - 1);
// }
}
unsigned long ConvertMaskToLinux(unsigned long mask)
{
unsigned long ret = 0;
for (int i = 0; i < 64; i++)
{
if (mask & (1ul << i))
{
int sig = ConvertSignalToLinux((Signals)(i + 1));
if (unlikely(sig == SIG_NULL))
continue;
ret |= 1ul << (sig - 1);
}
}
return ret;
// std::bitset<linux_SIGUNUSED + 1> bitMask(mask);
// for (int i = 0; i < linux_SIGUNUSED + 1; i++)
// {
// if (bitMask.test(i))
// ret |= 1 << (ConvertSignalToLinux(i + 1) - 1);
// }
}
void SetSigActToNative(const k_sigaction *linux, SignalAction *native)
{
native->sa_handler.Handler = linux->handler;
native->Flags = linux->flags;
native->Restorer = linux->restorer;
unsigned long mask = ((unsigned long)linux->mask[1] << 32) | linux->mask[0];
native->Mask = std::bitset<64>(ConvertMaskToNative(mask));
debug("m0:%#lx m1:%#lx | n:%#lx", linux->mask[0], linux->mask[1], native->Mask);
}
void SetSigActToLinux(const SignalAction *native, k_sigaction *linux)
{
linux->handler = native->sa_handler.Handler;
linux->flags = native->Flags;
linux->restorer = native->Restorer;
unsigned long mask = native->Mask.to_ulong();
mask = ConvertMaskToLinux(mask);
linux->mask[0] = mask & 0xFFFFFFFF;
linux->mask[1] = (mask >> 32) & 0xFFFFFFFF;
debug("m0:%#lx m1:%#lx | n:%#lx", linux->mask[0], linux->mask[1], native->Mask);
}
void __LinuxForkReturn(void *tableAddr)
{ {
#if defined(a64) #if defined(a64)
asmv("movq %0, %%cr3" ::"r"(tableAddr)); /* Load process page table */ asmv("movq %0, %%cr3" ::"r"(tableAddr)); /* Load process page table */
@ -56,7 +331,7 @@ void linux_fork_return(void *tableAddr)
asmv("sti\n"); /* Enable interrupts */ asmv("sti\n"); /* Enable interrupts */
asmv("sysretq\n"); /* Return to rcx address in user mode */ asmv("sysretq\n"); /* Return to rcx address in user mode */
#elif defined(a32) #elif defined(a32)
#warning "linux_fork_return not implemented for i386" #warning "__LinuxForkReturn not implemented for i386"
#endif #endif
__builtin_unreachable(); __builtin_unreachable();
} }
@ -648,7 +923,7 @@ static int linux_dup2(SysFrm *, int oldfd, int newfd)
static int linux_pause(SysFrm *) static int linux_pause(SysFrm *)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
return pcb->Signals->WaitAnySignal(); return pcb->Signals.WaitAnySignal();
} }
/* https://man7.org/linux/man-pages/man2/nanosleep.2.html */ /* https://man7.org/linux/man-pages/man2/nanosleep.2.html */
@ -690,7 +965,7 @@ static int linux_nanosleep(SysFrm *,
while (time < sleepTime) while (time < sleepTime)
{ {
if (pcb->Signals->HasPendingSignal()) if (pcb->Signals.HasPendingSignal())
{ {
debug("sleep interrupted by signal"); debug("sleep interrupted by signal");
return -EINTR; return -EINTR;
@ -739,6 +1014,9 @@ static pid_t linux_fork(SysFrm *sf)
return -EAGAIN; return -EAGAIN;
} }
NewProcess->Security.ProcessGroupID = Parent->Security.ProcessGroupID;
NewProcess->Security.SessionID = Parent->Security.SessionID;
NewProcess->PageTable = Parent->PageTable->Fork(); NewProcess->PageTable = Parent->PageTable->Fork();
NewProcess->vma->Table = NewProcess->PageTable; NewProcess->vma->Table = NewProcess->PageTable;
NewProcess->vma->Fork(Parent->vma); NewProcess->vma->Fork(Parent->vma);
@ -773,7 +1051,7 @@ static pid_t linux_fork(SysFrm *sf)
NewThread->Security.IsCritical = Thread->Security.IsCritical; NewThread->Security.IsCritical = Thread->Security.IsCritical;
NewThread->Registers = Thread->Registers; NewThread->Registers = Thread->Registers;
#if defined(a64) #if defined(a64)
NewThread->Registers.rip = (uintptr_t)linux_fork_return; NewThread->Registers.rip = (uintptr_t)__LinuxForkReturn;
/* For sysretq */ /* For sysretq */
NewThread->Registers.rdi = (uintptr_t)NewProcess->PageTable; NewThread->Registers.rdi = (uintptr_t)NewProcess->PageTable;
NewThread->Registers.rcx = sf->ReturnAddress; NewThread->Registers.rcx = sf->ReturnAddress;
@ -789,7 +1067,7 @@ static pid_t linux_fork(SysFrm *sf)
#endif #endif
debug("ret addr: %#lx, stack: %#lx ip: %#lx", sf->ReturnAddress, debug("ret addr: %#lx, stack: %#lx ip: %#lx", sf->ReturnAddress,
sf->StackPointer, (uintptr_t)linux_fork_return); sf->StackPointer, (uintptr_t)__LinuxForkReturn);
debug("Forked thread \"%s\"(%d) to \"%s\"(%d)", debug("Forked thread \"%s\"(%d) to \"%s\"(%d)",
Thread->Name, Thread->ID, Thread->Name, Thread->ID,
NewThread->Name, NewThread->ID); NewThread->Name, NewThread->ID);
@ -1077,7 +1355,9 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus,
int ExitStatus = child->ExitCode.load(); int ExitStatus = child->ExitCode.load();
bool ProcessSignaled = true; bool ProcessSignaled = true;
bool CoreDumped = true; bool CoreDumped = true;
int TermSignal = child->Signals->GetLastSignal(); int TermSignal = child->Signals.GetLastSignal();
TermSignal = ConvertSignalToLinux((Signals)TermSignal);
assert(TermSignal != SIG_NULL);
debug("Process returned %d", ExitStatus); debug("Process returned %d", ExitStatus);
@ -1234,8 +1514,8 @@ static pid_t linux_wait4(SysFrm *, pid_t pid, int *wstatus,
/* https://man7.org/linux/man-pages/man2/kill.2.html */ /* https://man7.org/linux/man-pages/man2/kill.2.html */
static int linux_kill(SysFrm *, pid_t pid, int sig) static int linux_kill(SysFrm *, pid_t pid, int sig)
{ {
PCB *target = thisProcess->GetContext()->GetProcessByID(pid); PCB *pcb = thisProcess->GetContext()->GetProcessByID(pid);
if (!target) if (!pcb)
return -ESRCH; return -ESRCH;
/* TODO: Check permissions */ /* TODO: Check permissions */
@ -1245,8 +1525,21 @@ static int linux_kill(SysFrm *, pid_t pid, int sig)
if (pid == 0) if (pid == 0)
{ {
fixme("Sending signal %d to all processes", sig); bool found = false;
return -ENOSYS; Signals nSig = ConvertSignalToNative(sig);
assert(nSig != SIG_NULL);
foreach (auto proc in pcb->GetContext()->GetProcessList())
{
if (proc->Security.ProcessGroupID == thisProcess->Security.ProcessGroupID)
{
debug("Sending signal %s to %s(%d)", lSigStr[sig], proc->Name, proc->ID);
proc->SendSignal(nSig);
found = true;
}
}
if (!found)
return -ESRCH;
return 0;
} }
if (pid == -1) if (pid == -1)
@ -1261,7 +1554,9 @@ static int linux_kill(SysFrm *, pid_t pid, int sig)
return -ENOSYS; return -ENOSYS;
} }
return target->Signals->SendSignal(sig); Signals nSig = ConvertSignalToNative(sig);
assert(nSig != SIG_NULL);
return pcb->SendSignal(nSig);
} }
/* https://man7.org/linux/man-pages/man2/uname.2.html */ /* https://man7.org/linux/man-pages/man2/uname.2.html */
@ -1510,17 +1805,13 @@ static pid_t linux_getpgid(SysFrm *, pid_t pid)
{ {
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
if (pid == 0) if (pid == 0)
{ return pcb->Security.ProcessGroupID;
fixme("pid=0 is stub!");
return 0;
}
PCB *target = pcb->GetContext()->GetProcessByID(pid); PCB *target = pcb->GetContext()->GetProcessByID(pid);
if (!target) if (!target)
return -ESRCH; return -ESRCH;
stub; return target->Security.ProcessGroupID;
return 0;
} }
/* https://man7.org/linux/man-pages/man2/setpgid.2.html */ /* https://man7.org/linux/man-pages/man2/setpgid.2.html */
@ -1529,7 +1820,7 @@ static int linux_setpgid(SysFrm *, pid_t pid, pid_t pgid)
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
if (pid == 0) if (pid == 0)
{ {
fixme("pid=0 is stub!"); pcb->Security.ProcessGroupID = pgid;
return 0; return 0;
} }
@ -1537,10 +1828,13 @@ static int linux_setpgid(SysFrm *, pid_t pid, pid_t pgid)
if (!target) if (!target)
return -ESRCH; return -ESRCH;
if (pgid < 0) if (pgid == 0)
return -EINVAL; {
target->Security.ProcessGroupID = target->ID;
return 0;
}
fixme("setpgid(%d, %d) is stub!", pid, pgid); target->Security.ProcessGroupID = pgid;
return 0; return 0;
} }
@ -1702,16 +1996,22 @@ static int linux_reboot(SysFrm *, int magic, int magic2, int cmd, void *arg)
} }
/* https://man7.org/linux/man-pages/man2/sigaction.2.html */ /* https://man7.org/linux/man-pages/man2/sigaction.2.html */
static int linux_sigaction(SysFrm *, int signum, static int linux_sigaction(SysFrm *, int signum, const k_sigaction *act,
const struct sigaction *act, k_sigaction *oldact, size_t sigsetsize)
struct sigaction *oldact)
{ {
if (signum == linux_SIGKILL || signum == linux_SIGSTOP) if (signum < 1 || signum > linux_SIGRTMAX ||
signum == linux_SIGKILL || signum == linux_SIGSTOP)
{ {
debug("Invalid signal %d", signum); debug("Invalid signal %d", signum);
return -EINVAL; return -EINVAL;
} }
if (sigsetsize != sizeof(sigset_t))
{
warn("Unsupported sigsetsize %d!", sigsetsize);
return -EINVAL;
}
PCB *pcb = thisProcess; PCB *pcb = thisProcess;
Memory::VirtualMemoryArea *vma = pcb->vma; Memory::VirtualMemoryArea *vma = pcb->vma;
@ -1727,13 +2027,35 @@ static int linux_sigaction(SysFrm *, int signum,
int ret = 0; int ret = 0;
if (pOldact) if (pOldact)
ret = pcb->Signals->GetAction(signum, pOldact); {
Signals nSig = ConvertSignalToNative(signum);
assert(nSig != SIG_NULL);
SignalAction nSA{};
SetSigActToNative(pOldact, &nSA);
ret = pcb->Signals.GetAction(nSig, &nSA);
SetSigActToLinux(&nSA, pOldact);
}
if (unlikely(ret < 0)) if (unlikely(ret < 0))
return ret; return ret;
if (pAct) if (pAct)
ret = pcb->Signals->SetAction(signum, *pAct); {
if (pAct->flags & SA_IMMUTABLE)
{
warn("Immutable signal %d", signum);
return -EINVAL;
}
Signals nSig = ConvertSignalToNative(signum);
assert(nSig != SIG_NULL);
SignalAction nSA{};
SetSigActToNative(pAct, &nSA);
ret = pcb->Signals.SetAction(nSig, &nSA);
SetSigActToLinux(&nSA, (k_sigaction *)pAct);
}
return ret; return ret;
} }
@ -1750,7 +2072,8 @@ static int linux_sigprocmask(SysFrm *, int how, const sigset_t *set,
return -EINVAL; return -EINVAL;
} }
PCB *pcb = thisProcess; TCB *tcb = thisThread;
PCB *pcb = tcb->Parent;
Memory::VirtualMemoryArea *vma = pcb->vma; Memory::VirtualMemoryArea *vma = pcb->vma;
if (vma->UserCheck(set) < 0 && set != nullptr) if (vma->UserCheck(set) < 0 && set != nullptr)
@ -1765,21 +2088,25 @@ static int linux_sigprocmask(SysFrm *, int how, const sigset_t *set,
how, pSet ? *pSet : 0, pOldset ? *pOldset : 0); how, pSet ? *pSet : 0, pOldset ? *pOldset : 0);
if (pOldset) if (pOldset)
*pOldset = pcb->Signals->GetMask(); {
*pOldset = tcb->Signals.GetMask();
*pOldset = ConvertMaskToLinux(*pOldset);
}
if (!pSet) if (!pSet)
return 0; return 0;
sigset_t nativeSet = ConvertMaskToNative(*pSet);
switch (how) switch (how)
{ {
case SIG_BLOCK: case SIG_BLOCK:
pcb->Signals->Block(*pSet); tcb->Signals.Block(nativeSet);
break; break;
case SIG_UNBLOCK: case SIG_UNBLOCK:
pcb->Signals->Unblock(*pSet); tcb->Signals.Unblock(nativeSet);
break; break;
case SIG_SETMASK: case SIG_SETMASK:
pcb->Signals->SetMask(*pSet); tcb->Signals.SetMask(nativeSet);
break; break;
default: default:
warn("Invalid how %#x", how); warn("Invalid how %#x", how);
@ -1791,7 +2118,7 @@ static int linux_sigprocmask(SysFrm *, int how, const sigset_t *set,
/* https://man7.org/linux/man-pages/man2/sigreturn.2.html */ /* https://man7.org/linux/man-pages/man2/sigreturn.2.html */
static void linux_sigreturn(SysFrm *sf) static void linux_sigreturn(SysFrm *sf)
{ {
thisProcess->Signals->RestoreHandleSignal(sf); thisProcess->Signals.RestoreHandleSignal(sf, thisThread);
} }
/* https://man7.org/linux/man-pages/man2/gettid.2.html */ /* https://man7.org/linux/man-pages/man2/gettid.2.html */
@ -1803,14 +2130,13 @@ static pid_t linux_gettid(SysFrm *)
/* https://man7.org/linux/man-pages/man2/tkill.2.html */ /* https://man7.org/linux/man-pages/man2/tkill.2.html */
static int linux_tkill(SysFrm *, int tid, int sig) static int linux_tkill(SysFrm *, int tid, int sig)
{ {
Tasking::PCB *pcb = thisProcess; Tasking::TCB *tcb = thisProcess->GetThread(tid);
Tasking::TCB *tcb = pcb->GetThread(tid);
if (!tcb) if (!tcb)
return -ESRCH; return -ESRCH;
Signals nSig = ConvertSignalToNative(sig); Signals nSig = ConvertSignalToNative(sig);
assert(nSig != SIG_NULL); assert(nSig != SIG_NULL);
return pcb->Signals.SendSignal(nSig); return tcb->SendSignal(nSig);
} }
/* https://man7.org/linux/man-pages/man2/set_tid_address.2.html */ /* https://man7.org/linux/man-pages/man2/set_tid_address.2.html */
@ -1919,6 +2245,7 @@ static int linux_clock_gettime(SysFrm *, clockid_t clockid, struct timespec *tp)
return 0; return 0;
} }
/* https://man7.org/linux/man-pages/man2/clock_nanosleep.2.html */
static int linux_clock_nanosleep(SysFrm *, clockid_t clockid, int flags, static int linux_clock_nanosleep(SysFrm *, clockid_t clockid, int flags,
const struct timespec *request, const struct timespec *request,
struct timespec *remain) struct timespec *remain)
@ -1981,12 +2308,29 @@ static __noreturn void linux_exit_group(SysFrm *sf, int status)
/* https://man7.org/linux/man-pages/man2/tgkill.2.html */ /* https://man7.org/linux/man-pages/man2/tgkill.2.html */
static int linux_tgkill(SysFrm *sf, pid_t tgid, pid_t tid, int sig) static int linux_tgkill(SysFrm *sf, pid_t tgid, pid_t tid, int sig)
{ {
Tasking::TCB *target = thisProcess->GetContext()->GetThreadByID(tid, thisProcess); Tasking::TCB *tcb = thisProcess->GetThread(tid);
if (!target) if (!tcb || tcb->Linux.tgid != tgid)
return -ESRCH; {
debug("Invalid tgid %d tid %d", tgid, tid);
fixme("semi-stub: %d %d %d", tgid, tid, sig); tcb = nullptr;
return target->Parent->Signals->SendSignal(sig); foreach (auto t in thisProcess->Threads)
{
if (t->Linux.tgid == tgid)
{
debug("Found tgid %d tid %d", tgid, t->ID);
tcb = t;
break;
}
}
if (!tcb)
return -ESRCH;
}
Signals nSig = ConvertSignalToNative(sig);
assert(nSig != SIG_NULL);
return tcb->SendSignal(nSig);
} }
/* https://man7.org/linux/man-pages/man2/open.2.html */ /* https://man7.org/linux/man-pages/man2/open.2.html */
@ -2098,36 +2442,20 @@ static int linux_prlimit64(SysFrm *, pid_t pid, int resource,
UNUSED(pNewLimit); UNUSED(pNewLimit);
if (new_limit) if (new_limit)
debug("new limit: rlim_cur:%ld rlim_max:%ld", pNewLimit->rlim_cur, pNewLimit->rlim_max); debug("new limit: rlim_cur:%#lx rlim_max:%#lx", pNewLimit->rlim_cur, pNewLimit->rlim_max);
if (old_limit) if (old_limit)
debug("old limit: rlim_cur:%ld rlim_max:%ld", pOldLimit->rlim_cur, pOldLimit->rlim_max); debug("old limit: rlim_cur:%#lx rlim_max:%#lx", pOldLimit->rlim_cur, pOldLimit->rlim_max);
switch (resource) switch (resource)
{ {
case RLIMIT_NOFILE:
{
fixme("Setting RLIMIT_NOFILE is stub");
return 0;
}
case RLIMIT_STACK:
{
fixme("Setting RLIMIT_STACK is stub");
return 0;
}
case RLIMIT_NPROC:
{
fixme("Setting RLIMIT_NPROC is stub");
return 0;
}
case RLIMIT_FSIZE:
{
fixme("Setting RLIMIT_FSIZE is stub");
return 0;
}
case RLIMIT_CPU: case RLIMIT_CPU:
case RLIMIT_FSIZE:
case RLIMIT_DATA: case RLIMIT_DATA:
case RLIMIT_STACK:
case RLIMIT_CORE: case RLIMIT_CORE:
case RLIMIT_RSS: case RLIMIT_RSS:
case RLIMIT_NPROC:
case RLIMIT_NOFILE:
case RLIMIT_MEMLOCK: case RLIMIT_MEMLOCK:
case RLIMIT_AS: case RLIMIT_AS:
case RLIMIT_LOCKS: case RLIMIT_LOCKS:
@ -2138,8 +2466,8 @@ static int linux_prlimit64(SysFrm *, pid_t pid, int resource,
case RLIMIT_RTTIME: case RLIMIT_RTTIME:
case RLIMIT_NLIMITS: case RLIMIT_NLIMITS:
{ {
fixme("resource %d is stub", resource); fixme("resource %s(%d) is stub", rlimitStr[resource], resource);
return -ENOSYS; return 0; /* just return 0 */
} }
default: default:
{ {

View File

@ -18,6 +18,7 @@
#include <task.hpp> #include <task.hpp>
#include <dumper.hpp> #include <dumper.hpp>
#include <signal.hpp>
#include <convert.h> #include <convert.h>
#include <lock.hpp> #include <lock.hpp>
#include <printf.h> #include <printf.h>
@ -58,7 +59,7 @@ namespace Tasking
int PCB::SendSignal(int sig) int PCB::SendSignal(int sig)
{ {
return this->Signals->SendSignal(sig); return this->Signals.SendSignal((enum Signals)sig);
} }
void PCB::SetState(TaskState state) void PCB::SetState(TaskState state)
@ -138,7 +139,8 @@ namespace Tasking
TaskExecutionMode ExecutionMode, TaskExecutionMode ExecutionMode,
bool UseKernelPageTable, bool UseKernelPageTable,
uint16_t UserID, uint16_t GroupID) uint16_t UserID, uint16_t GroupID)
: Node(ProcFS, std::to_string(ctx->NextPID), NodeType::DIRECTORY) : Node(ProcFS, std::to_string(ctx->NextPID), NodeType::DIRECTORY),
Signals(this)
{ {
debug("+ %#lx", this); debug("+ %#lx", this);
@ -214,7 +216,6 @@ namespace Tasking
this->vma = new Memory::VirtualMemoryArea(this->PageTable); this->vma = new Memory::VirtualMemoryArea(this->PageTable);
this->ProgramBreak = new Memory::ProgramBreak(this->PageTable, this->vma); this->ProgramBreak = new Memory::ProgramBreak(this->PageTable, this->vma);
this->Signals = new Signal(this);
debug("Process page table: %#lx", this->PageTable); debug("Process page table: %#lx", this->PageTable);
debug("Created %s process \"%s\"(%d). Parent \"%s\"(%d)", debug("Created %s process \"%s\"(%d). Parent \"%s\"(%d)",
@ -230,7 +231,6 @@ namespace Tasking
this->AllocatedMemory += sizeof(Memory::VirtualMemoryArea); this->AllocatedMemory += sizeof(Memory::VirtualMemoryArea);
this->AllocatedMemory += sizeof(Memory::ProgramBreak); this->AllocatedMemory += sizeof(Memory::ProgramBreak);
this->AllocatedMemory += sizeof(SymbolResolver::Symbols); this->AllocatedMemory += sizeof(SymbolResolver::Symbols);
this->AllocatedMemory += sizeof(Signal);
this->Info.SpawnTime = TimeManager->GetCounter(); this->Info.SpawnTime = TimeManager->GetCounter();
@ -250,9 +250,6 @@ namespace Tasking
don't get scheduled anymore */ don't get scheduled anymore */
ctx->PopProcess(this); ctx->PopProcess(this);
debug("Freeing signals");
delete this->Signals;
debug("Freeing allocated memory"); debug("Freeing allocated memory");
delete this->ProgramBreak; delete this->ProgramBreak;
delete this->vma; delete this->vma;

View File

@ -678,7 +678,7 @@ namespace Tasking::Scheduler
CPU::x32::wrmsr(CPU::x32::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase); CPU::x32::wrmsr(CPU::x32::MSR_FS_BASE, CurrentCPU->CurrentThread->FSBase);
#endif #endif
CurrentCPU->CurrentProcess->Signals->HandleSignal(Frame); CurrentCPU->CurrentProcess->Signals.HandleSignal(Frame, CurrentCPU->CurrentThread.load());
if (!ProcessNotChanged) if (!ProcessNotChanged)
(&CurrentCPU->CurrentProcess->Info)->LastUpdateTime = TimeManager->GetCounter(); (&CurrentCPU->CurrentProcess->Info)->LastUpdateTime = TimeManager->GetCounter();

View File

@ -30,73 +30,72 @@
#include "../kernel.h" #include "../kernel.h"
#ifdef DEBUG #ifdef DEBUG
const char *lSigStr[] = {
"SIGHUP",
"SIGINT",
"SIGQUIT",
"SIGILL",
"SIGTRAP",
"SIGABRT",
"SIGBUS",
"SIGFPE",
"SIGKILL",
"SIGUSR1",
"SIGSEGV",
"SIGUSR2",
"SIGPIPE",
"SIGALRM",
"SIGTERM",
"SIGSTKFLT",
"SIGCHLD",
"SIGCONT",
"SIGSTOP",
"SIGTSTP",
"SIGTTIN",
"SIGTTOU",
"SIGURG",
"SIGXCPU",
"SIGXFSZ",
"SIGVTALRM",
"SIGPROF",
"SIGWINCH",
"SIGPOLL",
"SIGPWR",
"SIGSYS",
"SIGUNUSED",
};
const char *sigStr[] = { const char *sigStr[] = {
"INVALID ", /* 0 */ "INVALID",
"SIGABRT ", /* 1 */ "SIGABRT",
"SIGALRM ", /* 2 */ "SIGALRM",
"SIGBUS ", /* 3 */ "SIGBUS",
"SIGCHLD ", /* 4 */ "SIGCHLD",
"SIGCONT ", /* 5 */ "SIGCONT",
"SIGFPE ", /* 6 */ "SIGFPE",
"SIGHUP ", /* 7 */ "SIGHUP",
"SIGILL ", /* 8 */ "SIGILL",
"SIGINT ", /* 9 */ "SIGINT",
"SIGKILL ", /* 10 */ "SIGKILL",
"SIGPIPE ", /* 11 */ "SIGPIPE",
"SIGQUIT ", /* 12 */ "SIGQUIT",
"SIGSEGV ", /* 13 */ "SIGSEGV",
"SIGSTOP ", /* 14 */ "SIGSTOP",
"SIGTERM ", /* 15 */ "SIGTERM",
"SIGTSTP ", /* 16 */ "SIGTSTP",
"SIGTTIN ", /* 17 */ "SIGTTIN",
"SIGTTOU ", /* 18 */ "SIGTTOU",
"SIGUSR1 ", /* 19 */ "SIGUSR1",
"SIGUSR2 ", /* 20 */ "SIGUSR2",
"SIGPOLL ", /* 21 */ "SIGPOLL",
"SIGPROF ", /* 22 */ "SIGPROF",
"SIGSYS ", /* 23 */ "SIGSYS",
"SIGTRAP ", /* 24 */ "SIGTRAP",
"SIGURG ", /* 25 */ "SIGURG",
"SIGVTALRM", /* 26 */ "SIGVTALRM",
"SIGXCPU ", /* 27 */ "SIGXCPU",
"SIGXFSZ ", /* 28 */ "SIGXFSZ",
"SIGRSV1 ", /* 29 */ "SIGCOMP1",
"SIGRSV2 ", /* 30 */ "SIGCOMP2",
/* 31 */ "SIGCOMP3",
/* 32 */ "SIGRTMIN",
/* 33 */ "SIGRT_1",
/* 34 */ "SIGRT_2",
/* 35 */ "SIGRT_3",
/* 36 */ "SIGRT_4",
/* 37 */ "SIGRT_5",
/* 38 */ "SIGRT_6",
/* 39 */ "SIGRT_7",
/* 40 */ "SIGRT_8",
/* 41 */ "SIGRT_9",
/* 42 */ "SIGRT_10",
/* 43 */ "SIGRT_11",
/* 44 */ "SIGRT_12",
/* 45 */ "SIGRT_13",
/* 46 */ "SIGRT_14",
/* 47 */ "SIGRT_15",
/* 48 */ "SIGRT_16",
/* 49 */ "SIGRT_17",
/* 50 */ "SIGRT_18",
/* 51 */ "SIGRT_19",
/* 52 */ "SIGRT_20",
/* 53 */ "SIGRT_21",
/* 54 */ "SIGRT_22",
/* 55 */ "SIGRT_23",
/* 56 */ "SIGRT_24",
/* 57 */ "SIGRT_25",
/* 58 */ "SIGRT_26",
/* 59 */ "SIGRT_27",
/* 60 */ "SIGRT_28",
/* 61 */ "SIGRT_29",
/* 62 */ "SIGRT_30",
/* 63 */ "SIGRT_31",
/* 64 */ "SIGRTMAX",
}; };
const char *dispStr[] = { const char *dispStr[] = {
@ -113,50 +112,89 @@ extern "C" uintptr_t _sig_linux_trampoline_start, _sig_linux_trampoline_end;
static const struct static const struct
{ {
int linuxSignal; Signals Signal;
int nativeSignal; SignalDispositions Disposition;
} signalMapping[] = { } SignalDisposition[] = {
{linux_SIGHUP, SIGHUP}, {SIGHUP, SIG_TERM},
{linux_SIGINT, SIGINT}, {SIGINT, SIG_TERM},
{linux_SIGQUIT, SIGQUIT}, {SIGQUIT, SIG_TERM},
{linux_SIGILL, SIGILL}, {SIGILL, SIG_CORE},
{linux_SIGTRAP, SIGTRAP}, {SIGTRAP, SIG_CORE},
{linux_SIGABRT, SIGABRT}, {SIGABRT, SIG_CORE},
{linux_SIGBUS, SIGBUS}, {SIGBUS, SIG_CORE},
{linux_SIGFPE, SIGFPE}, {SIGFPE, SIG_CORE},
{linux_SIGKILL, SIGKILL}, {SIGKILL, SIG_TERM},
{linux_SIGUSR1, SIGUSR1}, {SIGUSR1, SIG_TERM},
{linux_SIGSEGV, SIGSEGV}, {SIGSEGV, SIG_CORE},
{linux_SIGUSR2, SIGUSR2}, {SIGUSR2, SIG_TERM},
{linux_SIGPIPE, SIGPIPE}, {SIGPIPE, SIG_TERM},
{linux_SIGALRM, SIGALRM}, {SIGALRM, SIG_TERM},
{linux_SIGTERM, SIGTERM}, {SIGTERM, SIG_TERM},
{linux_SIGSTKFLT, SIGRSV1}, {SIGCOMP1, SIG_IGN},
{linux_SIGCHLD, SIGCHLD}, {SIGCHLD, SIG_IGN},
{linux_SIGCONT, SIGCONT}, {SIGCONT, SIG_CONT},
{linux_SIGSTOP, SIGSTOP}, {SIGSTOP, SIG_STOP},
{linux_SIGTSTP, SIGTSTP}, {SIGTSTP, SIG_STOP},
{linux_SIGTTIN, SIGTTIN}, {SIGTTIN, SIG_STOP},
{linux_SIGTTOU, SIGTTOU}, {SIGTTOU, SIG_STOP},
{linux_SIGURG, SIGURG}, {SIGURG, SIG_IGN},
{linux_SIGXCPU, SIGXCPU}, {SIGXCPU, SIG_CORE},
{linux_SIGXFSZ, SIGXFSZ}, {SIGXFSZ, SIG_CORE},
{linux_SIGVTALRM, SIGVTALRM}, {SIGVTALRM, SIG_TERM},
{linux_SIGPROF, SIGPROF}, {SIGPROF, SIG_TERM},
{linux_SIGPOLL, SIGPOLL}, {SIGCOMP2, SIG_IGN},
{linux_SIGPWR, SIGRSV2}, {SIGPOLL, SIG_TERM},
{linux_SIGSYS, SIGSYS}, {SIGCOMP3, SIG_IGN},
{linux_SIGUNUSED, SIGSYS}, {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},
}; };
static_assert(linux_SIGUNUSED == SIGNAL_MAX); SignalDispositions GetDefaultSignalDisposition(Signals sig)
{
foreach (auto var in SignalDisposition)
{
if (var.Signal == sig)
return var.Disposition;
}
#define CTLif(x) ConvertToLinuxIfNecessary(x) error("Invalid signal: %d", sig);
#define CTNif(x) ConvertToNativeIfNecessary(x) return SIG_TERM;
#define CSigTLif(x) ConvertSigsetToLinuxIfNecessary(x) }
#define CSigTNif(x) ConvertSigsetToNativeIfNecessary(x)
/* TODO: CTLif & CTNif may need optimization */ /* syscalls/linux.cpp */
extern int ConvertSignalToLinux(Signals sig);
namespace Tasking namespace Tasking
{ {
@ -165,86 +203,10 @@ namespace Tasking
return ((PCB *)ctx)->Info.Compatibility == Linux; return ((PCB *)ctx)->Info.Compatibility == Linux;
} }
int Signal::ConvertToLinuxIfNecessary(int sig) int Signal::MakeExitCode(Signals sig)
{
if (!LinuxSig())
{
debug("Not linux sig: %d", sig);
return sig;
}
foreach (auto &mapping in signalMapping)
{
if (mapping.nativeSignal == sig)
{
// debug("Converted %d to %d", sig, mapping.linuxSignal);
return mapping.linuxSignal;
}
}
return -1;
}
int Signal::ConvertToNativeIfNecessary(int sig)
{
if (!LinuxSig())
{
debug("Not native sig: %d", sig);
return sig;
}
foreach (auto &mapping in signalMapping)
{
if (mapping.linuxSignal == sig)
{
// debug("Converted %d to %d", sig, mapping.nativeSignal);
return mapping.nativeSignal;
}
}
return -1;
}
sigset_t Signal::ConvertSigsetToLinuxIfNecessary(sigset_t sig)
{
if (!LinuxSig())
{
debug("Not linux sigset: %#lx", sig);
return 0;
}
sigset_t ret = 0;
for (int i = 0; i < SIGNAL_MAX; i++)
{
if (sig & ToFlag(i))
ret |= ToFlag(CTLif(i));
}
return ret;
}
sigset_t Signal::ConvertSigsetToNativeIfNecessary(sigset_t sig)
{
if (!LinuxSig())
{
debug("Not native sigset: %#lx", sig);
return 0;
}
sigset_t ret = 0;
for (int i = 0; i < linux_SIGUNUSED; i++)
{
if (sig & ToFlag(i))
ret |= ToFlag(CTNif(i));
}
return ret;
}
int Signal::MakeExitCode(int sig)
{ {
if (this->LinuxSig()) if (this->LinuxSig())
return 128 + sig; return 128 + ConvertSignalToLinux(sig);
else else
return 100 + sig; return 100 + sig;
} }
@ -293,7 +255,7 @@ namespace Tasking
} }
case Windows: case Windows:
{ {
fixme("Windows compatibility"); assert(!"Windows compatibility not implemented");
break; break;
} }
default: default:
@ -304,18 +266,18 @@ namespace Tasking
/* ------------------------------------------------------ */ /* ------------------------------------------------------ */
int Signal::AddWatcher(Signal *who, int sig) int Signal::AddWatcher(Signal *who, Signals sig)
{ {
SmartLock(SignalLock);
SignalInfo info; SignalInfo info;
info.sig = sig; info.sig = sig;
info.val.sival_ptr = who; info.val.sival_ptr = who;
SmartLock(SignalLock);
Watchers.push_back(info); Watchers.push_back(info);
return 0; return 0;
} }
int Signal::RemoveWatcher(Signal *who, int sig) int Signal::RemoveWatcher(Signal *who, Signals sig)
{ {
SmartLock(SignalLock); SmartLock(SignalLock);
forItr(itr, Watchers) forItr(itr, Watchers)
@ -330,42 +292,73 @@ namespace Tasking
return -ENOENT; return -ENOENT;
} }
int Signal::AddSignal(int sig, union sigval val) int Signal::AddSignal(Signals sig, union sigval val, pid_t tid)
{ {
SmartLock(SignalLock); SignalInfo info{.sig = sig, .val = val, .tid = tid};
SignalInfo info{.sig = sig, .val = val}; Queue.push_back(info);
SignalQueue.push_back(info);
return 0; return 0;
} }
int Signal::RemoveSignal(int sig) int Signal::RemoveSignal(Signals sig)
{ {
SmartLock(SignalLock); size_t n = Queue.remove_if([sig](SignalInfo &info)
forItr(itr, SignalQueue) { return info.sig == sig; });
{ debug("Removed %d signals", n);
if (itr->sig == sig) return n ? 0 : -ENOENT;
{
SignalQueue.erase(itr);
return 0;
}
}
return -ENOENT;
} }
bool Signal::HandleSignal(CPU::TrapFrame *tf) Signal::SignalInfo Signal::GetAvailableSignal(void *thread)
{ {
SmartLock(SignalLock); forItr(itr, Queue)
if (SignalQueue.empty()) {
return false; // if (GlobalMask.test(itr->sig - 1))
// {
// debug("Signal %s is blocked by global mask",
// sigStr[itr->sig]);
// continue;
// }
if (((TCB *)thread)->Signals.Mask.test(itr->sig - 1))
{
debug("Signal %s is blocked by thread mask",
sigStr[itr->sig]);
continue;
}
if (((TCB *)thread)->ID != itr->tid && itr->tid != -1)
{
debug("Signal %s is not for this thread",
sigStr[itr->sig]);
continue;
}
assert(sa[itr->sig].sa_handler.Disposition != SAD_IGN);
assert(sa[itr->sig].sa_handler.Disposition != SAD_DFL);
Queue.erase(itr);
debug("Signal %s is available", sigStr[itr->sig]);
return *itr;
}
debug("No signal available");
return {};
}
bool Signal::HandleSignal(CPU::TrapFrame *tf, void *thread)
{
/* We don't want to do this in kernel mode */ /* We don't want to do this in kernel mode */
if (unlikely(tf->cs != GDT_USER_CODE)) if (tf->cs != GDT_USER_CODE)
return false; return false;
debug("We have %d signals to handle", SignalQueue.size()); if (Queue.empty())
return false;
SignalInfo sigI = SignalQueue.front(); debug("We have %d signals to handle", Queue.size());
SignalQueue.erase(SignalQueue.begin());
SmartLock(SignalLock);
SignalInfo sigI = GetAvailableSignal(thread);
if (sigI.sig == SIG_NULL)
return false;
uintptr_t _p_rsp = ((PCB *)ctx)->PageTable->Get(tf->rsp); uintptr_t _p_rsp = ((PCB *)ctx)->PageTable->Get(tf->rsp);
uint64_t paRsp = _p_rsp; uint64_t paRsp = _p_rsp;
@ -388,10 +381,11 @@ namespace Tasking
si.GSBase = CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE); si.GSBase = CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE);
si.FSBase = CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE); si.FSBase = CPU::x64::rdmsr(CPU::x64::MSR_FS_BASE);
si.ShadowGSBase = CPU::x64::rdmsr(CPU::x64::MSR_SHADOW_GS_BASE); si.ShadowGSBase = CPU::x64::rdmsr(CPU::x64::MSR_SHADOW_GS_BASE);
si.SignalMask = ((TCB *)thread)->Signals.Mask.to_ulong();
si.Compatibility = ((PCB *)ctx)->Info.Compatibility;
debug("gs: %#lx fs: %#lx shadow: %#lx", debug("gs: %#lx fs: %#lx shadow: %#lx",
si.GSBase, si.FSBase, si.ShadowGSBase); si.GSBase, si.FSBase, si.ShadowGSBase);
si.SignalMask = SignalMask.load();
si.Compatibility = ((PCB *)ctx)->Info.Compatibility;
/* Copy the stack info */ /* Copy the stack info */
uint64_t *pRsp = (uint64_t *)(paRsp - sizeof(StackInfo)); uint64_t *pRsp = (uint64_t *)(paRsp - sizeof(StackInfo));
@ -400,31 +394,56 @@ namespace Tasking
/* Set the handler address */ /* Set the handler address */
pRsp--; /* Alignment */ pRsp--; /* Alignment */
pRsp--; pRsp--;
*pRsp = uint64_t(SignalAction[sigI.sig].__sa_handler.sa_handler); *pRsp = uint64_t(sa[sigI.sig].sa_handler.Handler);
assert(!((uintptr_t)pRsp & 0xF)); assert(!((uintptr_t)pRsp & 0xF));
int cSig = LinuxSig() ? ConvertSignalToLinux((Signals)sigI.sig) : sigI.sig;
#ifdef DEBUG #ifdef DEBUG
DumpData("Stack Data", (void *)pRsp, DumpData("Stack Data", (void *)pRsp,
paRsp - uint64_t(pRsp)); paRsp - uint64_t(pRsp));
debug("initial stack tf->rsp: %#lx after: %#lx", debug("initial stack tf->rsp: %#lx after: %#lx",
tf->rsp, uint64_t(vRsp)); tf->rsp, uint64_t(vRsp));
debug("sig: %d -> %d", sigI.sig, CTLif(sigI.sig)); debug("sig: %d -> %d", sigI.sig, cSig);
#endif #endif
tf->rsp = uint64_t(vRsp); tf->rsp = uint64_t(vRsp);
tf->rip = uint64_t(TrampAddr); tf->rip = uint64_t(TrampAddr);
tf->rdi = CTLif(sigI.sig);
tf->rsi = uint64_t(sigI.val.sival_ptr);
/* void func(int signo); */
/* void func(int signo, siginfo_t *info, void *context); */
tf->rdi = cSig;
if (sa[sigI.sig].Flags & SA_SIGINFO)
{
fixme("SA_SIGINFO not implemented");
siginfo_t *info = 0;
void *context = 0;
tf->rsi = uint64_t(info);
tf->rdx = uint64_t(context);
tf->rcx = 0;
tf->r8 = 0;
tf->r9 = 0;
}
else
{
tf->rsi = 0;
tf->rdx = 0;
tf->rcx = 0;
tf->r8 = 0;
tf->r9 = 0;
}
((TCB *)thread)->Signals.Mask = sa[sigI.sig].Mask;
assert(TrampAddr != nullptr); assert(TrampAddr != nullptr);
return true; return true;
} }
void Signal::RestoreHandleSignal(SyscallsFrame *sf) void Signal::RestoreHandleSignal(SyscallsFrame *sf, void *thread)
{ {
SmartLock(SignalLock);
debug("Restoring signal handler"); debug("Restoring signal handler");
SmartLock(SignalLock);
gsTCB *gs = (gsTCB *)CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE); gsTCB *gs = (gsTCB *)CPU::x64::rdmsr(CPU::x64::MSR_GS_BASE);
uint64_t *sp = (uint64_t *)((PCB *)ctx)->PageTable->Get(gs->TempStack); uint64_t *sp = (uint64_t *)((PCB *)ctx)->PageTable->Get(gs->TempStack);
sp++; /* Alignment */ sp++; /* Alignment */
@ -454,7 +473,7 @@ namespace Tasking
sf->ReturnAddress = si->tf.rip; sf->ReturnAddress = si->tf.rip;
gs->TempStack = (void *)si->tf.rsp; gs->TempStack = (void *)si->tf.rsp;
SignalMask.store(si->SignalMask); ((TCB *)thread)->Signals.Mask = si->SignalMask;
CPU::x64::fxrstor(&si->fx); CPU::x64::fxrstor(&si->fx);
CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, si->ShadowGSBase); CPU::x64::wrmsr(CPU::x64::MSR_GS_BASE, si->ShadowGSBase);
@ -468,86 +487,83 @@ namespace Tasking
/* Return because we will restore at sysretq */ /* Return because we will restore at sysretq */
} }
sigset_t Signal::Block(sigset_t sig) int Signal::SetAction(Signals sig, const SignalAction *act)
{ {
SmartLock(SignalLock); SmartLock(SignalLock);
sig = CSigTNif(sig); if ((size_t)sig > sizeof(sa) / sizeof(sa[0]))
sigset_t oldMask = SignalMask.fetch_or(sig);
debug("%#lx -> %#lx", oldMask, SignalMask);
return CSigTLif(oldMask);
}
sigset_t Signal::Unblock(sigset_t sig)
{
SmartLock(SignalLock);
sig = CSigTNif(sig);
sigset_t oldMask = SignalMask.fetch_and(~sig);
debug("%#lx -> %#lx", oldMask, SignalMask);
return CSigTLif(oldMask);
}
sigset_t Signal::SetMask(sigset_t sig)
{
SmartLock(SignalLock);
sig = CSigTNif(sig);
sigset_t oldMask = SignalMask.exchange(sig);
debug("%#lx -> %#lx", oldMask, SignalMask);
return CSigTLif(oldMask);
}
int Signal::SetAction(int sig, const sigaction act)
{
SmartLock(SignalLock);
int nSig = CTNif(sig);
if ((size_t)nSig > sizeof(SignalAction) / sizeof(SignalAction[0]))
{ {
debug("Invalid signal: %d (req %d)", nSig, sig); debug("Invalid signal: %d", sig);
return -EINVAL; return -EINVAL;
} }
SignalAction[nSig].__sa_handler.sa_handler = act.__sa_handler.sa_handler; if ((long)act->sa_handler.Disposition == SAD_IGN)
SignalAction[nSig].sa_mask = act.sa_mask; {
SignalAction[nSig].sa_flags = act.sa_flags; Disposition[sig] = SIG_IGN;
debug("Set disposition for %s to SIG_IGN", sigStr[sig]);
debug("Discarding pending signals %s", sigStr[sig]);
bool found = false;
forItr(itr, Queue)
{
if (itr->sig == sig)
{
Queue.erase(itr);
found = true;
break;
}
}
if (!found)
{
debug("No pending signal %s", sigStr[sig]);
}
}
if ((long)act->sa_handler.Disposition == SAD_DFL)
{
Disposition[sig] = GetDefaultSignalDisposition(sig);
debug("Set disposition for %s to %s (default)", sigStr[sig],
dispStr[Disposition[sig]]);
}
sa[sig].sa_handler.Handler = act->sa_handler.Handler;
sa[sig].Mask = act->Mask;
sa[sig].Flags = act->Flags;
sa[sig].Restorer = act->Restorer;
debug("Set action for %s with handler %#lx, mask %#lx and flags %#lx", debug("Set action for %s with handler %#lx, mask %#lx and flags %#lx",
LinuxSig() ? lSigStr[nSig] : sigStr[nSig], sigStr[sig], sa[sig].sa_handler.Handler, sa[sig].Mask, sa[sig].Flags);
SignalAction[nSig].__sa_handler.sa_handler,
SignalAction[nSig].sa_mask,
SignalAction[nSig].sa_flags);
return 0; return 0;
} }
int Signal::GetAction(int sig, sigaction *act) int Signal::GetAction(Signals sig, SignalAction *act)
{ {
SmartLock(SignalLock); SmartLock(SignalLock);
if ((size_t)sig > sizeof(sa) / sizeof(sa[0]))
int nSig = CTNif(sig);
if ((size_t)nSig > sizeof(SignalAction) / sizeof(SignalAction[0]))
{ {
debug("Invalid signal: %d (req %d)", nSig, sig); debug("Invalid signal: %d", sig);
return -EINVAL; return -EINVAL;
} }
act->__sa_handler.sa_handler = SignalAction[nSig].__sa_handler.sa_handler; act->sa_handler.Handler = sa[sig].sa_handler.Handler;
act->sa_mask = SignalAction[nSig].sa_mask; act->Mask = sa[sig].Mask;
act->sa_flags = SignalAction[nSig].sa_flags; act->Flags = sa[sig].Flags;
act->Restorer = sa[sig].Restorer;
debug("Got action for %s with handler %#lx, mask %#lx and flags %#lx", debug("Got action for %s with handler %#lx, mask %#lx and flags %#lx",
LinuxSig() ? lSigStr[nSig] : sigStr[nSig], sigStr[sig], sa[sig].sa_handler.Handler, sa[sig].Mask, sa[sig].Flags);
SignalAction[nSig].__sa_handler.sa_handler,
SignalAction[nSig].sa_mask,
SignalAction[nSig].sa_flags);
return 0; return 0;
} }
int Signal::SendSignal(int sig, union sigval val) int Signal::SendSignal(Signals sig, sigval val, pid_t tid)
{ {
SmartLock(SignalLock);
PCB *pcb = (PCB *)ctx; PCB *pcb = (PCB *)ctx;
int nSig = CTNif(sig); LastSignal = sig;
LastSignal = (Signals)nSig;
debug("Sending signal %s to %s(%d)", debug("Sending signal %s to %s(%d)",
sigStr[nSig], pcb->Name, pcb->ID); sigStr[sig], pcb->Name, pcb->ID);
if (SignalAction[nSig].__sa_handler.sa_handler) if (sa[sig].sa_handler.Handler)
{ {
if (pcb->Security.ExecutionMode == Kernel) if (pcb->Security.ExecutionMode == Kernel)
{ {
@ -555,35 +571,51 @@ namespace Tasking
return -EINVAL; return -EINVAL;
} }
debug("sa_handler: %#lx", if (sa[sig].sa_handler.Disposition == SAD_IGN)
SignalAction[nSig].__sa_handler.sa_handler); {
debug("Adding signal %s to queue", sigStr[nSig]); debug("Ignoring signal %s", sigStr[sig]);
return 0;
}
debug("sa_handler: %#lx", sa[sig].sa_handler.Handler);
debug("Adding signal %s to queue", sigStr[sig]);
goto CompleteSignal; goto CompleteSignal;
} }
else
{
debug("No handler for signal %s", sigStr[sig]);
}
debug("Signal disposition: %s", dispStr[sigDisp[nSig]]); if (thisThread->Signals.Mask.test(sig - 1))
switch (sigDisp[nSig]) {
debug("Signal %s is blocked by thread mask",
sigStr[sig]);
return 0;
}
debug("Signal disposition: %s", dispStr[Disposition[sig]]);
switch (Disposition[sig])
{ {
case SIG_TERM: case SIG_TERM:
{ {
if (unlikely(pcb->Security.IsCritical)) if (unlikely(pcb->Security.IsCritical))
{ {
debug("Critical process %s received signal %s(%d): Terminated", debug("Critical process %s received signal %s(%d): Terminated",
pcb->Name, sigStr[nSig], nSig); pcb->Name, sigStr[sig], sig);
// int3; // int3;
} }
pcb->SetExitCode(MakeExitCode(nSig)); pcb->SetExitCode(MakeExitCode(sig));
debug("We have %d watchers", this->Watchers.size()); debug("We have %d watchers", this->Watchers.size());
if (this->Watchers.size() > 0) if (this->Watchers.size() > 0)
pcb->SetState(Zombie); pcb->SetState(Zombie);
else else
pcb->SetState(Terminated); pcb->SetState(Terminated);
break; return 0;
} }
case SIG_IGN: case SIG_IGN:
{ {
debug("Ignoring signal %d", nSig); debug("Ignoring signal %d", sig);
return 0; return 0;
} }
case SIG_CORE: case SIG_CORE:
@ -593,27 +625,31 @@ namespace Tasking
if (unlikely(pcb->Security.IsCritical)) if (unlikely(pcb->Security.IsCritical))
{ {
debug("Critical process %s received signal %s(%d): Core dumped", debug("Critical process %s received signal %s(%d): Core dumped",
pcb->Name, sigStr[nSig], nSig); pcb->Name, sigStr[sig], sig);
// int3; // int3;
} }
pcb->SetExitCode(MakeExitCode(nSig)); pcb->SetExitCode(MakeExitCode(sig));
debug("We have %d watchers", this->Watchers.size()); debug("We have %d watchers", this->Watchers.size());
if (this->Watchers.size() > 0) if (this->Watchers.size() > 0)
pcb->SetState(CoreDump); pcb->SetState(CoreDump);
else else
pcb->SetState(Terminated); pcb->SetState(Terminated);
break; return 0;
} }
case SIG_STOP: case SIG_STOP:
{ {
debug("Stopping process %s(%d) with signal %s(%d)",
pcb->Name, pcb->ID, sigStr[sig], sig);
pcb->SetState(Stopped); pcb->SetState(Stopped);
break; return 0;
} }
case SIG_CONT: case SIG_CONT:
{ {
debug("Continuing process %s(%d) with signal %s(%d)",
pcb->Name, pcb->ID, sigStr[sig], sig);
pcb->SetState(Ready); pcb->SetState(Ready);
break; return 0;
} }
default: default:
assert(!"Invalid signal disposition"); assert(!"Invalid signal disposition");
@ -624,14 +660,14 @@ namespace Tasking
if (pcb->Security.ExecutionMode == Kernel) if (pcb->Security.ExecutionMode == Kernel)
{ {
debug("Kernel process %s received signal %s(%d)! Ignoring... (with exceptions)", debug("Kernel process %s received signal %s(%d)! Ignoring... (with exceptions)",
pcb->Name, sigStr[nSig], nSig); pcb->Name, sigStr[sig], sig);
return 0; return 0;
} }
this->InitTrampoline(); this->InitTrampoline();
debug("Signal %s(%d) completed", sigStr[nSig], nSig); debug("Signal %s(%d) completed", sigStr[sig], sig);
if (sigDisp[nSig] != SIG_IGN) if (Disposition[sig] != SIG_IGN)
{ {
foreach (auto info in Watchers) foreach (auto info in Watchers)
{ {
@ -645,27 +681,24 @@ namespace Tasking
} }
debug("Adding signal to queue"); debug("Adding signal to queue");
SignalQueue.push_back({.sig = nSig, .val = val}); Queue.push_back({.sig = sig, .val = val, .tid = tid});
return 0; return 0;
} }
int Signal::WaitAnySignal() int Signal::WaitAnySignal()
{ {
/* Sleep until a signal that terminated or invokes
the signal catch function */
debug("Waiting for any signal"); debug("Waiting for any signal");
size_t oldSize = SignalQueue.size(); size_t oldSize = Queue.size();
Reset: Reset:
while (SignalQueue.size() == oldSize) while (Queue.size() == oldSize)
TaskManager->Yield(); TaskManager->Yield();
if (SignalQueue.size() > oldSize) if (Queue.size() > oldSize)
{ {
debug("Added signal to queue %d > %d", debug("Added signal to queue %d > %d",
SignalQueue.size(), oldSize); Queue.size(), oldSize);
oldSize = SignalQueue.size(); oldSize = Queue.size();
goto Reset; goto Reset;
} }
@ -673,77 +706,66 @@ namespace Tasking
return -EINTR; return -EINTR;
} }
bool Signal::HasPendingSignal() int Signal::WaitSignal(Signals sig, union sigval *val)
{
return !SignalQueue.empty();
}
int Signal::WaitSignal(int sig, union sigval *val)
{ {
assert(!"WaitSignal not implemented");
return 0; return 0;
} }
int Signal::WaitSignalTimeout(int sig, union sigval *val, uint64_t timeout) int Signal::WaitSignalTimeout(Signals sig, union sigval *val, uint64_t timeout)
{ {
assert(!"WaitSignalTimeout not implemented");
return 0; return 0;
} }
Signal::Signal(void *ctx) Signal::Signal(void *_ctx)
{ {
assert(ctx != nullptr); assert(_ctx != nullptr);
this->ctx = ctx; this->ctx = _ctx;
sigDisp[SIG_NULL] = SIG_IGN; // for (int i = 1; i < SIGNAL_MAX; i++)
sigDisp[SIGABRT] = SIG_CORE; // Disposition[i] = GetDefaultSignalDisposition(i);
sigDisp[SIGALRM] = SIG_TERM;
sigDisp[SIGBUS] = SIG_CORE;
sigDisp[SIGCHLD] = SIG_IGN;
sigDisp[SIGCONT] = SIG_CONT;
sigDisp[SIGFPE] = SIG_CORE;
sigDisp[SIGHUP] = SIG_TERM;
sigDisp[SIGILL] = SIG_CORE;
sigDisp[SIGINT] = SIG_TERM;
sigDisp[SIGKILL] = SIG_TERM;
sigDisp[SIGPIPE] = SIG_TERM;
sigDisp[SIGQUIT] = SIG_TERM;
sigDisp[SIGSEGV] = SIG_CORE;
sigDisp[SIGSTOP] = SIG_STOP;
sigDisp[SIGTERM] = SIG_TERM;
sigDisp[SIGTSTP] = SIG_STOP;
sigDisp[SIGTTIN] = SIG_STOP;
sigDisp[SIGTTOU] = SIG_STOP;
sigDisp[SIGUSR1] = SIG_TERM;
sigDisp[SIGUSR2] = SIG_TERM;
sigDisp[SIGPOLL] = SIG_TERM;
sigDisp[SIGPROF] = SIG_TERM;
sigDisp[SIGSYS] = SIG_CORE;
sigDisp[SIGTRAP] = SIG_CORE;
sigDisp[SIGURG] = SIG_IGN;
sigDisp[SIGVTALRM] = SIG_TERM;
sigDisp[SIGXCPU] = SIG_CORE;
sigDisp[SIGXFSZ] = SIG_CORE;
#ifdef DEBUG #ifdef DEBUG
static int once = 0; static int once = 0;
if (!once++) if (!once++)
{ {
if (LinuxSig()) for (int i = 1; i < SIGNAL_MAX; i++)
{ debug("%s: %s",
for (int i = 0; i <= linux_SIGUNUSED; i++) sigStr[i],
debug("%s: %s", dispStr[Disposition[(Signals)i]]);
lSigStr[i],
dispStr[sigDisp[i]]);
}
else
{
for (int i = 0; i < SIGNAL_MAX; i++)
debug("%s: %s",
sigStr[i],
dispStr[sigDisp[i]]);
}
} }
#endif #endif
} }
Signal::~Signal() {} Signal::~Signal() {}
sigset_t ThreadSignal::Block(sigset_t sig)
{
sigset_t oldMask = Mask.to_ulong();
Mask |= sig;
debug("%#lx -> %#lx", oldMask, Mask);
return oldMask;
}
sigset_t ThreadSignal::Unblock(sigset_t sig)
{
sigset_t oldMask = Mask.to_ulong();
Mask &= ~sig;
debug("%#lx -> %#lx", oldMask, Mask);
return oldMask;
}
sigset_t ThreadSignal::SetMask(sigset_t sig)
{
sigset_t oldMask = Mask.to_ulong();
Mask = sig;
debug("%#lx -> %#lx", oldMask, Mask);
return oldMask;
}
sigset_t ThreadSignal::GetMask()
{
return Mask.to_ulong();
}
} }

View File

@ -64,7 +64,7 @@ namespace Tasking
{ {
int TCB::SendSignal(int sig) int TCB::SendSignal(int sig)
{ {
return this->Parent->Signals->SendSignal(sig); return this->Parent->Signals.SendSignal((enum Signals)sig, {0}, this->ID);
} }
void TCB::SetState(TaskState state) void TCB::SetState(TaskState state)
@ -420,6 +420,7 @@ namespace Tasking
TaskArchitecture Architecture, TaskArchitecture Architecture,
TaskCompatibility Compatibility, TaskCompatibility Compatibility,
bool ThreadNotReady) bool ThreadNotReady)
: Signals(Parent->Signals)
{ {
debug("+ %#lx", this); debug("+ %#lx", this);
@ -440,6 +441,14 @@ namespace Tasking
this->ctx = ctx; this->ctx = ctx;
this->ID = (TID)this->Parent->ID + (TID)this->Parent->Threads.size(); this->ID = (TID)this->Parent->ID + (TID)this->Parent->Threads.size();
if (Compatibility == TaskCompatibility::Linux)
{
if (Parent->Threads.size() == 0)
this->Linux.tgid = Parent->ID;
else
this->Linux.tgid = Parent->Threads.front()->Linux.tgid;
}
if (this->Name) if (this->Name)
delete[] this->Name; delete[] this->Name;