mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Implement signals.
Note: This is an incompatible ABI change.
This commit is contained in:
parent
316ed84e60
commit
30cd318c17
64 changed files with 2188 additions and 1121 deletions
|
@ -46,6 +46,16 @@ Obsolescent in POSIX and scheduled for Sortix removal
|
|||
* ctime, ctime_r are scheduled for removal (obsolescent in POSIX).
|
||||
* utime, <utime.h> are scheduled for removal (obsolescent in POSIX).
|
||||
|
||||
Signal Stacks
|
||||
-------------
|
||||
|
||||
Threads are able to set a recursive signal handling stack using sigaltstack(2)
|
||||
even if SS_ONSTACK is currently set - while POSIX mandates EPERM in this case.
|
||||
Such a stack will be used for recursive signals (with SA_ONSTACK set) for the
|
||||
duration of the signal handler. The original signal stack state will be restored
|
||||
when the signal handler returns, any edit with sigaltstack will be temporary
|
||||
(unless the saved ucontext is modified).
|
||||
|
||||
Timestamps
|
||||
----------
|
||||
|
||||
|
|
36
kernel/include/sortix/__/sigset.h
Normal file
36
kernel/include/sortix/__/sigset.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix 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.
|
||||
|
||||
Sortix 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
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/__/sigset.h
|
||||
Declaration of the sigset_t structure size.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX____SIGSET_H
|
||||
#define INCLUDE_SORTIX____SIGSET_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define __SIGSET_NUM_SIGNALS 128
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
55
kernel/include/sortix/__/wait.h
Normal file
55
kernel/include/sortix/__/wait.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix 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.
|
||||
|
||||
Sortix 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
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/__/wait.h
|
||||
Declarations for waiting for the events of children.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX____WAIT_H
|
||||
#define INCLUDE_SORTIX____WAIT_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define __WNATURE_EXITED 0
|
||||
#define __WNATURE_SIGNALED 1
|
||||
#define __WNATURE_STOPPED 2
|
||||
#define __WNATURE_CONTINUED 3
|
||||
|
||||
#define __WEXITSTATUS(status) ((status >> 8) & 0xFF)
|
||||
#define __WTERMSIG(status) ((status >> 0) & 0x7F)
|
||||
#define __WNATURE(status) ((status >> 16) & 0xFF)
|
||||
|
||||
#define __WIFEXITED(status) (__WNATURE(status) == __WNATURE_EXITED)
|
||||
#define __WIFSIGNALED(status) (__WNATURE(status) == __WNATURE_SIGNALED)
|
||||
#define __WIFSTOPPED(status) (__WNATURE(status) == __WNATURE_STOPPED)
|
||||
#define __WIFCONTINUED(status) (__WNATURE(status) == __WNATURE_CONTINUED)
|
||||
|
||||
#define __WSTOPSIG(status) __WTERMSIG(status)
|
||||
|
||||
#define __WCONSTRUCT(nature, exitcode, signal) \
|
||||
(((nature) & 0xFF) << 16 | \
|
||||
((exitcode) & 0xFF) << 8 | \
|
||||
((signal) & 0x7F) << 0)
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -43,12 +43,17 @@ struct exit_thread
|
|||
size_t unmap_size;
|
||||
void* zero_from;
|
||||
size_t zero_size;
|
||||
unsigned long reserved[4];
|
||||
void* tls_unmap_from;
|
||||
size_t tls_unmap_size;
|
||||
unsigned long reserved[2];
|
||||
};
|
||||
|
||||
#define EXIT_THREAD_ONLY_IF_OTHERS (1<<0)
|
||||
#define EXIT_THREAD_UNMAP (1<<1)
|
||||
#define EXIT_THREAD_ZERO (1<<2)
|
||||
#define EXIT_THREAD_TLS_UNMAP (1<<3)
|
||||
#define EXIT_THREAD_PROCESS (1<<4)
|
||||
#define EXIT_THREAD_DUMP_CORE (1<<5)
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -22,13 +22,15 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_FORK_H
|
||||
#define SORTIX_FORK_H
|
||||
#ifndef INCLUDE_SORTIX_FORK_H
|
||||
#define INCLUDE_SORTIX_FORK_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sortix/x86/fork.h>
|
||||
#include <sortix/x64/fork.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sortix/sigset.h>
|
||||
#include <sortix/stack.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
@ -77,13 +79,48 @@ __BEGIN_DECLS
|
|||
own state into such a structure and calling tfork. Note that this structure
|
||||
is highly platform specific, portable code should use the standard threading
|
||||
facilities combined with sfork if possible. */
|
||||
struct tfork
|
||||
{
|
||||
#if defined(__i386__)
|
||||
typedef struct tforkregs_x86 tforkregs_t;
|
||||
uint32_t eip;
|
||||
uint32_t eax;
|
||||
uint32_t ebx;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
uint32_t edi;
|
||||
uint32_t esi;
|
||||
uint32_t esp;
|
||||
uint32_t ebp;
|
||||
uint32_t eflags;
|
||||
uint32_t fsbase;
|
||||
uint32_t gsbase;
|
||||
#elif defined(__x86_64__)
|
||||
typedef struct tforkregs_x64 tforkregs_t;
|
||||
uint64_t rip;
|
||||
uint64_t rax;
|
||||
uint64_t rbx;
|
||||
uint64_t rcx;
|
||||
uint64_t rdx;
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rsp;
|
||||
uint64_t rbp;
|
||||
uint64_t r8;
|
||||
uint64_t r9;
|
||||
uint64_t r10;
|
||||
uint64_t r11;
|
||||
uint64_t r12;
|
||||
uint64_t r13;
|
||||
uint64_t r14;
|
||||
uint64_t r15;
|
||||
uint64_t rflags;
|
||||
uint64_t fsbase;
|
||||
uint64_t gsbase;
|
||||
#else
|
||||
#warning No tforkregs_cpu structure declared
|
||||
#error "You need to add a struct tfork for your platform"
|
||||
#endif
|
||||
sigset_t sigmask;
|
||||
stack_t altstack;
|
||||
};
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -68,9 +68,15 @@ public:
|
|||
}
|
||||
|
||||
~ScopedLock()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
if ( mutex )
|
||||
kthread_mutex_unlock(mutex);
|
||||
mutex = NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -88,9 +94,15 @@ public:
|
|||
}
|
||||
|
||||
~ScopedLockSignal()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
if ( mutex && acquired )
|
||||
kthread_mutex_unlock(mutex);
|
||||
mutex = NULL;
|
||||
}
|
||||
|
||||
bool IsAcquired() { return acquired; }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -27,6 +27,9 @@
|
|||
|
||||
#include <sortix/fork.h>
|
||||
#include <sortix/resource.h>
|
||||
#include <sortix/sigaction.h>
|
||||
#include <sortix/signal.h>
|
||||
#include <sortix/sigset.h>
|
||||
|
||||
#include <sortix/kernel/clock.h>
|
||||
#include <sortix/kernel/kthread.h>
|
||||
|
@ -97,6 +100,12 @@ public:
|
|||
kthread_mutex_t resource_limits_lock;
|
||||
struct rlimit resource_limits[RLIMIT_NUM_DECLARED];
|
||||
|
||||
public:
|
||||
kthread_mutex_t signal_lock;
|
||||
struct sigaction signal_actions[SIG_MAX_NUM];
|
||||
sigset_t signal_pending;
|
||||
void (*sigreturn)(void);
|
||||
|
||||
public:
|
||||
void BootstrapTables(Ref<DescriptorTable> dtable, Ref<MountTable> mtable);
|
||||
void BootstrapDirectories(Ref<Descriptor> root);
|
||||
|
@ -123,7 +132,7 @@ private:
|
|||
size_t zombiewaiting;
|
||||
bool iszombie;
|
||||
bool nozombify;
|
||||
int exitstatus;
|
||||
int exit_code;
|
||||
|
||||
public:
|
||||
Process* group;
|
||||
|
@ -138,6 +147,7 @@ public:
|
|||
public:
|
||||
Thread* firstthread;
|
||||
kthread_mutex_t threadlock;
|
||||
bool threads_exiting;
|
||||
|
||||
public:
|
||||
struct segment* segments;
|
||||
|
@ -160,7 +170,8 @@ public:
|
|||
int envc, const char* const* envp,
|
||||
CPU::InterruptRegisters* regs);
|
||||
void ResetAddressSpace();
|
||||
void Exit(int status);
|
||||
void ExitThroughSignal(int signal);
|
||||
void ExitWithCode(int exit_code);
|
||||
pid_t Wait(pid_t pid, int* status, int options);
|
||||
bool DeliverSignal(int signum);
|
||||
bool DeliverGroupSignal(int signum);
|
||||
|
@ -194,7 +205,6 @@ public:
|
|||
|
||||
public:
|
||||
static Process* Get(pid_t pid);
|
||||
static pid_t HackGetForegroundProcess();
|
||||
|
||||
private:
|
||||
static bool Put(Process* process);
|
||||
|
@ -203,7 +213,7 @@ private:
|
|||
};
|
||||
|
||||
void InitializeThreadRegisters(CPU::InterruptRegisters* regs,
|
||||
const tforkregs_t* requested);
|
||||
const struct tfork* requested);
|
||||
Process* CurrentProcess();
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/kernel/signal.h
|
||||
Classes and functions making it easier to handle Unix signals.
|
||||
Asynchronous user-space thread interruption.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
|||
#define INCLUDE_SORTIX_KERNEL_SIGNAL_H
|
||||
|
||||
#include <sortix/signal.h>
|
||||
#include <sortix/sigset.h>
|
||||
|
||||
#include <sortix/kernel/cpu.h>
|
||||
|
||||
|
@ -35,28 +36,10 @@ extern "C" volatile unsigned long asm_signal_is_pending;
|
|||
|
||||
namespace Signal {
|
||||
|
||||
class Queue
|
||||
{
|
||||
public:
|
||||
Queue();
|
||||
|
||||
// TODO: This is the wrong data structure for the problem!
|
||||
private:
|
||||
bool pending[SIG_MAX_NUM];
|
||||
|
||||
// TODO: This is not SMP ready:
|
||||
// To avoid race conditions, these should be called with interrupts off.
|
||||
public:
|
||||
void Push(int signum);
|
||||
int Pop(int cursig);
|
||||
|
||||
};
|
||||
|
||||
void Init();
|
||||
int Priority(int signum);
|
||||
void Dispatch(CPU::InterruptRegisters* regs, void* user = NULL);
|
||||
void Return(CPU::InterruptRegisters* regs, void* user = NULL);
|
||||
inline bool IsPending() { return asm_signal_is_pending != 0; }
|
||||
void DispatchHandler(CPU::InterruptRegisters* regs, void* user);
|
||||
void ReturnHandler(CPU::InterruptRegisters* regs, void* user);
|
||||
|
||||
} // namespace Signal
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -25,8 +25,12 @@
|
|||
#ifndef INCLUDE_SORTIX_KERNEL_THREAD_H
|
||||
#define INCLUDE_SORTIX_KERNEL_THREAD_H
|
||||
|
||||
#include <sortix/sigaction.h>
|
||||
#include <sortix/signal.h>
|
||||
#include <sortix/sigset.h>
|
||||
#include <sortix/stack.h>
|
||||
|
||||
#include <sortix/kernel/kthread.h>
|
||||
#include <sortix/kernel/scheduler.h>
|
||||
#include <sortix/kernel/signal.h>
|
||||
|
||||
|
@ -68,17 +72,13 @@ Thread* RunKernelThread(ThreadEntry entry, void* user, size_t stacksize = 0);
|
|||
void SetupKernelThreadRegs(CPU::InterruptRegisters* regs, ThreadEntry entry,
|
||||
void* user, addr_t stack, size_t stacksize);
|
||||
|
||||
extern "C" void Thread__OnSigKill(Thread* thread);
|
||||
|
||||
typedef void (*sighandler_t)(int);
|
||||
|
||||
class Thread
|
||||
{
|
||||
friend Thread* CreateKernelThread(Process* process,
|
||||
CPU::InterruptRegisters* regs,
|
||||
unsigned long fsbase, unsigned long gsbase);
|
||||
friend void KernelInit(unsigned long magic, multiboot_info_t* bootinfo);
|
||||
friend void Thread__OnSigKill(Thread* thread);
|
||||
friend void UpdatePendingSignals(Thread* thread);
|
||||
|
||||
public:
|
||||
static void Init();
|
||||
|
@ -107,11 +107,14 @@ public:
|
|||
bool fpuinitialized;
|
||||
|
||||
public:
|
||||
sigset_t signal_pending;
|
||||
sigset_t signal_mask;
|
||||
stack_t signal_stack;
|
||||
addr_t addrspace;
|
||||
sighandler_t sighandler;
|
||||
addr_t kernelstackpos;
|
||||
size_t kernelstacksize;
|
||||
bool kernelstackmalloced;
|
||||
bool pledged_destruction;
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
public:
|
||||
|
@ -121,11 +124,6 @@ public:
|
|||
|
||||
private:
|
||||
CPU::InterruptRegisters registers;
|
||||
Signal::Queue signalqueue;
|
||||
int currentsignal;
|
||||
int siglevel;
|
||||
int signums[SIG_NUM_LEVELS];
|
||||
CPU::InterruptRegisters sigregs[SIG_NUM_LEVELS];
|
||||
|
||||
public:
|
||||
void SaveRegisters(const CPU::InterruptRegisters* src);
|
||||
|
@ -133,16 +131,9 @@ public:
|
|||
void HandleSignal(CPU::InterruptRegisters* regs);
|
||||
void HandleSigreturn(CPU::InterruptRegisters* regs);
|
||||
bool DeliverSignal(int signum);
|
||||
bool DeliverSignalUnlocked(int signum);
|
||||
addr_t SwitchAddressSpace(addr_t newaddrspace);
|
||||
|
||||
private:
|
||||
void GotoOnSigKill(CPU::InterruptRegisters* regs);
|
||||
__attribute__((noreturn)) void OnSigKill();
|
||||
void LastPrayer();
|
||||
void SetHavePendingSignals();
|
||||
void HandleSignalFixupRegsCPU(CPU::InterruptRegisters* regs);
|
||||
void HandleSignalCPU(CPU::InterruptRegisters* regs);
|
||||
|
||||
};
|
||||
|
||||
Thread* CurrentThread();
|
||||
|
|
63
kernel/include/sortix/sigaction.h
Normal file
63
kernel/include/sortix/sigaction.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix 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.
|
||||
|
||||
Sortix 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
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/sigaction.h
|
||||
Declares struct sigaction and associated flags.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX_SIGACTION_H
|
||||
#define INCLUDE_SORTIX_SIGACTION_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sortix/siginfo.h>
|
||||
#include <sortix/sigset.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define SA_NOCLDSTOP (1<<0)
|
||||
#define SA_ONSTACK (1<<1)
|
||||
#define SA_RESETHAND (1<<2)
|
||||
#define SA_RESTART (1<<3)
|
||||
#define SA_SIGINFO (1<<4)
|
||||
#define SA_NOCLDWAIT (1<<5)
|
||||
#define SA_NODEFER (1<<6)
|
||||
#define SA_COOKIE (1<<7)
|
||||
|
||||
#define __SA_SUPPORTED_FLAGS (SA_NOCLDSTOP | SA_ONSTACK | SA_RESETHAND | \
|
||||
SA_RESTART | SA_SIGINFO | SA_NOCLDWAIT | \
|
||||
SA_NODEFER | SA_COOKIE)
|
||||
|
||||
struct sigaction
|
||||
{
|
||||
sigset_t sa_mask;
|
||||
__extension__ union
|
||||
{
|
||||
void (*sa_handler)(int);
|
||||
void (*sa_sigaction)(int, siginfo_t*, void*);
|
||||
void (*sa_sigaction_cookie)(int, siginfo_t*, void*, void*);
|
||||
};
|
||||
void* sa_cookie;
|
||||
int sa_flags;
|
||||
};
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -31,6 +31,8 @@
|
|||
#include <__/pthread.h>
|
||||
#endif
|
||||
|
||||
#include <sortix/sigval.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#if __STDC_HOSTED__
|
||||
|
@ -44,12 +46,6 @@ typedef __pthread_attr_t pthread_attr_t;
|
|||
#define SIGEV_SIGNAL 1
|
||||
#define SIGEV_THREAD 2
|
||||
|
||||
union sigval
|
||||
{
|
||||
int sival_int;
|
||||
void* sival_ptr;
|
||||
};
|
||||
|
||||
struct sigevent
|
||||
{
|
||||
int sigev_notify;
|
||||
|
|
96
kernel/include/sortix/siginfo.h
Normal file
96
kernel/include/sortix/siginfo.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix 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.
|
||||
|
||||
Sortix 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
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/siginfo.h
|
||||
Declares siginfo_t and associated flags.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX_SIGINFO_H
|
||||
#define INCLUDE_SORTIX_SIGINFO_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/__/types.h>
|
||||
|
||||
#include <sortix/sigval.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#ifndef __pid_t_defined
|
||||
#define __pid_t_defined
|
||||
typedef __pid_t pid_t;
|
||||
#endif
|
||||
|
||||
#ifndef __uid_t_defined
|
||||
#define __uid_t_defined
|
||||
typedef __uid_t uid_t;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
union sigval si_value;
|
||||
void* si_addr;
|
||||
pid_t si_pid;
|
||||
uid_t si_uid;
|
||||
int si_signo;
|
||||
int si_code;
|
||||
int si_errno;
|
||||
int si_status;
|
||||
} siginfo_t;
|
||||
|
||||
/* TODO: Decide appropriate values for these constants: */
|
||||
#define ILL_ILLOPC 1
|
||||
#define ILL_ILLOPN 2
|
||||
#define ILL_ILLADR 3
|
||||
#define ILL_ILLTRP 4
|
||||
#define ILL_PRVOPC 5
|
||||
#define ILL_PRVREG 6
|
||||
#define ILL_COPROC 7
|
||||
#define ILL_BADSTK 8
|
||||
#define FPE_INTDIV 9
|
||||
#define FPE_INTOVF 10
|
||||
#define FPE_FLTDIV 11
|
||||
#define FPE_FLTOVF 12
|
||||
#define FPE_FLTUND 13
|
||||
#define FPE_FLTRES 14
|
||||
#define FPE_FLTINV 15
|
||||
#define FPE_FLTSUB 16
|
||||
#define SEGV_MAPERR 17
|
||||
#define SEGV_ACCERR 18
|
||||
#define BUS_ADRALN 19
|
||||
#define BUS_ADRERR 20
|
||||
#define BUS_OBJERR 21
|
||||
#define TRAP_BRKPT 22
|
||||
#define TRAP_TRACE 23
|
||||
#define CLD_EXITED 24
|
||||
#define CLD_KILLED 25
|
||||
#define CLD_DUMPED 26
|
||||
#define CLD_TRAPPED 27
|
||||
#define CLD_STOPPED 29
|
||||
#define CLD_CONTINUED 30
|
||||
#define SI_USER 31
|
||||
#define SI_QUEUE 32
|
||||
#define SI_TIMER 33
|
||||
#define SI_ASYNCIO 34
|
||||
#define SI_MSGQ 35
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -25,59 +25,52 @@
|
|||
#ifndef SORTIX_INCLUDE_SIGNAL_H
|
||||
#define SORTIX_INCLUDE_SIGNAL_H
|
||||
|
||||
/* TODO: Yes, signals are implemented in a non-standard manner for now. */
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define SIGHUP 1 /* Hangup */
|
||||
#define SIGINT 2 /* Interrupt */
|
||||
#define SIGQUIT 3 /* Quit */
|
||||
#define SIGILL 4 /* Illegal Instruction */
|
||||
#define SIGTRAP 5 /* Trace/Breakpoint Trap */
|
||||
#define SIGABRT 6 /* Abort */
|
||||
#define SIGEMT 7 /* Emulation Trap */
|
||||
#define SIGFPE 8 /* Arithmetic Exception */
|
||||
#define SIGKILL 9 /* Killed */
|
||||
#define SIGBUS 10 /* Bus Error */
|
||||
#define SIGSEGV 11 /* Segmentation Fault */
|
||||
#define SIGSYS 12 /* Bad System Call */
|
||||
#define SIGPIPE 13 /* Broken Pipe */
|
||||
#define SIGALRM 14 /* Alarm Clock */
|
||||
#define SIGTERM 15 /* Terminated */
|
||||
#define SIGUSR1 16 /* User Signal 1 */
|
||||
#define SIGUSR2 17 /* User Signal 2 */
|
||||
#define SIGCHLD 18 /* Child Status */
|
||||
#define SIGPWR 19 /* Power Fail/Restart */
|
||||
#define SIGWINCH 20 /* Window Size Change */
|
||||
#define SIGURG 21 /* Urgent Socket Condition */
|
||||
#define SIGSTOP 23 /* Stopped (signal) */
|
||||
#define SIGTSTP 24 /* Stopped (user) */
|
||||
#define SIGCONT 25 /* Continued */
|
||||
#define SIGTTIN 26 /* Stopped (tty input) */
|
||||
#define SIGTTOU 27 /* Stopped (tty output) */
|
||||
#define SIGVTALRM 28 /* Virtual Timer Expired */
|
||||
#define SIGXCPU 30 /* CPU time limit exceeded */
|
||||
#define SIGXFSZ 31 /* File size limit exceeded */
|
||||
#define SIGWAITING 32 /* All LWPs blocked */
|
||||
#define SIGLWP 33 /* Virtual Interprocessor Interrupt for Threads Library */
|
||||
#define SIGAIO 34 /* Asynchronous I/O */
|
||||
#define SIGPROF 35
|
||||
#define SIG__NUM_DECLARED 36
|
||||
#define SIG_MAX_NUM 128
|
||||
#define NSIG SIG_MAX_NUM
|
||||
#define SIGHUP 1 /* Hangup */
|
||||
#define SIGINT 2 /* Interrupt */
|
||||
#define SIGQUIT 3 /* Quit */
|
||||
#define SIGILL 4 /* Illegal instruction */
|
||||
#define SIGTRAP 5 /* Trace/breakpoint trap */
|
||||
#define SIGABRT 6 /* Aborted */
|
||||
#define SIGBUS 7 /* Bus Error */
|
||||
#define SIGFPE 8 /* Floating point exception */
|
||||
#define SIGKILL 9 /* Killed */
|
||||
#define SIGUSR1 10 /* User defined signal 1 */
|
||||
#define SIGSEGV 11 /* Segmentation fault */
|
||||
#define SIGUSR2 12 /* User defined signal 2 */
|
||||
#define SIGPIPE 13 /* Broken pipe */
|
||||
#define SIGALRM 14 /* Alarm clock */
|
||||
#define SIGTERM 15 /* Terminated */
|
||||
#define SIGSYS 16 /* Bad system call */
|
||||
#define SIGCHLD 17 /* Child exited */
|
||||
#define SIGCONT 18 /* Continued */
|
||||
#define SIGSTOP 19 /* Stopped (signal) */
|
||||
#define SIGTSTP 20 /* Stopped */
|
||||
#define SIGTTIN 21 /* Stopped (tty input) */
|
||||
#define SIGTTOU 22 /* Stopped (tty output) */
|
||||
#define SIGURG 23 /* Urgent I/O condition */
|
||||
#define SIGXCPU 24 /* CPU time limit exceeded */
|
||||
#define SIGXFSZ 25 /* File size limit exceeded */
|
||||
#define SIGVTALRM 26 /* Virtual timer expired */
|
||||
#define SIGPWR 27 /* Power Fail/Restart */
|
||||
#define SIGWINCH 28 /* Window changed */
|
||||
#define SIGRTMIN 64 /* First user-available real-time signal. */
|
||||
#define SIGRTMAX 127 /* Last user-available real-time signal. */
|
||||
|
||||
#define SIG_PRIO_NORMAL 0
|
||||
#define SIG_PRIO_HIGH 1
|
||||
#define SIG_PRIO_STOP 2
|
||||
#define SIG_PRIO_CORE 3
|
||||
#define SIG_PRIO_KILL 4
|
||||
#define SIG_NUM_LEVELS 5
|
||||
#define __SIG_NUM_DECLARED 31
|
||||
#define __SIG_MAX_NUM 128
|
||||
|
||||
#define SIG_BLOCK 0
|
||||
#define SIG_UNBLOCK 1
|
||||
#define SIG_SETMASK 2
|
||||
#if defined(__is_sortix_kernel)
|
||||
#define SIG_NUM_DECLARED __SIG_NUM_DECLARED
|
||||
#define SIG_MAX_NUM __SIG_MAX_NUM
|
||||
#endif
|
||||
|
||||
#define SIG_ERR ((void (*)(int)) -1)
|
||||
#define SIG_DFL ((void (*)(int)) 0)
|
||||
#define SIG_IGN ((void (*)(int)) 1)
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
38
kernel/include/sortix/sigprocmask.h
Normal file
38
kernel/include/sortix/sigprocmask.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix 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.
|
||||
|
||||
Sortix 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
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/sigprocmask.h
|
||||
Declares flags for sigprocmask.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX_SIGPROCMASK_H
|
||||
#define INCLUDE_SORTIX_SIGPROCMASK_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define SIG_BLOCK 0
|
||||
#define SIG_UNBLOCK 1
|
||||
#define SIG_SETMASK 2
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -27,11 +27,13 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sortix/__/sigset.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long __val[(1024 / (8 * sizeof (unsigned long int)))];
|
||||
unsigned long __val[__SIGSET_NUM_SIGNALS / (8 * sizeof(unsigned long int))];
|
||||
} sigset_t;
|
||||
|
||||
__END_DECLS
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -17,34 +17,22 @@
|
|||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/x86/fork.h
|
||||
Declarations related to the fork family of system calls on x86 Sortix.
|
||||
sortix/sigval.h
|
||||
Declares union sigval.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_X86_FORK_H
|
||||
#define SORTIX_X86_FORK_H
|
||||
#ifndef INCLUDE_SORTIX_SIGVAL_H
|
||||
#define INCLUDE_SORTIX_SIGVAL_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct tforkregs_x86
|
||||
union sigval
|
||||
{
|
||||
uint32_t eip;
|
||||
uint32_t eax;
|
||||
uint32_t ebx;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
uint32_t edi;
|
||||
uint32_t esi;
|
||||
uint32_t esp;
|
||||
uint32_t ebp;
|
||||
uint32_t eflags;
|
||||
uint32_t fsbase;
|
||||
uint32_t gsbase;
|
||||
int sival_int;
|
||||
void* sival_ptr;
|
||||
};
|
||||
|
||||
__END_DECLS
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -17,43 +17,37 @@
|
|||
You should have received a copy of the GNU General Public License along with
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/x64/fork.h
|
||||
Declarations related to the fork family of system calls on x64 Sortix.
|
||||
sortix/stack.h
|
||||
Declares stack_t and associated flags.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef SORTIX_X64_FORK_H
|
||||
#define SORTIX_X64_FORK_H
|
||||
#ifndef INCLUDE_SORTIX_STACK_H
|
||||
#define INCLUDE_SORTIX_STACK_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <sys/__/types.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
struct tforkregs_x64
|
||||
#ifndef __size_t_defined
|
||||
#define __size_t_defined
|
||||
#define __need_size_t
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#define SS_ONSTACK (1<<0)
|
||||
#define SS_DISABLE (1<<1)
|
||||
|
||||
#define __SS_SUPPORTED_FLAGS (SS_ONSTACK | SS_DISABLE)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t rip;
|
||||
uint64_t rax;
|
||||
uint64_t rbx;
|
||||
uint64_t rcx;
|
||||
uint64_t rdx;
|
||||
uint64_t rdi;
|
||||
uint64_t rsi;
|
||||
uint64_t rsp;
|
||||
uint64_t rbp;
|
||||
uint64_t r8;
|
||||
uint64_t r9;
|
||||
uint64_t r10;
|
||||
uint64_t r11;
|
||||
uint64_t r12;
|
||||
uint64_t r13;
|
||||
uint64_t r14;
|
||||
uint64_t r15;
|
||||
uint64_t rflags;
|
||||
uint64_t fsbase;
|
||||
uint64_t gsbase;
|
||||
};
|
||||
void* ss_sp;
|
||||
size_t ss_size;
|
||||
int ss_flags;
|
||||
} stack_t;
|
||||
|
||||
__END_DECLS
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
#define INCLUDE_SORTIX_SYSCALLNUM_H
|
||||
|
||||
#define SYSCALL_BAD_SYSCALL 0
|
||||
#define SYSCALL_EXIT 1
|
||||
#define SYSCALL_EXIT 1 /* OBSOLETE */
|
||||
#define SYSCALL_SLEEP 2
|
||||
#define SYSCALL_USLEEP 3
|
||||
#define SYSCALL_PRINT_STRING 4
|
||||
|
@ -154,6 +154,11 @@
|
|||
#define SYSCALL_WRMSR 130
|
||||
#define SYSCALL_SCHED_YIELD 131
|
||||
#define SYSCALL_EXIT_THREAD 132
|
||||
#define SYSCALL_MAX_NUM 133 /* index of highest constant + 1 */
|
||||
#define SYSCALL_SIGACTION 133
|
||||
#define SYSCALL_SIGALTSTACK 134
|
||||
#define SYSCALL_SIGPENDING 135
|
||||
#define SYSCALL_SIGPROCMASK 136
|
||||
#define SYSCALL_SIGSUSPEND 137
|
||||
#define SYSCALL_MAX_NUM 138 /* index of highest constant + 1 */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -27,8 +27,15 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sys/__/types.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#ifndef __time_t_defined
|
||||
#define __time_t_defined
|
||||
typedef __time_t time_t;
|
||||
#endif
|
||||
|
||||
struct timespec
|
||||
{
|
||||
time_t tv_sec;
|
||||
|
|
155
kernel/include/sortix/ucontext.h
Normal file
155
kernel/include/sortix/ucontext.h
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
Sortix 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.
|
||||
|
||||
Sortix 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
|
||||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
sortix/ucontext.h
|
||||
Declares ucontext_t and associated values.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#ifndef INCLUDE_SORTIX_UCONTEXT_H
|
||||
#define INCLUDE_SORTIX_UCONTEXT_H
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sortix/sigset.h>
|
||||
#include <sortix/stack.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* Register declarations for i386 */
|
||||
#if defined(__i386__)
|
||||
typedef int greg_t;
|
||||
#define NGREG 23
|
||||
typedef greg_t gregset_t[NGREG];
|
||||
enum
|
||||
{
|
||||
REG_GS = 0,
|
||||
#define REG_GS REG_GS
|
||||
REG_FS,
|
||||
#define REG_FS REG_FS
|
||||
REG_ES,
|
||||
#define REG_ES REG_ES
|
||||
REG_DS,
|
||||
#define REG_DS REG_DS
|
||||
REG_EDI,
|
||||
#define REG_EDI REG_EDI
|
||||
REG_ESI,
|
||||
#define REG_ESI REG_ESI
|
||||
REG_EBP,
|
||||
#define REG_EBP REG_EBP
|
||||
REG_ESP,
|
||||
#define REG_ESP REG_ESP
|
||||
REG_EBX,
|
||||
#define REG_EBX REG_EBX
|
||||
REG_EDX,
|
||||
#define REG_EDX REG_EDX
|
||||
REG_ECX,
|
||||
#define REG_ECX REG_ECX
|
||||
REG_EAX,
|
||||
#define REG_EAX REG_EAX
|
||||
REG_EIP,
|
||||
#define REG_EIP REG_EIP
|
||||
REG_CS,
|
||||
#define REG_CS REG_CS
|
||||
REG_EFL,
|
||||
#define REG_EFL REG_EFL
|
||||
REG_SS,
|
||||
#define REG_SS REG_SS
|
||||
REG_CR2,
|
||||
#define REG_CR2 REG_CR2
|
||||
REG_FSBASE,
|
||||
#define REG_FSBASE REG_FSBASE
|
||||
REG_GSBASE,
|
||||
#define REG_GSBASE REG_GSBASE
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Register declarations for x86-64 */
|
||||
#if defined(__x86_64__)
|
||||
typedef long int greg_t;
|
||||
#define NGREG 23
|
||||
typedef greg_t gregset_t[NGREG];
|
||||
enum
|
||||
{
|
||||
REG_R8 = 0,
|
||||
#define REG_R8 REG_R8
|
||||
REG_R9,
|
||||
#define REG_R9 REG_R9
|
||||
REG_R10,
|
||||
#define REG_R10 REG_R10
|
||||
REG_R11,
|
||||
#define REG_R11 REG_R11
|
||||
REG_R12,
|
||||
#define REG_R12 REG_R12
|
||||
REG_R13,
|
||||
#define REG_R13 REG_R13
|
||||
REG_R14,
|
||||
#define REG_R14 REG_R14
|
||||
REG_R15,
|
||||
#define REG_R15 REG_R15
|
||||
REG_RDI,
|
||||
#define REG_RDI REG_RDI
|
||||
REG_RSI,
|
||||
#define REG_RSI REG_RSI
|
||||
REG_RBP,
|
||||
#define REG_RBP REG_RBP
|
||||
REG_RBX,
|
||||
#define REG_RBX REG_RBX
|
||||
REG_RDX,
|
||||
#define REG_RDX REG_RDX
|
||||
REG_RAX,
|
||||
#define REG_RAX REG_RAX
|
||||
REG_RCX,
|
||||
#define REG_RCX REG_RCX
|
||||
REG_RSP,
|
||||
#define REG_RSP REG_RSP
|
||||
REG_RIP,
|
||||
#define REG_RIP REG_RIP
|
||||
REG_EFL,
|
||||
#define REG_EFL REG_EFL
|
||||
REG_CSGSFS, /* Actually short cs, gs, fs, __pad0. */
|
||||
#define REG_CSGSFS REG_CSGSFS
|
||||
REG_CR2,
|
||||
#define REG_CR2 REG_CR2
|
||||
REG_FSBASE,
|
||||
#define REG_FSBASE REG_FSBASE
|
||||
REG_GSBASE,
|
||||
#define REG_GSBASE REG_GSBASE
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gregset_t gregs;
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
unsigned char fpuenv[512];
|
||||
#endif
|
||||
} mcontext_t;
|
||||
|
||||
typedef struct ucontext
|
||||
{
|
||||
struct ucontext* uc_link;
|
||||
sigset_t uc_sigmask;
|
||||
stack_t uc_stack;
|
||||
mcontext_t uc_mcontext;
|
||||
} ucontext_t;
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -27,21 +27,32 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sortix/__/wait.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define WNOHANG (1<<0)
|
||||
#define WCONTINUED (1<<0)
|
||||
#define WNOHANG (1<<1)
|
||||
#define WUNTRACED (1<<2)
|
||||
|
||||
#define WEXITSTATUS(status) ((status >> 8) & 0xFF)
|
||||
#define WTERMSIG(status) ((status >> 0) & 0x7F)
|
||||
#define WSTOPSIG(status) WTERMSIG(status)
|
||||
#define WIFEXITED(status) (WTERMSIG(status) == 0)
|
||||
#define WIFSIGNALED(status) (WTERMSIG(status) != 0)
|
||||
/*#define WIFCONTINUED(status) (WTERMSIG(status) == TODO)*/
|
||||
/*#define WIFSTOPPED(status) (WTERMSIG(status) == TODO)*/
|
||||
/*#define WIFCONTINUED(status) (WTERMSIG(status) == TODO)*/
|
||||
#define WNATURE_EXITED __WNATURE_EXITED
|
||||
#define WNATURE_SIGNALED __WNATURE_SIGNALED
|
||||
#define WNATURE_STOPPED __WNATURE_STOPPED
|
||||
#define WNATURE_CONTINUED __WNATURE_CONTINUED
|
||||
|
||||
#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
|
||||
#define W_STOPCODE(sig) ((sig) << 8 | 0x7f)
|
||||
#define WEXITSTATUS(status) __WEXITSTATUS(status)
|
||||
#define WTERMSIG(status) __WTERMSIG(status)
|
||||
#define WNATURE(status) __WNATURE(status)
|
||||
|
||||
#define WIFEXITED(status) __WIFEXITED(status)
|
||||
#define WIFSIGNALED(status) __WIFSIGNALED(status)
|
||||
#define WIFSTOPPED(status) __WIFSTOPPED(status)
|
||||
#define WIFCONTINUED(status) __WIFCONTINUED(status)
|
||||
|
||||
#define WSTOPSIG(status) __WSTOPSIG(status)
|
||||
|
||||
#define WCONSTRUCT(nature, exitcode, signal) \
|
||||
__WCONSTRUCT(nature, exitcode, signal)
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -187,17 +187,8 @@ void LogTerminal::ProcessKeystroke(int kbkey)
|
|||
{
|
||||
while ( linebuffer.CanBackspace() )
|
||||
linebuffer.Backspace();
|
||||
if ( foreground_pgid )
|
||||
{
|
||||
if ( Process* process = Process::Get(foreground_pgid) )
|
||||
process->DeliverGroupSignal(SIGINT);
|
||||
}
|
||||
else // TODO: Backwards compatibility, delete this.
|
||||
{
|
||||
pid_t pid = Process::HackGetForegroundProcess();
|
||||
if ( Process* process = Process::Get(pid) )
|
||||
process->DeliverSignal(SIGINT);
|
||||
}
|
||||
if ( Process* process = Process::Get(foreground_pgid) )
|
||||
process->DeliverGroupSignal(SIGINT);
|
||||
return;
|
||||
}
|
||||
if ( termmode & TERMMODE_SIGNAL && control && kbkey == KBKEY_D )
|
||||
|
|
|
@ -22,10 +22,13 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <msr.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
@ -99,6 +102,7 @@ Process::Process()
|
|||
grouplimbo = false;
|
||||
firstthread = NULL;
|
||||
threadlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
threads_exiting = false;
|
||||
ptrlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
idlock = KTHREAD_MUTEX_INITIALIZER;
|
||||
user_timers_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||
|
@ -107,7 +111,7 @@ Process::Process()
|
|||
segments_used = 0;
|
||||
segments_length = 0;
|
||||
segment_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||
exitstatus = -1;
|
||||
exit_code = -1;
|
||||
pid = AllocatePID();
|
||||
uid = euid = 0;
|
||||
gid = egid = 0;
|
||||
|
@ -115,6 +119,16 @@ Process::Process()
|
|||
nicelock = KTHREAD_MUTEX_INITIALIZER;
|
||||
nice = 0;
|
||||
resource_limits_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||
signal_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||
sigemptyset(&signal_pending);
|
||||
memset(&signal_actions, 0, sizeof(signal_actions));
|
||||
for ( int i = 0; i < SIG_MAX_NUM; i++ )
|
||||
{
|
||||
sigemptyset(&signal_actions[i].sa_mask);
|
||||
signal_actions[i].sa_handler = SIG_DFL;
|
||||
signal_actions[i].sa_cookie = NULL;
|
||||
signal_actions[i].sa_flags = 0;
|
||||
}
|
||||
for ( size_t i = 0; i < RLIMIT_NUM_DECLARED; i++ )
|
||||
{
|
||||
resource_limits[i].rlim_cur = RLIM_INFINITY;
|
||||
|
@ -415,7 +429,7 @@ void Process::NotifyChildExit(Process* child, bool zombify)
|
|||
void Process::NotifyNewZombies()
|
||||
{
|
||||
ScopedLock lock(&childlock);
|
||||
// TODO: Send SIGCHLD here?
|
||||
DeliverSignal(SIGCHLD);
|
||||
if ( zombiewaiting )
|
||||
kthread_cond_broadcast(&zombiecond);
|
||||
}
|
||||
|
@ -481,9 +495,9 @@ pid_t Process::Wait(pid_t thepid, int* user_status, int options)
|
|||
child_execute_clock.Advance(zombie->child_execute_clock.current_time);
|
||||
child_system_clock.Advance(zombie->child_system_clock.current_time);
|
||||
|
||||
int status = zombie->exitstatus;
|
||||
int status = zombie->exit_code;
|
||||
if ( status < 0 )
|
||||
status = W_EXITCODE(128 + SIGKILL, SIGKILL);
|
||||
status = WCONSTRUCT(WNATURE_SIGNALED, 128 + SIGKILL, SIGKILL);
|
||||
|
||||
kthread_mutex_lock(&zombie->groupparentlock);
|
||||
bool in_limbo = zombie->groupfirst && (zombie->grouplimbo = true);
|
||||
|
@ -504,12 +518,16 @@ static pid_t sys_waitpid(pid_t pid, int* user_status, int options)
|
|||
return CurrentProcess()->Wait(pid, user_status, options);
|
||||
}
|
||||
|
||||
void Process::Exit(int status)
|
||||
void Process::ExitThroughSignal(int signal)
|
||||
{
|
||||
ExitWithCode(WCONSTRUCT(WNATURE_SIGNALED, 128 + signal, signal));
|
||||
}
|
||||
|
||||
void Process::ExitWithCode(int requested_exit_code)
|
||||
{
|
||||
ScopedLock lock(&threadlock);
|
||||
// Status codes can only contain 8 bits according to ISO C and POSIX.
|
||||
if ( exitstatus == -1 )
|
||||
exitstatus = W_EXITCODE(status & 0xFF, 0);
|
||||
if ( exit_code == -1 )
|
||||
exit_code = requested_exit_code;
|
||||
|
||||
// Broadcast SIGKILL to all our threads which will begin our long path
|
||||
// of process termination. We simply can't stop the threads as they may
|
||||
|
@ -519,30 +537,6 @@ void Process::Exit(int status)
|
|||
t->DeliverSignal(SIGKILL);
|
||||
}
|
||||
|
||||
static int sys_exit(int status)
|
||||
{
|
||||
CurrentProcess()->Exit(status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Process::DeliverSignal(int signum)
|
||||
{
|
||||
// TODO: How to handle signals that kill the process?
|
||||
if ( firstthread )
|
||||
return firstthread->DeliverSignal(signum);
|
||||
return errno = EINIT, false;
|
||||
}
|
||||
|
||||
bool Process::DeliverGroupSignal(int signum)
|
||||
{
|
||||
ScopedLock lock(&groupparentlock);
|
||||
if ( !groupfirst )
|
||||
return errno = ESRCH, false;
|
||||
for ( Process* iter = groupfirst; iter; iter = iter->groupnext )
|
||||
iter->DeliverSignal(signum);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Process::AddChildProcess(Process* child)
|
||||
{
|
||||
ScopedLock mylock(&childlock);
|
||||
|
@ -740,6 +734,21 @@ void Process::ResetForExecute()
|
|||
|
||||
DeleteTimers();
|
||||
|
||||
for ( int i = 0; i < SIG_MAX_NUM; i++ )
|
||||
{
|
||||
signal_actions[i].sa_flags = 0;
|
||||
if ( signal_actions[i].sa_handler == SIG_DFL )
|
||||
continue;
|
||||
if ( signal_actions[i].sa_handler == SIG_IGN )
|
||||
continue;
|
||||
signal_actions[i].sa_handler = SIG_DFL;
|
||||
}
|
||||
|
||||
sigreturn = NULL;
|
||||
stack_t* signal_stack = &CurrentThread()->signal_stack;
|
||||
memset(signal_stack, 0, sizeof(*signal_stack));
|
||||
signal_stack->ss_flags = SS_DISABLE;
|
||||
|
||||
ResetAddressSpace();
|
||||
}
|
||||
|
||||
|
@ -833,6 +842,10 @@ int Process::Execute(const char* programname, const uint8_t* program,
|
|||
int tls_prot = PROT_READ | PROT_WRITE | PROT_KREAD | PROT_KWRITE | PROT_FORK;
|
||||
void* tls_hint = stack_hint;
|
||||
|
||||
size_t auxcode_size = Page::Size();
|
||||
int auxcode_prot = PROT_EXEC | PROT_READ | PROT_KREAD | PROT_KWRITE | PROT_FORK;
|
||||
void* auxcode_hint = stack_hint;
|
||||
|
||||
size_t arg_size = 0;
|
||||
|
||||
size_t argv_size = sizeof(char*) * (argc + 1);
|
||||
|
@ -850,13 +863,15 @@ int Process::Execute(const char* programname, const uint8_t* program,
|
|||
struct segment stack_segment;
|
||||
struct segment raw_tls_segment;
|
||||
struct segment tls_segment;
|
||||
struct segment auxcode_segment;
|
||||
|
||||
kthread_mutex_lock(&segment_lock);
|
||||
|
||||
if ( !(MapSegment(&arg_segment, stack_hint, arg_size, 0, stack_prot) &&
|
||||
MapSegment(&stack_segment, stack_hint, stack_size, 0, stack_prot) &&
|
||||
MapSegment(&raw_tls_segment, raw_tls_hint, raw_tls_size, 0, raw_tls_prot) &&
|
||||
MapSegment(&tls_segment, tls_hint, tls_size, 0, tls_prot)) )
|
||||
MapSegment(&tls_segment, tls_hint, tls_size, 0, tls_prot) &&
|
||||
MapSegment(&auxcode_segment, auxcode_hint, auxcode_size, 0, auxcode_prot)) )
|
||||
{
|
||||
kthread_mutex_unlock(&segment_lock);
|
||||
ResetForExecute();
|
||||
|
@ -926,6 +941,20 @@ int Process::Execute(const char* programname, const uint8_t* program,
|
|||
wrmsr(MSRID_FSBASE, (uint64_t) uthread);
|
||||
#endif
|
||||
|
||||
uint8_t* auxcode = (uint8_t*) auxcode_segment.addr;
|
||||
#if defined(__i386__)
|
||||
sigreturn = (void (*)(void)) &auxcode[0];
|
||||
auxcode[0] = 0xCD; /* int .... */
|
||||
auxcode[1] = 0x83; /* ... $131 */
|
||||
#elif defined(__x86_64__)
|
||||
sigreturn = (void (*)(void)) &auxcode[0];
|
||||
auxcode[0] = 0xCD; /* int .... */
|
||||
auxcode[1] = 0x83; /* ... $131 */
|
||||
#else
|
||||
(void) auxcode;
|
||||
#warning "You need to initialize auxcode with a sigreturn routine"
|
||||
#endif
|
||||
|
||||
dtable->OnExecute();
|
||||
|
||||
ExecuteCPU(argc, target_argv, envc, target_envp, stack_segment.addr + stack_segment.size, entry, regs);
|
||||
|
@ -1076,9 +1105,9 @@ cleanup_done:
|
|||
return result;
|
||||
}
|
||||
|
||||
static pid_t sys_tfork(int flags, tforkregs_t* user_regs)
|
||||
static pid_t sys_tfork(int flags, struct tfork* user_regs)
|
||||
{
|
||||
tforkregs_t regs;
|
||||
struct tfork regs;
|
||||
if ( !CopyFromUser(®s, user_regs, sizeof(regs)) )
|
||||
return -1;
|
||||
|
||||
|
@ -1092,6 +1121,9 @@ static pid_t sys_tfork(int flags, tforkregs_t* user_regs)
|
|||
if ( !(making_thread || making_process) )
|
||||
return errno = ENOSYS, -1;
|
||||
|
||||
if ( regs.altstack.ss_flags & ~__SS_SUPPORTED_FLAGS )
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
CPU::InterruptRegisters cpuregs;
|
||||
InitializeThreadRegisters(&cpuregs, ®s);
|
||||
|
||||
|
@ -1124,7 +1156,8 @@ static pid_t sys_tfork(int flags, tforkregs_t* user_regs)
|
|||
thread->kernelstackpos = (addr_t) newkernelstack;
|
||||
thread->kernelstacksize = curthread->kernelstacksize;
|
||||
thread->kernelstackmalloced = true;
|
||||
thread->sighandler = curthread->sighandler;
|
||||
memcpy(&thread->signal_mask, ®s.sigmask, sizeof(sigset_t));
|
||||
memcpy(&thread->signal_stack, ®s.altstack, sizeof(stack_t));
|
||||
|
||||
StartKernelThread(thread);
|
||||
|
||||
|
@ -1233,23 +1266,6 @@ pid_t Process::AllocatePID()
|
|||
return nextpidtoallocate++;
|
||||
}
|
||||
|
||||
// TODO: This is not thread safe.
|
||||
pid_t Process::HackGetForegroundProcess()
|
||||
{
|
||||
for ( pid_t i = nextpidtoallocate; 1 <= i; i-- )
|
||||
{
|
||||
Process* process = Get(i);
|
||||
if ( !process )
|
||||
continue;
|
||||
if ( process->pid <= 1 )
|
||||
continue;
|
||||
if ( process->iszombie )
|
||||
continue;
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ProcessCompare(Process* a, Process* b)
|
||||
{
|
||||
if ( a->pid < b->pid )
|
||||
|
@ -1375,7 +1391,6 @@ static mode_t sys_getumask(void)
|
|||
void Process::Init()
|
||||
{
|
||||
Syscall::Register(SYSCALL_EXECVE, (void*) sys_execve);
|
||||
Syscall::Register(SYSCALL_EXIT, (void*) sys_exit);
|
||||
Syscall::Register(SYSCALL_GETPAGESIZE, (void*) sys_getpagesize);
|
||||
Syscall::Register(SYSCALL_GETPGID, (void*) sys_getpgid);
|
||||
Syscall::Register(SYSCALL_GETPID, (void*) sys_getpid);
|
||||
|
|
|
@ -151,10 +151,13 @@ void Switch(CPU::InterruptRegisters* regs)
|
|||
assert(premagic == SCHED_MAGIC);
|
||||
assert(postmagic == SCHED_MAGIC);
|
||||
DoActualSwitch(regs);
|
||||
if ( regs->signal_pending && regs->InUserspace() )
|
||||
Signal::Dispatch(regs);
|
||||
assert(premagic == SCHED_MAGIC);
|
||||
assert(postmagic == SCHED_MAGIC);
|
||||
if ( regs->signal_pending && regs->InUserspace() )
|
||||
{
|
||||
Interrupt::Enable();
|
||||
Signal::DispatchHandler(regs, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
const bool DEBUG_BEGINCTXSWITCH = false;
|
||||
|
|
|
@ -18,116 +18,833 @@
|
|||
Sortix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
signal.cpp
|
||||
Classes and functions making it easier to handle Unix signals.
|
||||
Asynchronous user-space thread interruption.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <sortix/sigaction.h>
|
||||
#include <sortix/signal.h>
|
||||
#include <sortix/sigset.h>
|
||||
#include <sortix/stack.h>
|
||||
#include <sortix/ucontext.h>
|
||||
|
||||
#include <sortix/kernel/copy.h>
|
||||
#include <sortix/kernel/interrupt.h>
|
||||
#include <sortix/kernel/kernel.h>
|
||||
#include <sortix/kernel/panic.h>
|
||||
#include <sortix/kernel/process.h>
|
||||
#include <sortix/kernel/signal.h>
|
||||
#include <sortix/kernel/syscall.h>
|
||||
#include <sortix/kernel/thread.h>
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
#include "x86-family/float.h"
|
||||
#endif
|
||||
|
||||
namespace Sortix {
|
||||
|
||||
sigset_t default_ignored_signals;
|
||||
sigset_t default_stop_signals;
|
||||
sigset_t unblockable_signals;
|
||||
|
||||
// A per-cpu value whether a signal is pending in the running task.
|
||||
extern "C" { volatile unsigned long asm_signal_is_pending = 0; }
|
||||
|
||||
void UpdatePendingSignals(Thread* thread) // thread->process->signal_lock held
|
||||
{
|
||||
struct sigaction* signal_actions = thread->process->signal_actions;
|
||||
|
||||
// Determine which signals wouldn't be ignored if received.
|
||||
sigset_t handled_signals;
|
||||
sigemptyset(&handled_signals);
|
||||
for ( int i = 1; i < SIG_MAX_NUM; i++ )
|
||||
{
|
||||
if ( signal_actions[i].sa_handler == SIG_IGN )
|
||||
continue;
|
||||
if ( signal_actions[i].sa_handler == SIG_DFL &&
|
||||
sigismember(&default_ignored_signals, i) )
|
||||
continue;
|
||||
// TODO: A process that is a member of an orphaned process group shall
|
||||
// not be allowed to stop in response to the SIGTSTP, SIGTTIN, or
|
||||
// SIGTTOU signals. In cases where delivery of one of these
|
||||
// signals would stop such a process, the signal shall be
|
||||
// discarded.
|
||||
if ( /* is member of an orphaned process group */ false &&
|
||||
signal_actions[i].sa_handler == SIG_DFL &&
|
||||
sigismember(&default_stop_signals, i) )
|
||||
continue;
|
||||
sigaddset(&handled_signals, i);
|
||||
}
|
||||
|
||||
// TODO: Handle that signals can be pending process-wide!
|
||||
|
||||
// Discard all requested signals that would be ignored if delivered.
|
||||
sigandset(&thread->signal_pending, &thread->signal_pending, &handled_signals);
|
||||
|
||||
// Determine which signals are not blocked.
|
||||
sigset_t permitted_signals;
|
||||
signotset(&permitted_signals, &thread->signal_mask);
|
||||
sigorset(&permitted_signals, &permitted_signals, &unblockable_signals);
|
||||
|
||||
// Determine which signals can currently be delivered to this thread.
|
||||
sigset_t deliverable_signals;
|
||||
sigandset(&deliverable_signals, &permitted_signals, &thread->signal_pending);
|
||||
|
||||
// Determine whether any signals can be delivered.
|
||||
unsigned long is_pending = !sigisemptyset(&deliverable_signals) ? 1 : 0;
|
||||
|
||||
// Store whether a signal is pending in the virtual register.
|
||||
if ( thread == CurrentThread() )
|
||||
asm_signal_is_pending = is_pending;
|
||||
else
|
||||
thread->registers.signal_pending = is_pending;
|
||||
}
|
||||
|
||||
static
|
||||
int sys_sigaction(int signum,
|
||||
const struct sigaction* user_newact,
|
||||
struct sigaction* user_oldact)
|
||||
{
|
||||
if ( signum < 0 || signum == 0 /* null signal */ || SIG_MAX_NUM <= signum )
|
||||
return errno = EINVAL;
|
||||
|
||||
Process* process = CurrentProcess();
|
||||
ScopedLock lock(&process->signal_lock);
|
||||
|
||||
struct sigaction* kact = &process->signal_actions[signum];
|
||||
|
||||
// Let the caller know the previous action.
|
||||
if ( user_oldact )
|
||||
{
|
||||
if ( !CopyToUser(user_oldact, kact, sizeof(struct sigaction)) )
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Retrieve and validate the new signal action.
|
||||
if ( user_newact )
|
||||
{
|
||||
struct sigaction newact;
|
||||
if ( !CopyFromUser(&newact, user_newact, sizeof(struct sigaction)) )
|
||||
return -1;
|
||||
|
||||
if ( newact.sa_flags & ~__SA_SUPPORTED_FLAGS )
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
if ( newact.sa_handler == SIG_ERR )
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
memcpy(kact, &newact, sizeof(struct sigaction));
|
||||
|
||||
// Signals may become discarded because of the new handler.
|
||||
ScopedLock threads_lock(&process->threadlock);
|
||||
for ( Thread* t = process->firstthread; t; t = t->nextsibling )
|
||||
UpdatePendingSignals(t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sys_sigaltstack(const stack_t* user_newstack, stack_t* user_oldstack)
|
||||
{
|
||||
Thread* thread = CurrentThread();
|
||||
|
||||
if ( user_oldstack )
|
||||
{
|
||||
if ( !CopyToUser(user_oldstack, &thread->signal_stack, sizeof(stack_t)) )
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( user_newstack )
|
||||
{
|
||||
stack_t newstack;
|
||||
if ( !CopyFromUser(&newstack, user_newstack, sizeof(stack_t)) )
|
||||
return -1;
|
||||
|
||||
if ( newstack.ss_flags & ~__SS_SUPPORTED_FLAGS )
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
memcpy(&thread->signal_stack, &newstack, sizeof(stack_t));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sys_sigpending(sigset_t* set)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
Thread* thread = CurrentThread();
|
||||
|
||||
ScopedLock lock(&process->signal_lock);
|
||||
|
||||
// TODO: What about process-wide signals?
|
||||
|
||||
return CopyToUser(set, &thread->signal_pending, sizeof(sigset_t)) ? 0 : -1;
|
||||
}
|
||||
|
||||
static
|
||||
int sys_sigprocmask(int how, const sigset_t* user_set, sigset_t* user_oldset)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
Thread* thread = CurrentThread();
|
||||
|
||||
// TODO: Signal masks are a per-thread property, perhaps this should be
|
||||
// locked in another manner?
|
||||
ScopedLock lock(&process->signal_lock);
|
||||
|
||||
// Let the caller know the previous signal mask.
|
||||
if ( user_oldset )
|
||||
{
|
||||
if ( !CopyToUser(user_oldset, &thread->signal_mask, sizeof(sigset_t)) )
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Update the current signal mask according to how.
|
||||
if ( user_set )
|
||||
{
|
||||
sigset_t set;
|
||||
if ( !CopyFromUser(&set, user_set, sizeof(sigset_t)) )
|
||||
return -1;
|
||||
|
||||
switch ( how )
|
||||
{
|
||||
case SIG_BLOCK:
|
||||
sigorset(&thread->signal_mask, &thread->signal_mask, &set);
|
||||
break;
|
||||
case SIG_UNBLOCK:
|
||||
signotset(&set, &set);
|
||||
sigandset(&thread->signal_mask, &thread->signal_mask, &set);
|
||||
break;
|
||||
case SIG_SETMASK:
|
||||
memcpy(&thread->signal_mask, &set, sizeof(sigset_t));
|
||||
break;
|
||||
default:
|
||||
return errno = EINVAL, -1;
|
||||
};
|
||||
|
||||
UpdatePendingSignals(thread);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sys_sigsuspend(const sigset_t* set)
|
||||
{
|
||||
Process* process = CurrentProcess();
|
||||
Thread* thread = CurrentThread();
|
||||
|
||||
sigset_t old_signal_mask;
|
||||
sigset_t new_signal_mask;
|
||||
|
||||
ScopedLock lock(&process->signal_lock);
|
||||
|
||||
// Only accept signals from the user-provided set if given.
|
||||
if ( set )
|
||||
{
|
||||
if ( !CopyFromUser(&new_signal_mask, set, sizeof(sigset_t)) )
|
||||
return -1;
|
||||
memcpy(&old_signal_mask, &thread->signal_mask, sizeof(sigset_t));
|
||||
memcpy(&thread->signal_mask, &new_signal_mask, sizeof(sigset_t));
|
||||
UpdatePendingSignals(thread);
|
||||
}
|
||||
|
||||
// Wait for a signal to happen or otherwise never halt.
|
||||
kthread_cond_t never_triggered = KTHREAD_COND_INITIALIZER;
|
||||
while ( !Signal::IsPending() )
|
||||
kthread_cond_wait_signal(&never_triggered, &process->signal_lock);
|
||||
|
||||
// Restore the previous signal mask if the user gave its own set to wait on.
|
||||
if ( set )
|
||||
{
|
||||
memcpy(&thread->signal_mask, &old_signal_mask, sizeof(sigset_t));
|
||||
UpdatePendingSignals(thread);
|
||||
}
|
||||
|
||||
// The system call never halts or it halts because a signal interrupted it.
|
||||
return errno = EINTR, -1;
|
||||
}
|
||||
|
||||
static int sys_kill(pid_t pid, int signum)
|
||||
{
|
||||
// Protect the kernel process.
|
||||
if ( !pid )
|
||||
return errno = EPERM, -1;
|
||||
|
||||
// TODO: Implement that pid == -1 means all processes!
|
||||
bool process_group = pid < 0 ? (pid = -pid, true) : false;
|
||||
|
||||
// TODO: Race condition: The process could be deleted while we use it.
|
||||
Process* process = Process::Get(pid);
|
||||
if ( !process )
|
||||
return errno = ESRCH, -1;
|
||||
|
||||
// TODO: Protect init?
|
||||
// TODO: Check for permission.
|
||||
// TODO: Check for zombies.
|
||||
|
||||
if ( process_group )
|
||||
{
|
||||
if ( !process->DeliverGroupSignal(signum) && errno != ESIGPENDING )
|
||||
return -1;
|
||||
return errno = 0, 0;
|
||||
}
|
||||
|
||||
if ( !process->DeliverSignal(signum) && errno != ESIGPENDING )
|
||||
return -1;
|
||||
return errno = 0, 0;
|
||||
}
|
||||
|
||||
bool Process::DeliverGroupSignal(int signum)
|
||||
{
|
||||
ScopedLock lock(&groupparentlock);
|
||||
if ( !groupfirst )
|
||||
return errno = ESRCH, false;
|
||||
for ( Process* iter = groupfirst; iter; iter = iter->groupnext )
|
||||
{
|
||||
int saved_errno = errno;
|
||||
if ( !iter->DeliverSignal(signum) && errno != ESIGPENDING )
|
||||
{
|
||||
// This is not currently an error condition.
|
||||
}
|
||||
errno = saved_errno;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Process::DeliverSignal(int signum)
|
||||
{
|
||||
ScopedLock lock(&threadlock);
|
||||
|
||||
if ( !firstthread )
|
||||
return errno = EINIT, false;
|
||||
|
||||
// Broadcast particular signals to all the threads in the process.
|
||||
if ( signum == SIGCONT || signum == SIGSTOP || signum == SIGKILL )
|
||||
{
|
||||
int saved_errno = errno;
|
||||
for ( Thread* t = firstthread; t; t = t->nextsibling )
|
||||
{
|
||||
if ( !t->DeliverSignal(signum) && errno != ESIGPENDING )
|
||||
{
|
||||
// This is not currently an error condition.
|
||||
}
|
||||
}
|
||||
errno = saved_errno;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Route the signal to a suitable thread that accepts it.
|
||||
// TODO: This isn't how signals should be routed to a particular thread.
|
||||
if ( CurrentThread()->process == this )
|
||||
return CurrentThread()->DeliverSignal(signum);
|
||||
return firstthread->DeliverSignal(signum);
|
||||
}
|
||||
|
||||
static int sys_raise(int signum)
|
||||
{
|
||||
if ( !CurrentThread()->DeliverSignal(signum) && errno != ESIGPENDING )
|
||||
return -1;
|
||||
return errno = 0, 0;
|
||||
}
|
||||
|
||||
bool Thread::DeliverSignal(int signum)
|
||||
{
|
||||
ScopedLock lock(&process->signal_lock);
|
||||
return DeliverSignalUnlocked(signum);
|
||||
}
|
||||
|
||||
bool Thread::DeliverSignalUnlocked(int signum) // thread->process->signal_lock held
|
||||
{
|
||||
if ( signum <= 0 || SIG_MAX_NUM <= signum )
|
||||
return errno = EINVAL, false;
|
||||
|
||||
// Discard the null signal, which does error checking, but doesn't actually
|
||||
// deliver a signal to the process or thread.
|
||||
if ( signum == 0 )
|
||||
return true;
|
||||
|
||||
if ( sigismember(&signal_pending, signum) )
|
||||
return errno = ESIGPENDING, false;
|
||||
|
||||
sigaddset(&signal_pending, signum);
|
||||
if ( signum == SIGSTOP || signum == SIGTSTP ||
|
||||
signum == SIGTTIN || signum == SIGTTOU )
|
||||
sigdelset(&signal_pending, SIGCONT);
|
||||
if ( signum == SIGCONT )
|
||||
{
|
||||
sigdelset(&signal_pending, SIGSTOP);
|
||||
sigdelset(&signal_pending, SIGTSTP);
|
||||
sigdelset(&signal_pending, SIGTTIN);
|
||||
sigdelset(&signal_pending, SIGTTOU);
|
||||
}
|
||||
UpdatePendingSignals(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int PickImportantSignal(const sigset_t* set)
|
||||
{
|
||||
if ( sigismember(set, SIGKILL) )
|
||||
return SIGKILL;
|
||||
if ( sigismember(set, SIGSTOP) )
|
||||
return SIGSTOP;
|
||||
for ( int i = 1; i < SIG_MAX_NUM; i++ )
|
||||
if ( sigismember(set, i) )
|
||||
return i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void EncodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs)
|
||||
{
|
||||
memset(mctx, 0, sizeof(*mctx));
|
||||
#if defined(__i386__)
|
||||
// TODO: REG_GS
|
||||
// TODO: REG_FS
|
||||
// TODO: REG_ES
|
||||
// TODO: REG_DS
|
||||
mctx->gregs[REG_EDI] = regs->edi;
|
||||
mctx->gregs[REG_ESI] = regs->esi;
|
||||
mctx->gregs[REG_EBP] = regs->ebp;
|
||||
mctx->gregs[REG_ESP] = regs->esp;
|
||||
mctx->gregs[REG_EBX] = regs->ebx;
|
||||
mctx->gregs[REG_EDX] = regs->edx;
|
||||
mctx->gregs[REG_ECX] = regs->ecx;
|
||||
mctx->gregs[REG_EAX] = regs->eax;
|
||||
mctx->gregs[REG_EIP] = regs->eip;
|
||||
// TODO: REG_CS
|
||||
mctx->gregs[REG_EFL] = regs->eflags & 0x0000FFFF;
|
||||
mctx->gregs[REG_CR2] = regs->cr2;
|
||||
// TODO: REG_SS
|
||||
Float::Yield();
|
||||
memcpy(mctx->fpuenv, CurrentThread()->fpuenvaligned, 512);
|
||||
#elif defined(__x86_64__)
|
||||
mctx->gregs[REG_R8] = regs->r8;
|
||||
mctx->gregs[REG_R9] = regs->r9;
|
||||
mctx->gregs[REG_R10] = regs->r10;
|
||||
mctx->gregs[REG_R11] = regs->r11;
|
||||
mctx->gregs[REG_R12] = regs->r12;
|
||||
mctx->gregs[REG_R13] = regs->r13;
|
||||
mctx->gregs[REG_R14] = regs->r14;
|
||||
mctx->gregs[REG_R15] = regs->r15;
|
||||
mctx->gregs[REG_RDI] = regs->rdi;
|
||||
mctx->gregs[REG_RSI] = regs->rsi;
|
||||
mctx->gregs[REG_RBP] = regs->rbp;
|
||||
mctx->gregs[REG_RBX] = regs->rbx;
|
||||
mctx->gregs[REG_RDX] = regs->rdx;
|
||||
mctx->gregs[REG_RAX] = regs->rax;
|
||||
mctx->gregs[REG_RCX] = regs->rcx;
|
||||
mctx->gregs[REG_RSP] = regs->rsp;
|
||||
mctx->gregs[REG_RIP] = regs->rip;
|
||||
mctx->gregs[REG_EFL] = regs->rflags & 0x000000000000FFFF;
|
||||
// TODO: REG_CSGSFS.
|
||||
mctx->gregs[REG_CR2] = regs->cr2;
|
||||
mctx->gregs[REG_FSBASE] = 0x0;
|
||||
mctx->gregs[REG_GSBASE] = 0x0;
|
||||
Float::Yield();
|
||||
memcpy(mctx->fpuenv, CurrentThread()->fpuenvaligned, 512);
|
||||
#else
|
||||
#error "You need to implement conversion to mcontext"
|
||||
#endif
|
||||
}
|
||||
|
||||
static void DecodeMachineContext(mcontext_t* mctx, CPU::InterruptRegisters* regs)
|
||||
{
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
unsigned long user_flags = FLAGS_CARRY | FLAGS_PARITY | FLAGS_AUX
|
||||
| FLAGS_ZERO | FLAGS_SIGN | FLAGS_DIRECTION
|
||||
| FLAGS_OVERFLOW;
|
||||
#endif
|
||||
#if defined(__i386__)
|
||||
regs->edi = mctx->gregs[REG_EDI];
|
||||
regs->esi = mctx->gregs[REG_ESI];
|
||||
regs->ebp = mctx->gregs[REG_EBP];
|
||||
regs->esp = mctx->gregs[REG_ESP];
|
||||
regs->ebx = mctx->gregs[REG_EBX];
|
||||
regs->edx = mctx->gregs[REG_EDX];
|
||||
regs->ecx = mctx->gregs[REG_ECX];
|
||||
regs->eax = mctx->gregs[REG_EAX];
|
||||
regs->eip = mctx->gregs[REG_EIP];
|
||||
regs->eflags &= ~user_flags;
|
||||
regs->eflags |= mctx->gregs[REG_EFL] & user_flags;
|
||||
regs->cr2 = mctx->gregs[REG_CR2];
|
||||
Float::Yield();
|
||||
memcpy(CurrentThread()->fpuenvaligned, mctx->fpuenv, 512);
|
||||
#elif defined(__x86_64__)
|
||||
regs->r8 = mctx->gregs[REG_R8];
|
||||
regs->r9 = mctx->gregs[REG_R9];
|
||||
regs->r10 = mctx->gregs[REG_R10];
|
||||
regs->r11 = mctx->gregs[REG_R11];
|
||||
regs->r12 = mctx->gregs[REG_R12];
|
||||
regs->r13 = mctx->gregs[REG_R13];
|
||||
regs->r14 = mctx->gregs[REG_R14];
|
||||
regs->r15 = mctx->gregs[REG_R15];
|
||||
regs->rdi = mctx->gregs[REG_RDI];
|
||||
regs->rsi = mctx->gregs[REG_RSI];
|
||||
regs->rbp = mctx->gregs[REG_RBP];
|
||||
regs->rbx = mctx->gregs[REG_RBX];
|
||||
regs->rdx = mctx->gregs[REG_RDX];
|
||||
regs->rax = mctx->gregs[REG_RAX];
|
||||
regs->rcx = mctx->gregs[REG_RCX];
|
||||
regs->rsp = mctx->gregs[REG_RSP];
|
||||
regs->rip = mctx->gregs[REG_RIP];
|
||||
regs->rflags &= ~user_flags;
|
||||
regs->rflags |= mctx->gregs[REG_EFL] & user_flags;
|
||||
regs->cr2 = mctx->gregs[REG_CR2];
|
||||
Float::Yield();
|
||||
memcpy(CurrentThread()->fpuenvaligned, mctx->fpuenv, 512);
|
||||
#else
|
||||
#error "You need to implement conversion to mcontext"
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__i386__)
|
||||
struct stack_frame
|
||||
{
|
||||
unsigned long sigreturn;
|
||||
int signum_param;
|
||||
siginfo_t* siginfo_param;
|
||||
ucontext_t* ucontext_param;
|
||||
void* cookie_param;
|
||||
siginfo_t siginfo;
|
||||
ucontext_t ucontext;
|
||||
};
|
||||
#elif defined(__x86_64__)
|
||||
struct stack_frame
|
||||
{
|
||||
unsigned long sigreturn;
|
||||
siginfo_t siginfo;
|
||||
ucontext_t ucontext;
|
||||
};
|
||||
#else
|
||||
#error "You need to implement struct stack_frame"
|
||||
#endif
|
||||
|
||||
void Thread::HandleSignal(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
assert(Interrupt::IsEnabled());
|
||||
assert(this == CurrentThread());
|
||||
|
||||
ScopedLock lock(&process->signal_lock);
|
||||
|
||||
assert(process->sigreturn);
|
||||
|
||||
retry_another_signal:
|
||||
|
||||
// Determine which signals are not blocked.
|
||||
sigset_t permitted_signals;
|
||||
signotset(&permitted_signals, &signal_mask);
|
||||
sigorset(&permitted_signals, &permitted_signals, &unblockable_signals);
|
||||
|
||||
// Determine which signals can currently be delivered to this thread.
|
||||
sigset_t deliverable_signals;
|
||||
sigandset(&deliverable_signals, &permitted_signals, &signal_pending);
|
||||
|
||||
// Decide which signal to deliver to the thread.
|
||||
int signum = PickImportantSignal(&deliverable_signals);
|
||||
if ( !signum )
|
||||
return;
|
||||
|
||||
// Unmark the selected signal as pending.
|
||||
sigdelset(&signal_pending, signum);
|
||||
UpdatePendingSignals(this);
|
||||
regs->signal_pending = asm_signal_is_pending;
|
||||
|
||||
// Destroy the current thread if the signal is critical.
|
||||
if ( signum == SIGKILL )
|
||||
{
|
||||
lock.Reset();
|
||||
kthread_exit();
|
||||
}
|
||||
|
||||
struct sigaction* action = &process->signal_actions[signum];
|
||||
|
||||
// Stop the current thread upon receipt of a stop signal that isn't handled
|
||||
// or cannot be handled (SIGSTOP).
|
||||
if ( (action->sa_handler == SIG_DFL &&
|
||||
sigismember(&default_stop_signals, signum) ) ||
|
||||
signum == SIGSTOP )
|
||||
{
|
||||
Log::PrintF("%s:%u: `%s' FIXME SIGSTOP\n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
|
||||
// TODO: Stop the current process.
|
||||
// TODO: Deliver SIGCHLD to the parent except if SA_NOCLDSTOP is set in
|
||||
// the parent's SIGCHLD sigaction.
|
||||
// TODO: SIGCHLD should not be delivered until all the threads in the
|
||||
// process has received SIGSTOP and stopped?
|
||||
// TODO: SIGKILL must still be deliverable to a stopped process.
|
||||
}
|
||||
|
||||
// Resume the current thread upon receipt of SIGCONT.
|
||||
if ( signum == SIGCONT )
|
||||
{
|
||||
Log::PrintF("%s:%u: `%s' FIXME SIGCONT\n", __FILE__, __LINE__, __PRETTY_FUNCTION__);
|
||||
// TODO: Resume the current process.
|
||||
// TODO: Can SIGCONT be masked?
|
||||
// TODO: Can SIGCONT be handled?
|
||||
// TODO: Can SIGCONT be ignored?
|
||||
// TODO: Deliver SIGCHLD to the parent except if SA_NOCLDSTOP is set in
|
||||
// the parent's SIGCHLD sigaction.
|
||||
}
|
||||
|
||||
// Signals that would be ignored are already filtered away at this point.
|
||||
assert(action->sa_handler != SIG_IGN);
|
||||
assert(action->sa_handler != SIG_DFL || !sigismember(&default_ignored_signals, signum));
|
||||
|
||||
// The default action must be to terminate the process. Signals that are
|
||||
// ignored by default got discarded earlier.
|
||||
if ( action->sa_handler == SIG_DFL )
|
||||
{
|
||||
kthread_mutex_unlock(&process->signal_lock);
|
||||
process->ExitThroughSignal(signum);
|
||||
kthread_mutex_lock(&process->signal_lock);
|
||||
goto retry_another_signal;
|
||||
}
|
||||
|
||||
// At this point we have to attempt to invoke the user-space signal handler,
|
||||
// which will then return control to us through sigreturn. However, we can't
|
||||
// save the kernel state because 1) we can't trust the user-space stack 2)
|
||||
// we can't rely on the kernel stack being intact as the signal handler may
|
||||
// invoke system calls. For those reasons, we'll have to modify the saved
|
||||
// registers so they restore a user-space state. We can do this because
|
||||
// threads in the kernel cannot be delivered signals except when returning
|
||||
// from a system call, so we'll simply save the state that would have been
|
||||
// returned to user-space had no signal occured.
|
||||
if ( !regs->InUserspace() )
|
||||
{
|
||||
#if defined(__i386__)
|
||||
uint32_t* params = (uint32_t*) regs->ebx;
|
||||
regs->eip = params[0];
|
||||
regs->eflags = params[2];
|
||||
regs->esp = params[3];
|
||||
regs->cs = UCS | URPL;
|
||||
regs->ds = UDS | URPL;
|
||||
regs->ss = UDS | URPL;
|
||||
#elif defined(__x86_64__)
|
||||
regs->rip = regs->rdi;
|
||||
regs->rflags = regs->rsi;
|
||||
regs->rsp = regs->r8;
|
||||
regs->cs = UCS | URPL;
|
||||
regs->ds = UDS | URPL;
|
||||
regs->ss = UDS | URPL;
|
||||
#else
|
||||
#error "You may need to fix the registers"
|
||||
#endif
|
||||
}
|
||||
|
||||
sigset_t new_signal_mask;
|
||||
memcpy(&new_signal_mask, &action->sa_mask, sizeof(sigset_t));
|
||||
sigorset(&new_signal_mask, &new_signal_mask, &signal_mask);
|
||||
|
||||
// Prevent signals from interrupting themselves by default.
|
||||
if ( !(action->sa_flags & SA_NODEFER) )
|
||||
sigaddset(&new_signal_mask, signum);
|
||||
|
||||
// Determine whether we use an alternate signal stack.
|
||||
bool signal_uses_altstack = action->sa_flags & SA_ONSTACK;
|
||||
bool usable_altstack = !(signal_stack.ss_flags & (SS_DISABLE | SS_ONSTACK));
|
||||
bool use_altstack = signal_uses_altstack && usable_altstack;
|
||||
|
||||
// Determine which signal stack to use and what to save.
|
||||
stack_t old_signal_stack, new_signal_stack;
|
||||
uintptr_t stack_location;
|
||||
if ( use_altstack )
|
||||
{
|
||||
old_signal_stack = signal_stack;
|
||||
new_signal_stack = signal_stack;
|
||||
new_signal_stack.ss_flags |= SS_ONSTACK;
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
stack_location = (uintptr_t) signal_stack.ss_sp + signal_stack.ss_size;
|
||||
#else
|
||||
#error "You need to implement getting the alternate stack pointer"
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
old_signal_stack.ss_sp = NULL;
|
||||
old_signal_stack.ss_flags = SS_DISABLE;
|
||||
old_signal_stack.ss_size = 0;
|
||||
new_signal_stack = signal_stack;
|
||||
#if defined(__i386__)
|
||||
stack_location = (uintptr_t) regs->esp;
|
||||
#elif defined(__x86_64__)
|
||||
stack_location = (uintptr_t) regs->rsp;
|
||||
#else
|
||||
#error "You need to implement getting the user-space stack pointer"
|
||||
#endif
|
||||
}
|
||||
|
||||
CPU::InterruptRegisters new_regs = *regs;
|
||||
|
||||
struct stack_frame stack_frame;
|
||||
memset(&stack_frame, 0, sizeof(stack_frame));
|
||||
|
||||
void* handler_ptr = action->sa_flags & SA_COOKIE ?
|
||||
(void*) action->sa_sigaction_cookie :
|
||||
action->sa_flags & SA_SIGINFO ?
|
||||
(void*) action->sa_sigaction :
|
||||
(void*) action->sa_handler;
|
||||
|
||||
#if defined(__i386__)
|
||||
stack_location -= sizeof(stack_frame);
|
||||
stack_location &= ~(4UL-1UL);
|
||||
struct stack_frame* stack = (struct stack_frame*) stack_location;
|
||||
|
||||
stack_frame.sigreturn = (unsigned long) process->sigreturn;
|
||||
stack_frame.signum_param = signum;
|
||||
stack_frame.siginfo_param = &stack->siginfo;
|
||||
stack_frame.ucontext_param = &stack->ucontext;
|
||||
stack_frame.cookie_param = action->sa_cookie;
|
||||
|
||||
new_regs.esp = (unsigned long) stack;
|
||||
new_regs.eip = (unsigned long) handler_ptr;
|
||||
new_regs.eflags &= ~FLAGS_DIRECTION;
|
||||
#elif defined(__x86_64__)
|
||||
stack_location -= 128; /* Red zone. */
|
||||
stack_location -= sizeof(stack_frame);
|
||||
stack_location = ((stack_location - 8) & ~(16UL-1UL)) + 8;
|
||||
struct stack_frame* stack = (struct stack_frame*) stack_location;
|
||||
|
||||
stack_frame.sigreturn = (unsigned long) process->sigreturn;
|
||||
new_regs.rdi = (unsigned long) signum;
|
||||
new_regs.rsi = (unsigned long) &stack->siginfo;
|
||||
new_regs.rdx = (unsigned long) &stack->ucontext;
|
||||
new_regs.rcx = (unsigned long) action->sa_cookie;
|
||||
|
||||
new_regs.rsp = (unsigned long) stack;
|
||||
new_regs.rip = (unsigned long) handler_ptr;
|
||||
new_regs.rflags &= ~FLAGS_DIRECTION;
|
||||
#else
|
||||
#error "You need to format the stack frame"
|
||||
#endif
|
||||
|
||||
// Format the siginfo into the stack frame.
|
||||
stack_frame.siginfo.si_signo = signum;
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
// TODO: Is this cr2 value trustworthy? I don't think it is.
|
||||
if ( signum == SIGSEGV )
|
||||
stack_frame.siginfo.si_addr = (void*) regs->cr2;
|
||||
#else
|
||||
#warning "You need to tell user-space where it crashed"
|
||||
#endif
|
||||
|
||||
// Format the ucontext into the stack frame.
|
||||
stack_frame.ucontext.uc_link = NULL;
|
||||
memcpy(&stack_frame.ucontext.uc_sigmask, &signal_mask, sizeof(signal_mask));
|
||||
memcpy(&stack_frame.ucontext.uc_stack, &signal_stack, sizeof(signal_stack));
|
||||
EncodeMachineContext(&stack_frame.ucontext.uc_mcontext, regs);
|
||||
|
||||
if ( !CopyToUser(stack, &stack_frame, sizeof(stack_frame)) )
|
||||
{
|
||||
// Self-destruct if we crashed during delivering the crash signal.
|
||||
if ( signum == SIGSEGV )
|
||||
{
|
||||
kthread_mutex_unlock(&process->signal_lock);
|
||||
process->ExitThroughSignal(signum);
|
||||
kthread_mutex_lock(&process->signal_lock);
|
||||
goto retry_another_signal;
|
||||
}
|
||||
|
||||
// Deliver SIGSEGV if we could not deliver the signal on the stack.
|
||||
// TODO: Is it possible to block SIGSEGV here?
|
||||
kthread_mutex_unlock(&process->signal_lock);
|
||||
DeliverSignal(SIGSEGV);
|
||||
kthread_mutex_lock(&process->signal_lock);
|
||||
goto retry_another_signal;
|
||||
}
|
||||
|
||||
// Update the current signal mask.
|
||||
memcpy(&signal_mask, &new_signal_mask, sizeof(sigset_t));
|
||||
|
||||
// Update the current alternate signal stack.
|
||||
signal_stack = new_signal_stack;
|
||||
|
||||
// Update the current registers.
|
||||
*regs = new_regs;
|
||||
|
||||
// TODO: SA_RESETHAND:
|
||||
// "If set, the disposition of the signal shall be reset to SIG_DFL
|
||||
// and the SA_SIGINFO flag shall be cleared on entry to the signal
|
||||
// handler. Note: SIGILL and SIGTRAP cannot be automatically reset
|
||||
// when delivered; the system silently enforces this restriction."
|
||||
|
||||
// Run the signal handler by returning to user-space.
|
||||
return;
|
||||
}
|
||||
|
||||
void Thread::HandleSigreturn(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
assert(Interrupt::IsEnabled());
|
||||
assert(this == CurrentThread());
|
||||
|
||||
ScopedLock lock(&process->signal_lock);
|
||||
|
||||
struct stack_frame stack_frame;
|
||||
const struct stack_frame* user_stack_frame;
|
||||
#if defined(__i386__)
|
||||
user_stack_frame = (const struct stack_frame*) (regs->esp - 4);
|
||||
#elif defined(__x86_64__)
|
||||
user_stack_frame = (const struct stack_frame*) (regs->rsp - 8);
|
||||
#else
|
||||
#error "You need to locate the stack we passed the signal handler"
|
||||
#endif
|
||||
|
||||
if ( CopyFromUser(&stack_frame, user_stack_frame, sizeof(stack_frame)) )
|
||||
{
|
||||
memcpy(&signal_mask, &stack_frame.ucontext.uc_sigmask, sizeof(signal_mask));
|
||||
memcpy(&signal_stack, &stack_frame.ucontext.uc_stack, sizeof(signal_stack));
|
||||
signal_stack.ss_flags &= __SS_SUPPORTED_FLAGS;
|
||||
DecodeMachineContext(&stack_frame.ucontext.uc_mcontext, regs);
|
||||
}
|
||||
|
||||
UpdatePendingSignals(this);
|
||||
regs->signal_pending = asm_signal_is_pending;
|
||||
|
||||
lock.Reset();
|
||||
|
||||
HandleSignal(regs);
|
||||
}
|
||||
|
||||
namespace Signal {
|
||||
|
||||
const int PRIORITIES[SIG__NUM_DECLARED] =
|
||||
{
|
||||
SIG_PRIO_NORMAL, // unused
|
||||
SIG_PRIO_NORMAL, // SIGHUP
|
||||
SIG_PRIO_NORMAL, // SIGINT
|
||||
SIG_PRIO_NORMAL, // SIGQUIT
|
||||
SIG_PRIO_CORE, // SIGILL
|
||||
SIG_PRIO_CORE, // SIGTRAP
|
||||
SIG_PRIO_CORE, // SIGABRT
|
||||
SIG_PRIO_CORE, // SIGEMT
|
||||
SIG_PRIO_CORE, // SIGFPE
|
||||
SIG_PRIO_KILL, // SIGKILL
|
||||
SIG_PRIO_CORE, // SIGBUS
|
||||
SIG_PRIO_CORE, // SIGSEGV
|
||||
SIG_PRIO_CORE, // SIGSYS
|
||||
SIG_PRIO_NORMAL, // SIGPIPE
|
||||
SIG_PRIO_NORMAL, // SIGALRM
|
||||
SIG_PRIO_NORMAL, // SIGTERM
|
||||
SIG_PRIO_NORMAL, // SIGUSR1
|
||||
SIG_PRIO_NORMAL, // SIGUSR2
|
||||
SIG_PRIO_NORMAL, // SIGCHLD
|
||||
SIG_PRIO_HIGH, // SIGPWR
|
||||
SIG_PRIO_NORMAL, // SIGWINCH
|
||||
SIG_PRIO_NORMAL, // SIGURG
|
||||
SIG_PRIO_NORMAL, // obsolete
|
||||
SIG_PRIO_STOP, // SIGSTOP
|
||||
SIG_PRIO_STOP, // SIGTSTP
|
||||
SIG_PRIO_STOP, // SIGCONT
|
||||
SIG_PRIO_STOP, // SIGTTIN
|
||||
SIG_PRIO_STOP, // SIGTTOU
|
||||
SIG_PRIO_NORMAL, // SIGVTALRM
|
||||
SIG_PRIO_NORMAL, // obsolete
|
||||
SIG_PRIO_CORE, // SIGXCPU
|
||||
SIG_PRIO_CORE, // SIGXFSZ
|
||||
SIG_PRIO_NORMAL, // SIGCORE
|
||||
SIG_PRIO_NORMAL, // SIGLWP
|
||||
SIG_PRIO_NORMAL, // SIGAIO
|
||||
};
|
||||
|
||||
int Priority(int signum)
|
||||
{
|
||||
assert(0 <= signum && signum < SIG_MAX_NUM);
|
||||
if ( !signum )
|
||||
return -1;
|
||||
if ( SIG__NUM_DECLARED <= signum )
|
||||
return SIG_PRIO_NORMAL;
|
||||
return PRIORITIES[signum];
|
||||
}
|
||||
|
||||
Queue::Queue()
|
||||
{
|
||||
for ( int i = 1; i < SIG_MAX_NUM; i++ )
|
||||
pending[i] = false;
|
||||
}
|
||||
|
||||
void Queue::Push(int signum)
|
||||
{
|
||||
assert(0 < signum && signum < SIG_MAX_NUM);
|
||||
pending[signum] = true;
|
||||
}
|
||||
|
||||
int Queue::Pop(int cursig)
|
||||
{
|
||||
int best = 0;
|
||||
int bestprio = Priority(cursig);
|
||||
for ( int i = 1; i < SIG_MAX_NUM; i++ )
|
||||
if ( pending[i] && bestprio < Priority(i) )
|
||||
{
|
||||
best = i;
|
||||
bestprio = Priority(i);
|
||||
}
|
||||
pending[best] = false;
|
||||
return best;
|
||||
}
|
||||
|
||||
void Dispatch(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
void DispatchHandler(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
{
|
||||
return CurrentThread()->HandleSignal(regs);
|
||||
}
|
||||
|
||||
void Return(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
void ReturnHandler(CPU::InterruptRegisters* regs, void* /*user*/)
|
||||
{
|
||||
return CurrentThread()->HandleSigreturn(regs);
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
sigemptyset(&default_ignored_signals);
|
||||
sigaddset(&default_ignored_signals, SIGCHLD);
|
||||
sigaddset(&default_ignored_signals, SIGURG);
|
||||
sigaddset(&default_ignored_signals, SIGPWR);
|
||||
sigaddset(&default_ignored_signals, SIGWINCH);
|
||||
sigemptyset(&default_stop_signals);
|
||||
sigaddset(&default_stop_signals, SIGTSTP);
|
||||
sigaddset(&default_stop_signals, SIGTTIN);
|
||||
sigaddset(&default_stop_signals, SIGTTOU);
|
||||
sigemptyset(&unblockable_signals);
|
||||
sigaddset(&unblockable_signals, SIGKILL);
|
||||
sigaddset(&unblockable_signals, SIGSTOP);
|
||||
|
||||
Syscall::Register(SYSCALL_KILL, (void*) sys_kill);
|
||||
Syscall::Register(SYSCALL_RAISE, (void*) sys_raise);
|
||||
Syscall::Register(SYSCALL_SIGACTION, (void*) sys_sigaction);
|
||||
Syscall::Register(SYSCALL_SIGALTSTACK, (void*) sys_sigaltstack);
|
||||
Syscall::Register(SYSCALL_SIGPENDING, (void*) sys_sigpending);
|
||||
Syscall::Register(SYSCALL_SIGPROCMASK, (void*) sys_sigprocmask);
|
||||
Syscall::Register(SYSCALL_SIGSUSPEND, (void*) sys_sigsuspend);
|
||||
}
|
||||
|
||||
} // namespace Signal
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -22,8 +22,11 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sortix/exit.h>
|
||||
|
@ -58,15 +61,17 @@ Thread::Thread()
|
|||
kernelstackpos = 0;
|
||||
kernelstacksize = 0;
|
||||
kernelstackmalloced = false;
|
||||
currentsignal = 0;
|
||||
siglevel = 0;
|
||||
sighandler = NULL;
|
||||
pledged_destruction = false;
|
||||
terminated = false;
|
||||
fpuinitialized = false;
|
||||
// If malloc isn't 16-byte aligned, then we can't rely on offsets in
|
||||
// our own class, so we'll just fix ourselves nicely up.
|
||||
unsigned long fpuaddr = ((unsigned long) fpuenv+16UL) & ~(16UL-1UL);
|
||||
fpuenvaligned = (uint8_t*) fpuaddr;
|
||||
sigemptyset(&signal_pending);
|
||||
sigemptyset(&signal_mask);
|
||||
memset(&signal_stack, 0, sizeof(signal_stack));
|
||||
signal_stack.ss_flags = SS_DISABLE;
|
||||
}
|
||||
|
||||
Thread::~Thread()
|
||||
|
@ -89,11 +94,6 @@ addr_t Thread::SwitchAddressSpace(addr_t newaddrspace)
|
|||
return result;
|
||||
}
|
||||
|
||||
// Last chance to clean up user-space things before this thread dies.
|
||||
void Thread::LastPrayer()
|
||||
{
|
||||
}
|
||||
|
||||
extern "C" void BootstrapKernelThread(void* user, ThreadEntry entry)
|
||||
{
|
||||
entry(user);
|
||||
|
@ -196,98 +196,19 @@ Thread* RunKernelThread(ThreadEntry entry, void* user, size_t stacksize)
|
|||
return thread;
|
||||
}
|
||||
|
||||
void Thread::HandleSignal(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
int signum = signalqueue.Pop(currentsignal);
|
||||
regs->signal_pending = 0;
|
||||
|
||||
if ( !signum )
|
||||
return;
|
||||
|
||||
if ( !sighandler )
|
||||
return;
|
||||
|
||||
if ( SIG_NUM_LEVELS <= siglevel )
|
||||
return;
|
||||
|
||||
// Signals can't return to kernel mode because the kernel stack may have
|
||||
// been overwritten by a system call during the signal handler. Correct
|
||||
// the return state so it returns to userspace and not the kernel.
|
||||
if ( !regs->InUserspace() )
|
||||
HandleSignalFixupRegsCPU(regs);
|
||||
|
||||
if ( signum == SIGKILL )
|
||||
{
|
||||
// We need to run the OnSigKill method here with interrupts enabled
|
||||
// and on our own stack. But this method this may have been called
|
||||
// from the scheduler on any stack, so we need to do a little
|
||||
// bootstrap and switch to our own stack.
|
||||
GotoOnSigKill(regs);
|
||||
return;
|
||||
}
|
||||
|
||||
int level = siglevel++;
|
||||
signums[level] = currentsignal = signum;
|
||||
memcpy(sigregs + level, regs, sizeof(*regs));
|
||||
|
||||
HandleSignalCPU(regs);
|
||||
}
|
||||
|
||||
void Thread::HandleSigreturn(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
if ( !siglevel )
|
||||
return;
|
||||
|
||||
siglevel--;
|
||||
|
||||
currentsignal = siglevel ? signums[siglevel-1] : 0;
|
||||
memcpy(regs, sigregs + siglevel, sizeof(*regs));
|
||||
regs->signal_pending = 0;
|
||||
|
||||
// Check if a more important signal is pending.
|
||||
HandleSignal(regs);
|
||||
}
|
||||
|
||||
extern "C" void Thread__OnSigKill(Thread* thread)
|
||||
{
|
||||
thread->OnSigKill();
|
||||
}
|
||||
|
||||
void Thread::OnSigKill()
|
||||
{
|
||||
LastPrayer();
|
||||
kthread_exit();
|
||||
}
|
||||
|
||||
void Thread::SetHavePendingSignals()
|
||||
{
|
||||
// TODO: This doesn't really work if Interrupt::IsCPUInterrupted()!
|
||||
if ( CurrentThread() == this )
|
||||
asm_signal_is_pending = 1;
|
||||
else
|
||||
registers.signal_pending = 1;
|
||||
}
|
||||
|
||||
bool Thread::DeliverSignal(int signum)
|
||||
{
|
||||
if ( signum <= 0 || 128 <= signum )
|
||||
return errno = EINVAL, false;
|
||||
|
||||
bool wasenabled = Interrupt::SetEnabled(false);
|
||||
signalqueue.Push(signum);
|
||||
SetHavePendingSignals();
|
||||
Interrupt::SetEnabled(wasenabled);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int sys_exit_thread(int status,
|
||||
static int sys_exit_thread(int requested_exit_code,
|
||||
int flags,
|
||||
const struct exit_thread* user_extended)
|
||||
{
|
||||
if ( flags & ~(EXIT_THREAD_ONLY_IF_OTHERS |
|
||||
EXIT_THREAD_UNMAP |
|
||||
EXIT_THREAD_ZERO) )
|
||||
EXIT_THREAD_ZERO |
|
||||
EXIT_THREAD_TLS_UNMAP |
|
||||
EXIT_THREAD_PROCESS |
|
||||
EXIT_THREAD_DUMP_CORE) )
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
if ( (flags & EXIT_THREAD_ONLY_IF_OTHERS) && (flags & EXIT_THREAD_PROCESS) )
|
||||
return errno = EINVAL, -1;
|
||||
|
||||
Thread* thread = CurrentThread();
|
||||
|
@ -309,12 +230,25 @@ static int sys_exit_thread(int status,
|
|||
{
|
||||
if ( iter == thread )
|
||||
continue;
|
||||
if ( iter->pledged_destruction )
|
||||
continue;
|
||||
if ( iter->terminated )
|
||||
continue;
|
||||
is_others = true;
|
||||
}
|
||||
if ( !(flags & EXIT_THREAD_ONLY_IF_OTHERS) || is_others )
|
||||
thread->pledged_destruction = true;
|
||||
bool are_threads_exiting = false;
|
||||
if ( (flags & EXIT_THREAD_PROCESS) || !is_others )
|
||||
process->threads_exiting = true;
|
||||
else if ( process->threads_exiting )
|
||||
are_threads_exiting = true;
|
||||
kthread_mutex_unlock(&thread->process->threadlock);
|
||||
|
||||
// Self-destruct if another thread began exiting the process.
|
||||
if ( are_threads_exiting )
|
||||
kthread_exit();
|
||||
|
||||
if ( (flags & EXIT_THREAD_ONLY_IF_OTHERS) && !is_others )
|
||||
return errno = ESRCH, -1;
|
||||
|
||||
|
@ -326,62 +260,61 @@ static int sys_exit_thread(int status,
|
|||
Memory::UnmapMemory(process, (uintptr_t) extended.unmap_from,
|
||||
extended.unmap_size);
|
||||
Memory::Flush();
|
||||
// TODO: The segment is not actually removed!
|
||||
}
|
||||
|
||||
if ( flags & EXIT_THREAD_TLS_UNMAP &&
|
||||
Page::IsAligned((uintptr_t) extended.tls_unmap_from) &&
|
||||
extended.tls_unmap_size )
|
||||
{
|
||||
ScopedLock lock(&process->segment_lock);
|
||||
Memory::UnmapMemory(process, (uintptr_t) extended.tls_unmap_from,
|
||||
extended.tls_unmap_size);
|
||||
Memory::Flush();
|
||||
}
|
||||
|
||||
if ( flags & EXIT_THREAD_ZERO )
|
||||
ZeroUser(extended.zero_from, extended.zero_size);
|
||||
|
||||
if ( !is_others )
|
||||
thread->process->Exit(status);
|
||||
{
|
||||
// Validate the requested exit code such that the process can't exit
|
||||
// with an impossible exit status or that it wasn't actually terminated.
|
||||
|
||||
int the_nature = WNATURE(requested_exit_code);
|
||||
int the_status = WEXITSTATUS(requested_exit_code);
|
||||
int the_signal = WTERMSIG(requested_exit_code);
|
||||
|
||||
if ( the_nature == WNATURE_EXITED )
|
||||
the_signal = 0;
|
||||
else if ( the_nature == WNATURE_SIGNALED )
|
||||
{
|
||||
if ( the_signal == 0 /* null signal */ ||
|
||||
the_signal == SIGSTOP ||
|
||||
the_signal == SIGTSTP ||
|
||||
the_signal == SIGTTIN ||
|
||||
the_signal == SIGTTOU ||
|
||||
the_signal == SIGCONT )
|
||||
the_signal = SIGKILL;
|
||||
the_status = 128 + the_signal;
|
||||
}
|
||||
else
|
||||
{
|
||||
the_nature = WNATURE_SIGNALED;
|
||||
the_signal = SIGKILL;
|
||||
}
|
||||
|
||||
requested_exit_code = WCONSTRUCT(the_nature, the_status, the_signal);
|
||||
|
||||
thread->process->ExitWithCode(requested_exit_code);
|
||||
}
|
||||
|
||||
kthread_exit();
|
||||
}
|
||||
|
||||
static int sys_kill(pid_t pid, int signum)
|
||||
{
|
||||
// Protect the system idle process.
|
||||
if ( !pid )
|
||||
return errno = EPERM, -1;
|
||||
|
||||
// TODO: Implement that pid == -1 means all processes!
|
||||
bool process_group = pid < 0 ? (pid = -pid, true) : false;
|
||||
|
||||
// If we kill our own process, deliver the signal to this thread.
|
||||
Thread* currentthread = CurrentThread();
|
||||
if ( currentthread->process->pid == pid )
|
||||
return currentthread->DeliverSignal(signum) ? 0 : -1;
|
||||
|
||||
// TODO: Race condition: The process could be deleted while we use it.
|
||||
Process* process = Process::Get(pid);
|
||||
if ( !process )
|
||||
return errno = ESRCH, -1;
|
||||
|
||||
// TODO: Protect init?
|
||||
// TODO: Check for permission.
|
||||
// TODO: Check for zombies.
|
||||
|
||||
return process_group ?
|
||||
process->DeliverGroupSignal(signum) ? 0 : -1 :
|
||||
process->DeliverSignal(signum) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int sys_raise(int signum)
|
||||
{
|
||||
return CurrentThread()->DeliverSignal(signum) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int sys_register_signal_handler(sighandler_t sighandler)
|
||||
{
|
||||
CurrentThread()->sighandler = sighandler;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Thread::Init()
|
||||
{
|
||||
Syscall::Register(SYSCALL_EXIT_THREAD, (void*) sys_exit_thread);
|
||||
Syscall::Register(SYSCALL_KILL, (void*) sys_kill);
|
||||
Syscall::Register(SYSCALL_RAISE, (void*) sys_raise);
|
||||
Syscall::Register(SYSCALL_REGISTER_SIGNAL_HANDLER, (void*) sys_register_signal_handler);
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <timespec.h>
|
||||
|
||||
#include <sortix/clock.h>
|
||||
|
@ -138,7 +139,12 @@ static int sys_timer_getoverrun(timer_t timerid)
|
|||
if ( !timer )
|
||||
return -1;
|
||||
|
||||
// TODO: This is not fully kept track of yet.
|
||||
if ( (size_t) INT_MAX < timer->num_overrun_events)
|
||||
return INT_MAX;
|
||||
|
||||
// TODO: How does the caller reset the overrun count back to 0? Should we
|
||||
// adopt the Linux semantics where it resets back to 0 after INT_MAX?
|
||||
// How about signed overflow in the kernel and in the user process?
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -164,15 +170,14 @@ static void timer_callback(Clock* /*clock*/, Timer* timer, void* user)
|
|||
Process* process = user_timer->process;
|
||||
ScopedLock lock(&process->user_timers_lock);
|
||||
|
||||
size_t current_overrun = timer->num_overrun_events;
|
||||
// TODO: This delivery facility is insufficient! sigevent is much more
|
||||
// powerful than sending a simple old-school signal.
|
||||
// TODO: If the last signal from last time is still being processed, we need
|
||||
// to handle the sum of overrun. I'm not sure how to handle overrun
|
||||
// properly, so we'll just pretend to user-space it never happens when
|
||||
// it does and we do some of the bookkeeping.
|
||||
(void) current_overrun;
|
||||
process->DeliverSignal(user_timer->event.sigev_signo);
|
||||
if ( !process->DeliverSignal(user_timer->event.sigev_signo) &&
|
||||
errno == ESIGPENDING )
|
||||
{
|
||||
if ( timer->num_overrun_events < SIZE_MAX )
|
||||
timer->num_overrun_events++;
|
||||
}
|
||||
}
|
||||
|
||||
static int sys_timer_settime(timer_t timerid, int flags,
|
||||
|
|
|
@ -38,10 +38,7 @@ void Process::ExecuteCPU(int argc, char** argv, int envc, char** envp,
|
|||
addr_t stackpos, addr_t entry,
|
||||
CPU::InterruptRegisters* regs)
|
||||
{
|
||||
const uint64_t CS = 0x18;
|
||||
const uint64_t DS = 0x20;
|
||||
const uint64_t RPL = 0x3;
|
||||
|
||||
memset(regs, 0, sizeof(*regs));
|
||||
regs->rdi = argc;
|
||||
regs->rsi = (size_t) argv;
|
||||
regs->rdx = envc;
|
||||
|
@ -49,14 +46,15 @@ void Process::ExecuteCPU(int argc, char** argv, int envc, char** envp,
|
|||
regs->rip = entry;
|
||||
regs->rsp = stackpos & ~15UL;
|
||||
regs->rbp = regs->rsp;
|
||||
regs->cs = CS | RPL;
|
||||
regs->ds = DS | RPL;
|
||||
regs->ss = DS | RPL;
|
||||
regs->cs = UCS | URPL;
|
||||
regs->ds = UDS | URPL;
|
||||
regs->ss = UDS | URPL;
|
||||
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||
regs->signal_pending = 0;
|
||||
}
|
||||
|
||||
void InitializeThreadRegisters(CPU::InterruptRegisters* regs,
|
||||
const tforkregs_t* requested)
|
||||
const struct tfork* requested)
|
||||
{
|
||||
memset(regs, 0, sizeof(*regs));
|
||||
regs->rip = requested->rip;
|
||||
|
|
|
@ -117,43 +117,4 @@ void SetupKernelThreadRegs(CPU::InterruptRegisters* regs, ThreadEntry entry,
|
|||
regs->signal_pending = 0;
|
||||
}
|
||||
|
||||
void Thread::HandleSignalFixupRegsCPU(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
if ( regs->InUserspace() )
|
||||
return;
|
||||
regs->rip = regs->rdi;
|
||||
regs->rflags = regs->rsi;
|
||||
regs->rsp = regs->r8;
|
||||
regs->cs = UCS | URPL;
|
||||
regs->ds = UDS | URPL;
|
||||
regs->ss = UDS | URPL;
|
||||
}
|
||||
|
||||
void Thread::HandleSignalCPU(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
const size_t STACK_ALIGNMENT = 16UL;
|
||||
const size_t RED_ZONE_SIZE = 128UL;
|
||||
regs->rsp -= RED_ZONE_SIZE;
|
||||
regs->rsp &= ~(STACK_ALIGNMENT-1UL);
|
||||
regs->rbp = regs->rsp;
|
||||
regs->rdi = currentsignal;
|
||||
regs->rip = (size_t) sighandler;
|
||||
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||
regs->kerrno = 0;
|
||||
regs->signal_pending = 0;
|
||||
}
|
||||
|
||||
void Thread::GotoOnSigKill(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
regs->rip = (unsigned long) Thread__OnSigKill;
|
||||
regs->rdi = (unsigned long) this;
|
||||
regs->rsp = regs->rbp = kernelstackpos + kernelstacksize;
|
||||
regs->rflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||
regs->cs = KCS | KRPL;
|
||||
regs->ds = KDS | KRPL;
|
||||
regs->ss = KDS | KRPL;
|
||||
regs->kerrno = 0;
|
||||
regs->signal_pending = 0;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -34,6 +34,7 @@ namespace Sortix {
|
|||
namespace Float {
|
||||
|
||||
static Thread* fputhread;
|
||||
bool fpu_is_enabled = false;
|
||||
|
||||
static inline void InitFPU()
|
||||
{
|
||||
|
@ -52,6 +53,53 @@ static inline void LoadState(const uint8_t* src)
|
|||
asm volatile ("fxrstor (%0)" : : "r"(src));
|
||||
}
|
||||
|
||||
void Yield()
|
||||
{
|
||||
Thread* thread = CurrentThread();
|
||||
|
||||
Interrupt::Disable();
|
||||
|
||||
bool fpu_was_enabled = fpu_is_enabled;
|
||||
|
||||
// The FPU contains the registers for this thread.
|
||||
if ( fputhread == thread )
|
||||
{
|
||||
if ( !fpu_was_enabled )
|
||||
EnableFPU();
|
||||
SaveState(thread->fpuenvaligned);
|
||||
fputhread = NULL;
|
||||
DisableFPU();
|
||||
}
|
||||
|
||||
// This thread has used the FPU once.
|
||||
else if ( thread->fpuinitialized )
|
||||
{
|
||||
// Nothing needs to be done, the FPU is owned by another thread and the
|
||||
// FPU registers are already stored in the thread structure.
|
||||
}
|
||||
|
||||
// This thread has never used the FPU and needs its registers initialized.
|
||||
else
|
||||
{
|
||||
if ( !fpu_was_enabled )
|
||||
EnableFPU();
|
||||
|
||||
if ( fputhread )
|
||||
SaveState(fputhread->fpuenvaligned);
|
||||
|
||||
InitFPU();
|
||||
SaveState(thread->fpuenvaligned);
|
||||
|
||||
if ( fputhread )
|
||||
LoadState(fputhread->fpuenvaligned);
|
||||
|
||||
if ( !fpu_was_enabled )
|
||||
DisableFPU();
|
||||
}
|
||||
|
||||
Interrupt::Enable();
|
||||
}
|
||||
|
||||
static void OnFPUAccess(CPU::InterruptRegisters* /*regs*/, void* /*user*/)
|
||||
{
|
||||
EnableFPU();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
|
||||
|
||||
This file is part of Sortix.
|
||||
|
||||
|
@ -31,16 +31,21 @@ class Thread;
|
|||
|
||||
namespace Float {
|
||||
|
||||
extern bool fpu_is_enabled;
|
||||
|
||||
void Init();
|
||||
void NofityTaskExit(Thread* thread);
|
||||
void Yield();
|
||||
|
||||
static inline void EnableFPU()
|
||||
{
|
||||
asm volatile ("clts");
|
||||
fpu_is_enabled = true;
|
||||
}
|
||||
|
||||
static inline void DisableFPU()
|
||||
{
|
||||
fpu_is_enabled = false;
|
||||
unsigned long cr0;
|
||||
asm volatile ("mov %%cr0, %0" : "=r"(cr0));
|
||||
cr0 |= 1UL<<3UL;
|
||||
|
|
|
@ -30,14 +30,6 @@
|
|||
namespace Sortix {
|
||||
namespace IDT {
|
||||
|
||||
static struct idt_entry idt_entries[256];
|
||||
|
||||
void Init()
|
||||
{
|
||||
memset(&idt_entries, 0, sizeof(idt_entries));
|
||||
Set(idt_entries, 256);
|
||||
}
|
||||
|
||||
void Set(struct idt_entry* table, size_t length)
|
||||
{
|
||||
size_t limit = sizeof(idt_entry) * length - 1;
|
||||
|
@ -69,10 +61,5 @@ void SetEntry(struct idt_entry* entry, uintptr_t handler, uint16_t selector, uin
|
|||
#endif
|
||||
}
|
||||
|
||||
void SetEntry(uint8_t num, uintptr_t handler, uint16_t selector, uint8_t flags, uint8_t ist)
|
||||
{
|
||||
SetEntry(idt_entries + num, handler, selector, flags, ist);
|
||||
}
|
||||
|
||||
} // namespace IDT
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -230,13 +230,13 @@ void Init()
|
|||
RegisterRawHandler(47, irq15, false, false);
|
||||
RegisterRawHandler(128, syscall_handler, true, true);
|
||||
RegisterRawHandler(129, yield_cpu_handler, true, false);
|
||||
RegisterRawHandler(130, isr130, true, false);
|
||||
RegisterRawHandler(131, isr131, true, false);
|
||||
RegisterRawHandler(130, isr130, true, true);
|
||||
RegisterRawHandler(131, isr131, true, true);
|
||||
RegisterRawHandler(132, thread_exit_handler, true, false);
|
||||
|
||||
RegisterHandler(129, Scheduler::InterruptYieldCPU, NULL);
|
||||
RegisterHandler(130, Signal::Dispatch, NULL);
|
||||
RegisterHandler(131, Signal::Return, NULL);
|
||||
RegisterHandler(130, Signal::DispatchHandler, NULL);
|
||||
RegisterHandler(131, Signal::ReturnHandler, NULL);
|
||||
RegisterHandler(132, Scheduler::ThreadExitCPU, NULL);
|
||||
|
||||
IDT::Set(interrupt_table, NUM_INTERRUPTS);
|
||||
|
@ -313,6 +313,19 @@ void UserCrashHandler(CPU::InterruptRegisters* regs)
|
|||
// Execute this crash handler with preemption on.
|
||||
Interrupt::Enable();
|
||||
|
||||
// TODO: Also send signals for other types of user-space crashes.
|
||||
if ( regs->int_no == 14 /* Page fault */ )
|
||||
{
|
||||
struct sigaction* act = &CurrentProcess()->signal_actions[SIGSEGV];
|
||||
kthread_mutex_lock(&CurrentProcess()->signal_lock);
|
||||
bool handled = act->sa_handler != SIG_DFL && act->sa_handler != SIG_IGN;
|
||||
if ( handled )
|
||||
CurrentThread()->DeliverSignalUnlocked(SIGSEGV);
|
||||
kthread_mutex_unlock(&CurrentProcess()->signal_lock);
|
||||
if ( handled )
|
||||
return Signal::DispatchHandler(regs, NULL);
|
||||
}
|
||||
|
||||
// Walk and print the stack frames if this is a debug build.
|
||||
if ( CALLTRACE_USER )
|
||||
CrashCalltrace(regs);
|
||||
|
@ -330,13 +343,10 @@ void UserCrashHandler(CPU::InterruptRegisters* regs)
|
|||
|
||||
// Exit the process with the right error code.
|
||||
// TODO: Send a SIGINT, SIGBUS, or whatever instead.
|
||||
CurrentProcess()->Exit(139);
|
||||
|
||||
// TODO: Is it strictly needed or even desirable to disable preemption here?
|
||||
Interrupt::Disable();
|
||||
CurrentProcess()->ExitThroughSignal(SIGSEGV);
|
||||
|
||||
// Deliver signals to this thread so it can exit correctly.
|
||||
Signal::Dispatch(regs);
|
||||
Signal::DispatchHandler(regs, NULL);
|
||||
}
|
||||
|
||||
extern "C" void interrupt_handler(CPU::InterruptRegisters* regs)
|
||||
|
|
|
@ -99,11 +99,3 @@ asm_call_BootstrapKernelThread:
|
|||
call BootstrapKernelThread
|
||||
# BootstrapKernelThread is noreturn, no need for code here.
|
||||
.size asm_call_BootstrapKernelThread, . - asm_call_BootstrapKernelThread
|
||||
|
||||
.global asm_call_Thread__OnSigKill
|
||||
.type asm_call_Thread__OnSigKill, @function
|
||||
asm_call_Thread__OnSigKill:
|
||||
pushl %edi
|
||||
call Thread__OnSigKill
|
||||
# Thread__OnSigKill is noreturn, no need for code here.
|
||||
.size asm_call_Thread__OnSigKill, . - asm_call_Thread__OnSigKill
|
||||
|
|
|
@ -38,6 +38,7 @@ void Process::ExecuteCPU(int argc, char** argv, int envc, char** envp,
|
|||
addr_t stackpos, addr_t entry,
|
||||
CPU::InterruptRegisters* regs)
|
||||
{
|
||||
memset(regs, 0, sizeof(*regs));
|
||||
regs->eax = argc;
|
||||
regs->ebx = (size_t) argv;
|
||||
regs->edx = envc;
|
||||
|
@ -49,10 +50,11 @@ void Process::ExecuteCPU(int argc, char** argv, int envc, char** envp,
|
|||
regs->ds = UDS | URPL;
|
||||
regs->ss = UDS | URPL;
|
||||
regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||
regs->signal_pending = 0;
|
||||
}
|
||||
|
||||
void InitializeThreadRegisters(CPU::InterruptRegisters* regs,
|
||||
const tforkregs_t* requested)
|
||||
const struct tfork* requested)
|
||||
{
|
||||
memset(regs, 0, sizeof(*regs));
|
||||
regs->eip = requested->eip;
|
||||
|
|
|
@ -96,50 +96,4 @@ void SetupKernelThreadRegs(CPU::InterruptRegisters* regs, ThreadEntry entry,
|
|||
regs->signal_pending = 0;
|
||||
}
|
||||
|
||||
void Thread::HandleSignalFixupRegsCPU(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
if ( regs->InUserspace() )
|
||||
return;
|
||||
uint32_t* params = (uint32_t*) regs->ebx;
|
||||
regs->eip = params[0];
|
||||
regs->eflags = params[2];
|
||||
regs->esp = params[3];
|
||||
regs->cs = UCS | URPL;
|
||||
regs->ds = UDS | URPL;
|
||||
regs->ss = UDS | URPL;
|
||||
}
|
||||
|
||||
void Thread::HandleSignalCPU(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
const size_t STACK_ALIGNMENT = 16UL;
|
||||
const size_t RED_ZONE_SIZE = 128UL;
|
||||
regs->esp -= RED_ZONE_SIZE;
|
||||
regs->esp &= ~(STACK_ALIGNMENT-1UL);
|
||||
regs->ebp = regs->esp;
|
||||
regs->edi = currentsignal;
|
||||
regs->eip = (size_t) sighandler;
|
||||
regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||
regs->kerrno = 0;
|
||||
regs->signal_pending = 0;
|
||||
}
|
||||
|
||||
extern "C" void asm_call_Thread__OnSigKill(void);
|
||||
|
||||
void Thread::GotoOnSigKill(CPU::InterruptRegisters* regs)
|
||||
{
|
||||
regs->eip = (unsigned long) asm_call_Thread__OnSigKill;
|
||||
regs->edi = (unsigned long) this;
|
||||
// TODO: HACK: The -256 is because if we are jumping to the safe stack
|
||||
// we currently are on, this may not be fully supported by interrupt.s
|
||||
// that is quite aware of this (but isn't perfect). If our destination
|
||||
// is further down the stack, then we are probably safe.
|
||||
regs->esp = regs->ebp = kernelstackpos + kernelstacksize - 256;
|
||||
regs->eflags = FLAGS_RESERVED1 | FLAGS_INTERRUPT | FLAGS_ID;
|
||||
regs->cs = KCS | KRPL;
|
||||
regs->ds = KDS | KRPL;
|
||||
regs->ss = KDS | KRPL;
|
||||
regs->kerrno = 0;
|
||||
regs->signal_pending = 0;
|
||||
}
|
||||
|
||||
} // namespace Sortix
|
||||
|
|
|
@ -374,14 +374,15 @@ pwd/setpwent.o \
|
|||
sched/sched_yield.o \
|
||||
signal/kill.o \
|
||||
signal/killpg.o \
|
||||
signal/psiginfo.o \
|
||||
signal/psignal.o \
|
||||
signal/raise.o \
|
||||
signal/sigaction.o \
|
||||
signal/SIG_DFL.o \
|
||||
signal/SIG_ERR.o \
|
||||
signal/SIG_IGN.o \
|
||||
signal/sigaltstack.o \
|
||||
signal/signal.o \
|
||||
signal/sigpending.o \
|
||||
signal/sigprocmask.o \
|
||||
signal/sigsuspend.o \
|
||||
stdio/fcloseall.o \
|
||||
stdio/fdio.o \
|
||||
stdio/fgetpos.o \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -27,18 +27,24 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include <sortix/__/sigset.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#if defined(__x86_64__)
|
||||
typedef unsigned long jmp_buf[8];
|
||||
typedef unsigned long sigjmp_buf[8 + 1 + __SIGSET_NUM_SIGNALS / (sizeof(unsigned long int) * 8)];
|
||||
#elif defined(__i386__)
|
||||
typedef unsigned long jmp_buf[6];
|
||||
typedef unsigned long sigjmp_buf[6 + 1 + __SIGSET_NUM_SIGNALS / (sizeof(unsigned long int) * 8)];
|
||||
#else
|
||||
#error "You need to implement jmp_buf on your CPU"
|
||||
#error "You need to implement sigjmp_buf on your CPU"
|
||||
#endif
|
||||
|
||||
void longjmp(jmp_buf env, int val);
|
||||
int setjmp(jmp_buf env);
|
||||
typedef sigjmp_buf jmp_buf;
|
||||
|
||||
void longjmp(jmp_buf, int);
|
||||
int setjmp(jmp_buf);
|
||||
void siglongjmp(sigjmp_buf, int);
|
||||
int sigsetjmp(sigjmp_buf, int);
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
|||
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
signal.h
|
||||
Signals.
|
||||
Signal API.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
|
@ -33,7 +33,17 @@
|
|||
#include <__/pthread.h>
|
||||
#endif
|
||||
|
||||
#include <sortix/sigaction.h>
|
||||
#include <sortix/sigevent.h>
|
||||
#include <sortix/siginfo.h>
|
||||
#include <sortix/signal.h>
|
||||
#include <sortix/signal.h>
|
||||
#include <sortix/sigprocmask.h>
|
||||
#include <sortix/sigset.h>
|
||||
#include <sortix/sigval.h>
|
||||
#include <sortix/stack.h>
|
||||
#include <sortix/timespec.h>
|
||||
#include <sortix/ucontext.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
@ -53,12 +63,6 @@ typedef __pid_t pid_t;
|
|||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
/* TODO: POSIX says this header declares struct timespec, but not time_t... */
|
||||
#ifndef __time_t_defined
|
||||
#define __time_t_defined
|
||||
typedef __time_t time_t;
|
||||
#endif
|
||||
|
||||
#if __STDC_HOSTED__
|
||||
|
||||
#ifndef __pthread_attr_t_defined
|
||||
|
@ -73,134 +77,12 @@ typedef __pthread_t pthread_t;
|
|||
|
||||
#endif
|
||||
|
||||
__END_DECLS
|
||||
#define NSIG __SIG_MAX_NUM
|
||||
|
||||
#include <sortix/sigset.h>
|
||||
#include <sortix/timespec.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
/* TODO: Should this be volatile? It isn't on Linux. */
|
||||
typedef int sig_atomic_t;
|
||||
|
||||
typedef void (*sighandler_t)(int);
|
||||
|
||||
void SIG_DFL(int);
|
||||
void SIG_IGN(int);
|
||||
void SIG_ERR(int);
|
||||
|
||||
#define SIG_DFL SIG_DFL
|
||||
#define SIG_IGN SIG_IGN
|
||||
#define SIG_ERR SIG_ERR
|
||||
/* TODO: POSIX specifies a obsolecent SIG_HOLD here. */
|
||||
|
||||
union sigval
|
||||
{
|
||||
int sival_int;
|
||||
void* sival_ptr;
|
||||
};
|
||||
|
||||
struct sigevent
|
||||
{
|
||||
int sigev_notify;
|
||||
int sigev_signo;
|
||||
union sigval sigev_value;
|
||||
void (*sigev_notify_function)(union sigval);
|
||||
/*pthread_attr_t* sigev_notify_attributes;*/
|
||||
};
|
||||
|
||||
#define SIGEV_NONE 0
|
||||
#define SIGEV_SIGNAL 1
|
||||
#define SIGEV_THREAD 2
|
||||
|
||||
/* TODO: SIGRTMIN */
|
||||
/* TODO: SIGRTMAX */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int si_signo;
|
||||
int si_code;
|
||||
int si_errno;
|
||||
pid_t si_pid;
|
||||
uid_t si_uid;
|
||||
void* si_addr;
|
||||
int si_status;
|
||||
union sigval si_value;
|
||||
} siginfo_t;
|
||||
|
||||
#define ILL_ILLOPC 1
|
||||
#define ILL_ILLOPN 2
|
||||
#define ILL_ILLADR 3
|
||||
#define ILL_ILLTRP 4
|
||||
#define ILL_PRVOPC 5
|
||||
#define ILL_PRVREG 6
|
||||
#define ILL_COPROC 7
|
||||
#define ILL_BADSTK 8
|
||||
#define FPE_INTDIV 9
|
||||
#define FPE_INTOVF 10
|
||||
#define FPE_FLTDIV 11
|
||||
#define FPE_FLTOVF 12
|
||||
#define FPE_FLTUND 13
|
||||
#define FPE_FLTRES 14
|
||||
#define FPE_FLTINV 15
|
||||
#define FPE_FLTSUB 16
|
||||
#define SEGV_MAPERR 17
|
||||
#define SEGV_ACCERR 18
|
||||
#define BUS_ADRALN 19
|
||||
#define BUS_ADRERR 20
|
||||
#define BUS_OBJERR 21
|
||||
#define TRAP_BRKPT 22
|
||||
#define TRAP_TRACE 23
|
||||
#define CLD_EXITED 24
|
||||
#define CLD_KILLED 25
|
||||
#define CLD_DUMPED 26
|
||||
#define CLD_TRAPPED 27
|
||||
#define CLD_STOPPED 29
|
||||
#define CLD_CONTINUED 30
|
||||
#define SI_USER 31
|
||||
#define SI_QUEUE 32
|
||||
#define SI_TIMER 33
|
||||
#define SI_ASYNCIO 34
|
||||
#define SI_MSGQ 35
|
||||
|
||||
struct sigaction
|
||||
{
|
||||
void (*sa_handler)(int);
|
||||
void (*sa_sigaction)(int, siginfo_t*, void*);
|
||||
sigset_t sa_mask;
|
||||
int sa_flags;
|
||||
};
|
||||
|
||||
#define SA_NOCLDSTOP (1<<0)
|
||||
#define SA_ONSTACK (1<<1)
|
||||
#define SA_RESETHAND (1<<2)
|
||||
#define SA_RESTART (1<<3)
|
||||
#define SA_SIGINFO (1<<4)
|
||||
#define SA_NOCLDWAIT (1<<5)
|
||||
#define SA_NODEFER (1<<6)
|
||||
#define SS_ONSTACK (1<<7)
|
||||
#define SS_DISABLE (1<<8)
|
||||
/* TODO: MINSIGSTKSZ */
|
||||
/* TODO: SIGSTKSZ */
|
||||
|
||||
/* TODO: mcontext_t */
|
||||
typedef int mcontext_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* ss_sp;
|
||||
size_t ss_size;
|
||||
int ss_flags;
|
||||
} stack_t;
|
||||
|
||||
typedef struct __ucontext ucontext_t;
|
||||
struct __ucontext
|
||||
{
|
||||
ucontext_t* uc_link;
|
||||
sigset_t uc_sigmask;
|
||||
stack_t uc_stack;
|
||||
mcontext_t uc_mcontext;
|
||||
};
|
||||
#define MINSIGSTKSZ 2048
|
||||
#define SIGSTKSZ 8192
|
||||
|
||||
int kill(pid_t, int);
|
||||
int killpg(pid_t, int);
|
||||
|
@ -216,25 +98,19 @@ int sigandset(sigset_t*, const sigset_t*, const sigset_t*);
|
|||
int sigdelset(sigset_t*, int);
|
||||
int sigemptyset(sigset_t*);
|
||||
int sigfillset(sigset_t*);
|
||||
/* TODO: sighold (obsolescent XSI). */
|
||||
/* TODO: sigignore (obsolescent XSI). */
|
||||
/* TODO: siginterrupt (obsolescent XSI). */
|
||||
int sigisemptyset(const sigset_t*);
|
||||
int sigismember(const sigset_t*, int);
|
||||
sighandler_t signal(int, sighandler_t);
|
||||
void (*signal(int, void (*)(int)))(int);
|
||||
int signotset(sigset_t*, const sigset_t*);
|
||||
int sigorset(sigset_t*, const sigset_t*, const sigset_t*);
|
||||
/* TODO: sigpause (obsolescent XSI). */
|
||||
int sigpending(sigset_t*);
|
||||
int sigprocmask(int, const sigset_t* __restrict, sigset_t* __restrict);
|
||||
int sigqueue(pid_t, int, const union sigval);
|
||||
/* TODO: sigrelse (obsolescent XSI). */
|
||||
/* TODO: sigset (obsolescent XSI). */
|
||||
/* TODO: int sigqueue(pid_t, int, const union sigval); */
|
||||
int sigsuspend(const sigset_t*);
|
||||
int sigtimedwait(const sigset_t* __restrict, siginfo_t* __restrict,
|
||||
const struct timespec* __restrict);
|
||||
int sigwait(const sigset_t* __restrict, int* __restrict);
|
||||
int sigwaitinfo(const sigset_t* __restrict, siginfo_t* vrestrict);
|
||||
/* TODO: int sigtimedwait(const sigset_t* __restrict, siginfo_t* __restrict,
|
||||
const struct timespec* __restrict); */
|
||||
/* TODO: int sigwait(const sigset_t* __restrict, int* __restrict); */
|
||||
/* TODO: int sigwaitinfo(const sigset_t* __restrict, siginfo_t* __restrict); */
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -22,10 +22,8 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
// TODO: Make this header comply with POSIX-1.2008
|
||||
|
||||
#ifndef _SYS_WAIT_H
|
||||
#define _SYS_WAIT_H 1
|
||||
#ifndef INCLUDE_SYS_WAIT_H
|
||||
#define INCLUDE_SYS_WAIT_H 1
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
|
@ -40,12 +38,8 @@ __BEGIN_DECLS
|
|||
typedef __pid_t pid_t;
|
||||
#endif
|
||||
|
||||
/* TODO: These are not implemented in sortix libc yet. */
|
||||
#if 0
|
||||
int waitid(idtype_t, id_t, siginfo_t*, int);
|
||||
#endif
|
||||
|
||||
pid_t wait(int* stat_loc);
|
||||
/* TODO: int waitid(idtype_t, id_t, siginfo_t*, int); */
|
||||
pid_t waitpid(pid_t pid, int *stat_loc, int options);
|
||||
|
||||
__END_DECLS
|
||||
|
|
|
@ -406,7 +406,7 @@ int exit_thread(int, int, const struct exit_thread*);
|
|||
int memstat(size_t* memused, size_t* memtotal);
|
||||
int mkpartition(int fd, off_t start, off_t length);
|
||||
pid_t sfork(int flags);
|
||||
pid_t tfork(int flags, tforkregs_t* regs);
|
||||
pid_t tfork(int flags, struct tfork* regs);
|
||||
size_t writeall(int fd, const void* buf, size_t count);
|
||||
size_t writeleast(int fd, const void* buf, size_t least, size_t max);
|
||||
#endif
|
||||
|
|
|
@ -31,7 +31,6 @@ extern "C" { char* program_invocation_name; }
|
|||
extern "C" { char* program_invocation_short_name; }
|
||||
|
||||
extern "C" void init_stdio();
|
||||
extern "C" void init_signal();
|
||||
|
||||
static char* find_last_elem(char* str)
|
||||
{
|
||||
|
@ -53,9 +52,6 @@ extern "C" void initialize_standard_library(int argc, char* argv[])
|
|||
program_invocation_name = (char*) argv0;
|
||||
program_invocation_short_name = find_last_elem((char*) argv0);
|
||||
|
||||
// It's probably best to initialize the Unix signals early on.
|
||||
init_signal();
|
||||
|
||||
// Initialize pthreads and stuff like thread-local storage.
|
||||
pthread_initialize();
|
||||
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
The Sortix C Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The Sortix C Library 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
signal/SIG_DFL.cpp
|
||||
Default signal handler.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void Core(int signum)
|
||||
{
|
||||
exit(128 + signum);
|
||||
}
|
||||
|
||||
extern "C" void SIG_DFL(int signum)
|
||||
{
|
||||
if ( signum == SIGHUP ) { exit(128 + signum); } else
|
||||
if ( signum == SIGINT ) { exit(128 + signum); } else
|
||||
if ( signum == SIGQUIT ) { Core(signum); } else
|
||||
if ( signum == SIGTRAP ) { Core(signum); } else
|
||||
if ( signum == SIGABRT ) { Core(signum); } else
|
||||
if ( signum == SIGEMT ) { Core(signum); } else
|
||||
if ( signum == SIGFPE ) { Core(signum); } else
|
||||
if ( signum == SIGKILL ) { exit(128 + signum); } else
|
||||
if ( signum == SIGBUS ) { Core(signum); } else
|
||||
if ( signum == SIGSEGV ) { Core(signum); } else
|
||||
if ( signum == SIGSYS ) { Core(signum); } else
|
||||
if ( signum == SIGPIPE ) { exit(128 + signum); } else
|
||||
if ( signum == SIGALRM ) { exit(128 + signum); } else
|
||||
if ( signum == SIGTERM ) { exit(128 + signum); } else
|
||||
if ( signum == SIGUSR1 ) { exit(128 + signum); } else
|
||||
if ( signum == SIGUSR2 ) { exit(128 + signum); } else
|
||||
if ( signum == SIGCHLD ) { /* Ignore this signal. */ } else
|
||||
if ( signum == SIGPWR ) { /* Ignore this signal. */ } else
|
||||
if ( signum == SIGWINCH ) { /* Ignore this signal. */ } else
|
||||
if ( signum == SIGURG ) { /* Ignore this signal. */ } else
|
||||
if ( signum == SIGCONT ) { /* Ignore this signal. */ } else
|
||||
if ( signum == SIGVTALRM ) { /* Ignore this signal. */ } else
|
||||
if ( signum == SIGXCPU ) { Core(signum); } else
|
||||
if ( signum == SIGXFSZ ) { Core(signum); } else
|
||||
if ( signum == SIGWAITING ) { /* Ignore this signal. */ } else
|
||||
if ( signum == SIGLWP ) { /* Ignore this signal. */ } else
|
||||
if ( signum == SIGAIO ) { /* Ignore this signal. */ } else
|
||||
{ /* Ignore this signal. */ }
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -17,15 +17,14 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
signal/SIG_IGN.cpp
|
||||
Ignore signal.
|
||||
signal/psiginfo.cpp
|
||||
Print signal error condition to stderr.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern "C" void SIG_IGN(int /*signum*/)
|
||||
extern "C" void psiginfo(const siginfo_t* si, const char* message)
|
||||
{
|
||||
|
||||
psignal(si->si_signo, message);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -22,53 +22,19 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
const int MAX_SIGNALS = 128;
|
||||
extern sighandler_t handlers[MAX_SIGNALS];
|
||||
DEFN_SYSCALL3(int, sys_sigaction, SYSCALL_SIGACTION,
|
||||
int,
|
||||
const struct sigaction*,
|
||||
struct sigaction*);
|
||||
|
||||
// TODO: Actually implement the sigaction interface for real.
|
||||
extern "C"
|
||||
int sigaction(int signum, const struct sigaction* restrict act,
|
||||
int sigaction(int signum,
|
||||
const struct sigaction* restrict act,
|
||||
struct sigaction* restrict oldact)
|
||||
{
|
||||
if ( !act )
|
||||
{
|
||||
// TODO: set oldact->sa_mask here?
|
||||
oldact->sa_sigaction = NULL;
|
||||
oldact->sa_handler = handlers[signum];
|
||||
oldact->sa_flags = 0;
|
||||
return 0;
|
||||
}
|
||||
int understood_flags = SA_SIGINFO | SA_RESTART;
|
||||
if ( act->sa_flags & ~understood_flags )
|
||||
{
|
||||
fprintf(stderr, "%s:%u sigaction with unsupported flags 0x%x, ignoring "
|
||||
"hoping they aren't needed.\n", __FILE__, __LINE__,
|
||||
act->sa_flags & ~understood_flags);
|
||||
}
|
||||
if ( act->sa_flags & SA_RESTART )
|
||||
/* TODO: Actually implement this. Signals are a bit rare on Sortix right
|
||||
now, so it doesn't matter much that system calls don't restart
|
||||
on Sortix, so pretend that they do. */ {};
|
||||
if ( act->sa_flags & SA_SIGINFO )
|
||||
{
|
||||
fprintf(stderr, "%s:%u sigaction with unsupported SA_SIGINFO, ignoring "
|
||||
"hoping the signal never happens.\n", __FILE__,
|
||||
__LINE__);
|
||||
return 0;
|
||||
}
|
||||
sighandler_t new_handler = act->sa_handler;
|
||||
sighandler_t old_handler = signal(signum, new_handler);
|
||||
if ( old_handler == SIG_ERR )
|
||||
return -1;
|
||||
if ( oldact )
|
||||
{
|
||||
// TODO: set oldact->sa_mask here?
|
||||
oldact->sa_sigaction = NULL;
|
||||
oldact->sa_handler = old_handler;
|
||||
oldact->sa_flags = 0;
|
||||
}
|
||||
return 0;
|
||||
return sys_sigaction(signum, act, oldact);
|
||||
}
|
||||
|
|
34
libc/signal/sigaltstack.cpp
Normal file
34
libc/signal/sigaltstack.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
The Sortix C Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The Sortix C Library 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
signal/sigaltstack.cpp
|
||||
Sets the stack used during signal handling.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
DEFN_SYSCALL2(int, sys_sigaltstack, SYSCALL_SIGALTSTACK, const stack_t*, stack_t*);
|
||||
|
||||
extern "C" int sigaltstack(const stack_t* restrict ss, stack_t* restrict oss)
|
||||
{
|
||||
return sys_sigaltstack(ss, oss);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -18,38 +18,35 @@
|
|||
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
signal/signal.cpp
|
||||
Handles the good old unix signals.
|
||||
Configure and retrieve a signal handler.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
const int MAX_SIGNALS = 128;
|
||||
sighandler_t handlers[MAX_SIGNALS];
|
||||
|
||||
extern "C" void SignalHandlerAssembly(int signum);
|
||||
extern "C" void SignalHandler(int signum)
|
||||
extern "C" void (*signal(int signum, void (*handler)(int)))(int)
|
||||
{
|
||||
if ( 0 <= signum && signum < (int) MAX_SIGNALS )
|
||||
handlers[signum](signum);
|
||||
}
|
||||
|
||||
DEFN_SYSCALL1(int, sys_register_signal_handler, SYSCALL_REGISTER_SIGNAL_HANDLER, sighandler_t);
|
||||
|
||||
extern "C" void init_signal()
|
||||
{
|
||||
for ( int i = 0; i < MAX_SIGNALS; i++ )
|
||||
handlers[i] = SIG_DFL;
|
||||
|
||||
// Tell the kernel which function we want called upon signals.
|
||||
sys_register_signal_handler(&SignalHandlerAssembly);
|
||||
}
|
||||
|
||||
extern "C" sighandler_t signal(int signum, sighandler_t handler)
|
||||
{
|
||||
if ( signum < 0 || MAX_SIGNALS <= signum ) { return SIG_ERR; }
|
||||
return handlers[signum] = handler;
|
||||
// Create a structure describing the new handler.
|
||||
struct sigaction newact;
|
||||
memset(&newact, 0, sizeof(newact));
|
||||
sigemptyset(&newact.sa_mask);
|
||||
newact.sa_handler = handler;
|
||||
newact.sa_flags = SA_RESTART;
|
||||
|
||||
// Register the new handler and atomically get the old.
|
||||
struct sigaction oldact;
|
||||
if ( sigaction(signum, &newact, &oldact) != 0 )
|
||||
return SIG_ERR;
|
||||
|
||||
// We can't return the old handler properly if it's SA_SIGINFO or SA_COOKIE,
|
||||
// unless it's the common SIG_IGN or SIG_DFL handlers. Let's just say to the
|
||||
// caller that it's SIG_DFL and assume that they'll be using sigaction
|
||||
// instead if they wish to restore an old handler.
|
||||
if ( (oldact.sa_flags & (SA_SIGINFO | SA_COOKIE)) &&
|
||||
oldact.sa_handler != SIG_IGN &&
|
||||
oldact.sa_handler != SIG_DFL )
|
||||
return SIG_DFL;
|
||||
|
||||
return oldact.sa_handler;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -17,15 +17,18 @@
|
|||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
signal/SIG_ERR.cpp
|
||||
Abort on signal.
|
||||
signal/sigpending.cpp
|
||||
Get the set of pending signals.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
extern "C" void SIG_ERR(int /*signum*/)
|
||||
#include <signal.h>
|
||||
|
||||
DEFN_SYSCALL1(int, sys_sigpending, SYSCALL_SIGPENDING, sigset_t*);
|
||||
|
||||
extern "C" int sigpending(sigset_t* set)
|
||||
{
|
||||
abort();
|
||||
return sys_sigpending(set);
|
||||
}
|
|
@ -22,13 +22,13 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
DEFN_SYSCALL3(int, sys_sigprocmask, SYSCALL_SIGPROCMASK, int, const sigset_t*, sigset_t*);
|
||||
|
||||
extern "C" int sigprocmask(int how, const sigset_t* set, sigset_t* oldset)
|
||||
{
|
||||
(void) how;
|
||||
(void) set;
|
||||
(void) oldset;
|
||||
return 0;
|
||||
return sys_sigprocmask(how, set, oldset);
|
||||
}
|
||||
|
|
34
libc/signal/sigsuspend.cpp
Normal file
34
libc/signal/sigsuspend.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
The Sortix C Library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at your
|
||||
option) any later version.
|
||||
|
||||
The Sortix C Library 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
signal/sigsuspend.cpp
|
||||
Wait until a signal occurs.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
DEFN_SYSCALL1(int, sys_sigsuspend, SYSCALL_SIGSUSPEND, const sigset_t*);
|
||||
|
||||
extern "C" int sigsuspend(const sigset_t* set)
|
||||
{
|
||||
return sys_sigsuspend(set);
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2013, 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -23,9 +23,12 @@
|
|||
*******************************************************************************/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <calltrace.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if defined(__is_sortix_kernel)
|
||||
|
||||
|
@ -42,19 +45,30 @@ extern "C" void abort(void)
|
|||
extern "C" void abort(void)
|
||||
{
|
||||
struct stat st;
|
||||
if ( getenv("LIBC_DEBUG_CALLTRACE") || stat("/etc/calltrace", &st) == 0 )
|
||||
if ( stat("/etc/calltrace", &st) == 0 )
|
||||
calltrace();
|
||||
if ( getenv("LIBC_DEBUG_LOOP") || stat("/etc/calltrace_loop", &st) == 0 )
|
||||
if ( stat("/etc/calltrace_loop", &st) == 0 )
|
||||
while ( true );
|
||||
// TODO: Send SIGABRT instead!
|
||||
_Exit(128 + 6);
|
||||
|
||||
sigset_t set_of_sigabrt;
|
||||
sigemptyset(&set_of_sigabrt);
|
||||
sigaddset(&set_of_sigabrt, SIGABRT);
|
||||
sigprocmask(SIG_UNBLOCK, &set_of_sigabrt, NULL);
|
||||
|
||||
raise(SIGABRT);
|
||||
|
||||
int exit_code = WCONSTRUCT(WNATURE_SIGNALED, 128 + SIGABRT, SIGABRT);
|
||||
int exit_flags = EXIT_THREAD_PROCESS | EXIT_THREAD_DUMP_CORE;
|
||||
exit_thread(exit_code, exit_flags, NULL);
|
||||
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
extern "C" void abort(void)
|
||||
{
|
||||
while ( true ) { };
|
||||
while ( true ) { }
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
|
|
|
@ -30,15 +30,20 @@
|
|||
|
||||
extern "C" { struct exit_handler* __exit_handler_stack = NULL; }
|
||||
|
||||
static pthread_mutex_t exit_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t exit_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
static bool currently_exiting = false;
|
||||
|
||||
extern "C" void exit(int status)
|
||||
{
|
||||
// Only allow a single thread to do the exit cleanup. If somehow the cleanup
|
||||
// code calls exit, then we'll self-destruct. If multiple threads attempt to
|
||||
// call exit, then we'll destroy the ones that got here too late.
|
||||
if ( pthread_mutex_trylock(&exit_lock) != 0 )
|
||||
exit_thread(status, 0, NULL);
|
||||
// It's undefined behavior to call this function more than once: If more
|
||||
// than one thread calls the function we'll wait until the process dies.
|
||||
pthread_mutex_lock(&exit_lock);
|
||||
|
||||
// It's undefined behavior to call this function more than once: If a
|
||||
// cleanup function calls this function we'll self-destruct immediately.
|
||||
if ( currently_exiting )
|
||||
_Exit(status);
|
||||
currently_exiting = true;
|
||||
|
||||
while ( __exit_handler_stack )
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -30,40 +30,41 @@ extern "C" const char* sortix_strsignal(int signum)
|
|||
{
|
||||
switch ( signum )
|
||||
{
|
||||
case SIGHUP: return "SIGHUP";
|
||||
case SIGINT: return "SIGINT";
|
||||
case SIGQUIT: return "SIGQUIT";
|
||||
case SIGILL: return "SIGILL";
|
||||
case SIGTRAP: return "SIGTRAP";
|
||||
case SIGABRT: return "SIGABRT";
|
||||
case SIGEMT: return "SIGEMT";
|
||||
case SIGFPE: return "SIGFPE";
|
||||
case SIGKILL: return "SIGKILL";
|
||||
case SIGBUS: return "SIGBUS";
|
||||
case SIGSEGV: return "SYSSEGV";
|
||||
case SIGSYS: return "SIGSYS";
|
||||
case SIGPIPE: return "SIGPIPE";
|
||||
case SIGALRM: return "SIGALRM";
|
||||
case SIGTERM: return "SIGTERM";
|
||||
case SIGUSR1: return "SIGUSR1";
|
||||
case SIGUSR2: return "SIGUSR2";
|
||||
case SIGCHLD: return "SIGCHLD";
|
||||
case SIGPWR: return "SIGPWR";
|
||||
case SIGWINCH: return "SIGWINCH";
|
||||
case SIGURG: return "SIGURG";
|
||||
case SIGSTOP: return "SIGSTOP";
|
||||
case SIGTSTP: return "SIGTSTP";
|
||||
case SIGCONT: return "SIGCONT";
|
||||
case SIGTTIN: return "SIGTTIN";
|
||||
case SIGTTOU: return "SIGTTOU";
|
||||
case SIGVTALRM: return "SIGVTALRM";
|
||||
case SIGXCPU: return "SIGXCPU";
|
||||
case SIGXFSZ: return "SIGXFSZ";
|
||||
case SIGWAITING: return "SIGWAITING";
|
||||
case SIGLWP: return "SIGLWP";
|
||||
case SIGAIO: return "SIGAIO";
|
||||
default: return "Unknown signal value";
|
||||
case SIGHUP: return "Hangup";
|
||||
case SIGINT: return "Interrupt";
|
||||
case SIGQUIT: return "Quit";
|
||||
case SIGILL: return "Illegal instruction";
|
||||
case SIGTRAP: return "Trace/breakpoint trap";
|
||||
case SIGABRT: return "Aborted";
|
||||
case SIGBUS: return "Bus Error";
|
||||
case SIGFPE: return "Floating point exception";
|
||||
case SIGKILL: return "Killed";
|
||||
case SIGUSR1: return "User defined signal 1";
|
||||
case SIGSEGV: return "Segmentation fault";
|
||||
case SIGUSR2: return "User defined signal 2";
|
||||
case SIGPIPE: return "Broken pipe";
|
||||
case SIGALRM: return "Alarm clock";
|
||||
case SIGTERM: return "Terminated";
|
||||
case SIGSYS: return "Bad system call";
|
||||
case SIGCHLD: return "Child exited";
|
||||
case SIGCONT: return "Continued";
|
||||
case SIGSTOP: return "Stopped (signal)";
|
||||
case SIGTSTP: return "Stopped";
|
||||
case SIGTTIN: return "Stopped (tty input)";
|
||||
case SIGTTOU: return "Stopped (tty output)";
|
||||
case SIGURG: return "Urgent I/O condition";
|
||||
case SIGXCPU: return "CPU time limit exceeded";
|
||||
case SIGXFSZ: return "File size limit exceeded";
|
||||
case SIGVTALRM: return "Virtual timer expired";
|
||||
case SIGPWR: return "Power Fail/Restart";
|
||||
case SIGWINCH: return "Window changed";
|
||||
default: break;
|
||||
}
|
||||
|
||||
if ( SIGRTMIN <= signum && signum <= SIGRTMAX )
|
||||
return "Real-time signal";
|
||||
|
||||
return "Unknown signal value";
|
||||
}
|
||||
|
||||
extern "C" char* strsignal(int signum)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -22,13 +22,13 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
DEFN_SYSCALL1(int, sys_exit, SYSCALL_EXIT, int);
|
||||
#include <unistd.h>
|
||||
|
||||
extern "C" void _exit(int status)
|
||||
{
|
||||
sys_exit(status);
|
||||
int exit_code = WCONSTRUCT(WNATURE_EXITED, status, 0);
|
||||
exit_thread(exit_code, EXIT_THREAD_PROCESS, NULL);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -22,11 +22,18 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern "C" pid_t __call_tfork_with_regs(int flags);
|
||||
extern "C" pid_t __sfork(int flags, struct tfork* regs);
|
||||
|
||||
extern "C" pid_t sfork(int flags)
|
||||
{
|
||||
return __call_tfork_with_regs(flags);
|
||||
struct tfork regs;
|
||||
memset(®s, 0, sizeof(regs));
|
||||
regs.altstack.ss_flags = SS_DISABLE;
|
||||
sigprocmask(SIG_SETMASK, NULL, ®s.sigmask);
|
||||
regs.altstack.ss_flags = SS_DISABLE;
|
||||
return __sfork(flags, ®s);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern "C" long sysconf(int name)
|
||||
|
@ -34,6 +35,7 @@ extern "C" long sysconf(int name)
|
|||
case _SC_PAGESIZE: case _SC_PAGE_SIZE:
|
||||
return getpagesize();
|
||||
case _SC_OPEN_MAX: return 0x10000;
|
||||
case _SC_RTSIG_MAX: return (SIGRTMAX+1) - SIGRTMIN;
|
||||
default:
|
||||
fprintf(stderr, "%s:%u warning: %s(%i) is unsupported\n",
|
||||
__FILE__, __LINE__, __func__, name);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -25,9 +25,9 @@
|
|||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
DEFN_SYSCALL2(pid_t, sys_tfork, SYSCALL_TFORK, int, tforkregs_t*);
|
||||
DEFN_SYSCALL2(pid_t, sys_tfork, SYSCALL_TFORK, int, struct tfork*);
|
||||
|
||||
extern "C" pid_t tfork(int flags, tforkregs_t* regs)
|
||||
extern "C" pid_t tfork(int flags, struct tfork* regs)
|
||||
{
|
||||
return sys_tfork(flags, regs);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -27,48 +27,45 @@
|
|||
|
||||
.section .text
|
||||
|
||||
.globl __call_tfork_with_regs
|
||||
.type __call_tfork_with_regs, @function
|
||||
__call_tfork_with_regs:
|
||||
.globl __sfork
|
||||
.type __sfork, @function
|
||||
__sfork:
|
||||
pushq %rbp
|
||||
movq %rsp, %rbp
|
||||
|
||||
# Save the flags parameter so rdmsr won't trash it and align stack.
|
||||
pushq %rdi
|
||||
sub $8, %rsp
|
||||
pushq %rsi
|
||||
|
||||
# The actual system call expects a struct tforkregs_x64 containing the state
|
||||
# of each register in the child. Since we create an identical copy, we
|
||||
# simply set each member of the structure to our own state. Note that since
|
||||
# the stack goes downwards, we create it in the reverse order.
|
||||
movl $MSRID_GSBASE, %edi
|
||||
call rdmsr
|
||||
pushq %rax
|
||||
movq $.Lafter_fork, (0 * 8)(%rsi) # rip
|
||||
movq $0, (1 * 8)(%rsi) # rax, result is 0 for child
|
||||
movq %rbx, (2 * 8)(%rsi)
|
||||
movq %rcx, (3 * 8)(%rsi)
|
||||
movq %rdx, (4 * 8)(%rsi)
|
||||
movq %rdi, (5 * 8)(%rsi)
|
||||
movq %rsi, (6 * 8)(%rsi)
|
||||
movq %rsp, (7 * 8)(%rsi)
|
||||
movq %rbp, (8 * 8)(%rsi)
|
||||
movq %r8, (9 * 8)(%rsi)
|
||||
movq %r9, (10 * 8)(%rsi)
|
||||
movq %r10, (11 * 8)(%rsi)
|
||||
movq %r11, (12 * 8)(%rsi)
|
||||
movq %r12, (13 * 8)(%rsi)
|
||||
movq %r13, (14 * 8)(%rsi)
|
||||
movq %r14, (15 * 8)(%rsi)
|
||||
movq %r15, (16 * 8)(%rsi)
|
||||
pushfq
|
||||
popq %rax
|
||||
movq %rax, (17 * 8)(%rsi) # rflags
|
||||
movl $MSRID_FSBASE, %edi
|
||||
call rdmsr
|
||||
pushq %rax
|
||||
movq -8(%rbp), %rdi
|
||||
pushfq
|
||||
pushq %r15
|
||||
pushq %r14
|
||||
pushq %r13
|
||||
pushq %r12
|
||||
pushq %r11
|
||||
pushq %r10
|
||||
pushq %r9
|
||||
pushq %r8
|
||||
pushq %rbp
|
||||
pushq %rsp
|
||||
pushq %rsi
|
||||
pushq %rdi
|
||||
pushq %rdx
|
||||
pushq %rcx
|
||||
pushq %rbx
|
||||
pushq $0 # rax, result of sfork is 0 for the child.
|
||||
pushq $.Lafter_fork # rip, child will start execution from here.
|
||||
movq 0(%rsp), %rsi
|
||||
movq %rax, (18 * 8)(%rsi) # fsbase
|
||||
movl $MSRID_GSBASE, %edi
|
||||
call rdmsr
|
||||
movq 0(%rsp), %rsi
|
||||
movq %rax, (19 * 8)(%rsi) # gsbase
|
||||
movq 8(%rsp), %rdi
|
||||
|
||||
# Call tfork with a nice pointer to our structure.
|
||||
movq %rsp, %rsi
|
||||
call tfork
|
||||
|
||||
.Lafter_fork:
|
||||
|
@ -77,4 +74,4 @@ __call_tfork_with_regs:
|
|||
# which does that for us.
|
||||
leaveq
|
||||
retq
|
||||
.size __call_tfork_with_regs, . - __call_tfork_with_regs
|
||||
.size __sfork, . - __sfork
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -22,41 +22,88 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#define SIG_SETMASK 2
|
||||
|
||||
/*
|
||||
* sigjmp_buf[0] = %rbx
|
||||
* sigjmp_buf[1] = %rsp
|
||||
* sigjmp_buf[2] = %rbp
|
||||
* sigjmp_buf[3] = %r12
|
||||
* sigjmp_buf[4] = %r13
|
||||
* sigjmp_buf[5] = %r14
|
||||
* sigjmp_buf[6] = %r15
|
||||
* sigjmp_buf[7] = <return-address>
|
||||
* sigjmp_buf[8] = <non-zero if sigmask saved>
|
||||
* sigjmp_buf[9...] = <saved sigmask if sigjmp_buf[8] != 0>
|
||||
*/
|
||||
|
||||
.global setjmp
|
||||
.type setjmp, @function
|
||||
setjmp:
|
||||
# TODO: Floating point stuff!
|
||||
mov %rbx, 0x00(%rdi)
|
||||
mov %rsp, 0x08(%rdi)
|
||||
mov %rbp, 0x10(%rdi)
|
||||
mov %r12, 0x18(%rdi)
|
||||
mov %r13, 0x20(%rdi)
|
||||
mov %r14, 0x28(%rdi)
|
||||
mov %r15, 0x30(%rdi)
|
||||
mov 0(%rsp), %rax
|
||||
mov %rax, 0x38(%rdi)
|
||||
xorl %eax, %eax
|
||||
.Lsetjmp_return:
|
||||
ret
|
||||
movl $1, %esi # setjmp saves the signal mask on Sortix
|
||||
jmp 1f
|
||||
.size setjmp, . - setjmp
|
||||
|
||||
.global sigsetjmp
|
||||
.type sigsetjmp, @function
|
||||
sigsetjmp:
|
||||
mov %esi, %esi # clear upper 32-bit bits
|
||||
testl %esi, %esi
|
||||
jz 2f
|
||||
1: push %rdi
|
||||
push %rsi
|
||||
lea (9 * 8)(%rdi), %rdx # oldset
|
||||
xor %esi, %esi # set
|
||||
xor %edi, %edi # how (ignored because set is NULL)
|
||||
call sigprocmask # assumes sigprocmask is per-thread on Sortix
|
||||
pop %rsi
|
||||
pop %rdi
|
||||
2: mov 0(%rsp), %rax
|
||||
mov %rbx, (0 * 8)(%rdi)
|
||||
mov %rsp, (1 * 8)(%rdi)
|
||||
mov %rbp, (2 * 8)(%rdi)
|
||||
mov %r12, (3 * 8)(%rdi)
|
||||
mov %r13, (4 * 8)(%rdi)
|
||||
mov %r14, (5 * 8)(%rdi)
|
||||
mov %r15, (6 * 8)(%rdi)
|
||||
mov %rax, (7 * 8)(%rdi)
|
||||
mov %rsi, (8 * 8)(%rdi)
|
||||
xorl %eax, %eax
|
||||
ret
|
||||
.size sigsetjmp, . - sigsetjmp
|
||||
|
||||
.global longjmp
|
||||
.type longjmp, @function
|
||||
longjmp:
|
||||
jmp siglongjmp
|
||||
.size longjmp, . - longjmp
|
||||
|
||||
.global siglongjmp
|
||||
.type siglongjmp, @function
|
||||
siglongjmp:
|
||||
testl %esi, %esi
|
||||
jnz 1f
|
||||
mov $1, %esi
|
||||
1:
|
||||
# TODO: Floating point stuff!
|
||||
mov 0x00(%rdi), %rbx
|
||||
mov 0x08(%rdi), %rsp
|
||||
mov 0x10(%rdi), %rbp
|
||||
mov 0x18(%rdi), %r12
|
||||
mov 0x20(%rdi), %r13
|
||||
mov 0x28(%rdi), %r14
|
||||
mov 0x30(%rdi), %r15
|
||||
mov 0x38(%rdi), %rax
|
||||
mov %rax, 0(%rsp)
|
||||
mov %esi, %eax
|
||||
jmp .Lsetjmp_return
|
||||
.size longjmp, . - longjmp
|
||||
movl $1, %esi
|
||||
1: movq (8 * 8)(%rdi), %rdx
|
||||
testq %rdx, %rdx
|
||||
jz 2f
|
||||
pushq %rdi
|
||||
pushq %rsi
|
||||
leaq (9 * 8)(%rdi), %rsi # set
|
||||
movl $SIG_SETMASK, %edi # how
|
||||
xorl %edx, %edx # oldset
|
||||
call sigprocmask
|
||||
popq %rsi
|
||||
popq %rdi
|
||||
2: movq (0 * 8)(%rdi), %rbx
|
||||
movq (1 * 8)(%rdi), %rsp
|
||||
movq (2 * 8)(%rdi), %rbp
|
||||
movq (3 * 8)(%rdi), %r12
|
||||
movq (4 * 8)(%rdi), %r13
|
||||
movq (5 * 8)(%rdi), %r14
|
||||
movq (6 * 8)(%rdi), %r15
|
||||
movq (7 * 8)(%rdi), %rax
|
||||
movq %rax, 0(%rsp)
|
||||
movl %esi, %eax
|
||||
ret
|
||||
.size siglongjmp, . - siglongjmp
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -27,38 +27,45 @@
|
|||
|
||||
.section .text
|
||||
|
||||
.globl __call_tfork_with_regs
|
||||
.type __call_tfork_with_regs, @function
|
||||
__call_tfork_with_regs:
|
||||
.globl __sfork
|
||||
.type __sfork, @function
|
||||
__sfork:
|
||||
pushl %ebp
|
||||
movl %esp, %ebp
|
||||
|
||||
# The actual system call expects a struct tforkregs_x86 containing the state
|
||||
# of each register in the child. Since we create an identical copy, we
|
||||
# simply set each member of the structure to our own state. Note that since
|
||||
# the stack goes downwards, we create it in the reverse order.
|
||||
pushl $MSRID_GSBASE
|
||||
call rdmsr
|
||||
movl %eax, (%esp)
|
||||
movl 12(%ebp), %ecx
|
||||
push %ecx
|
||||
movl 8(%ebp), %edx
|
||||
push %edx
|
||||
# -- stack is 16-byte aligned -- #
|
||||
|
||||
movl $.Lafter_fork, (0 * 4)(%ecx) # eip
|
||||
movl $0, (1 * 4)(%ecx) # rax, result is 0 for child
|
||||
movl %ebx, (2 * 4)(%ecx)
|
||||
movl %ecx, (3 * 4)(%ecx)
|
||||
movl %edx, (4 * 4)(%ecx)
|
||||
movl %edi, (5 * 4)(%ecx)
|
||||
movl %esi, (6 * 4)(%ecx)
|
||||
movl %esp, (7 * 4)(%ecx)
|
||||
movl %ebp, (8 * 4)(%ecx)
|
||||
pushfl
|
||||
popl %eax
|
||||
movl %eax, (9 * 4)(%ecx) # eflags
|
||||
|
||||
subl $12, %esp
|
||||
pushl $MSRID_FSBASE
|
||||
call rdmsr
|
||||
movl %eax, (%esp)
|
||||
pushfl
|
||||
pushl %ebp
|
||||
pushl %esp
|
||||
pushl %esi
|
||||
pushl %edi
|
||||
pushl %edx
|
||||
pushl %ecx
|
||||
pushl %ebx
|
||||
pushl $0 # eax, result of sfork (0 for the child).
|
||||
pushl $.Lafter_fork # rip, child will start execution from here.
|
||||
movl 12(%ebp), %ecx
|
||||
movl %eax, (10 * 4)(%ecx) # fsbase
|
||||
addl $16, %esp
|
||||
|
||||
subl $12, %esp
|
||||
pushl $MSRID_GSBASE
|
||||
call rdmsr
|
||||
movl 12(%ebp), %ecx
|
||||
movl %eax, (11 * 4)(%ecx) # gsbase
|
||||
addl $16, %esp
|
||||
|
||||
# Call tfork with a nice pointer to our structure. Note that %edi contains
|
||||
# the flag parameter that this function accepted.
|
||||
movl 8(%ebp), %edx # flags parameter, edx need not be preserved.
|
||||
pushl %esp
|
||||
pushl %edx
|
||||
call tfork
|
||||
|
||||
.Lafter_fork:
|
||||
|
@ -67,4 +74,4 @@ __call_tfork_with_regs:
|
|||
# which does that for us.
|
||||
leavel
|
||||
retl
|
||||
.size __call_tfork_with_regs, . - __call_tfork_with_regs
|
||||
.size __sfork, . - __sfork
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*******************************************************************************
|
||||
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013.
|
||||
Copyright(C) Jonas 'Sortie' Termansen 2013, 2014.
|
||||
|
||||
This file is part of the Sortix C Library.
|
||||
|
||||
|
@ -22,40 +22,86 @@
|
|||
|
||||
*******************************************************************************/
|
||||
|
||||
#define SIG_SETMASK 2
|
||||
|
||||
/*
|
||||
* sigjmp_buf[0] = %ebx
|
||||
* sigjmp_buf[1] = %esi
|
||||
* sigjmp_buf[2] = %edi
|
||||
* sigjmp_buf[3] = %ebp
|
||||
* sigjmp_buf[4] = %esp
|
||||
* sigjmp_buf[5] = <return-address>
|
||||
* sigjmp_buf[6] = <non-zero if sigmask saved>
|
||||
* sigjmp_buf[7...] = <saved sigmask if sigjmp_buf[6] != 0>
|
||||
*/
|
||||
|
||||
.global setjmp
|
||||
.type setjmp, @function
|
||||
setjmp:
|
||||
mov 4(%esp), %ecx
|
||||
# TODO: Floating point stuff!
|
||||
mov %ebx, 0x00(%ecx)
|
||||
mov %esi, 0x04(%ecx)
|
||||
mov %edi, 0x08(%ecx)
|
||||
mov %ebp, 0x0C(%ecx)
|
||||
mov %esp, 0x10(%ecx)
|
||||
mov 0(%esp), %eax
|
||||
mov %eax, 0x14(%ecx)
|
||||
xorl %eax, %eax
|
||||
.Lsetjmp_return:
|
||||
ret
|
||||
# setjmp saves the signal mask on Sortix
|
||||
jmp 1f
|
||||
.size setjmp, . - setjmp
|
||||
|
||||
.global sigsetjmp
|
||||
.type sigsetjmp, @function
|
||||
sigsetjmp:
|
||||
movl 8(%esp), %edx
|
||||
testl %edx, %edx
|
||||
jz 2f
|
||||
1: movl 4(%esp), %ecx
|
||||
leal (7 * 4)(%ecx), %edx
|
||||
pushl %edx # oldset
|
||||
pushl $0 # set
|
||||
pushl $0 # how (ignored because set is NULL)
|
||||
call sigprocmask
|
||||
addl $(3 * 4), %esp
|
||||
movl $1, %edx
|
||||
2: movl 4(%esp), %ecx
|
||||
movl 0(%esp), %eax
|
||||
movl %ebx, (0 * 4)(%ecx)
|
||||
movl %esi, (1 * 4)(%ecx)
|
||||
movl %edi, (2 * 4)(%ecx)
|
||||
movl %ebp, (3 * 4)(%ecx)
|
||||
movl %esp, (4 * 4)(%ecx)
|
||||
movl %eax, (5 * 4)(%ecx)
|
||||
movl %edx, (6 * 4)(%ecx)
|
||||
xorl %eax, %eax
|
||||
ret
|
||||
.size sigsetjmp, . - sigsetjmp
|
||||
|
||||
.global longjmp
|
||||
.type longjmp, @function
|
||||
longjmp:
|
||||
mov 4(%esp), %ecx
|
||||
mov 8(%esp), %edx
|
||||
testl %edx, %edx
|
||||
jnz 1f
|
||||
mov $1, %edx
|
||||
1:
|
||||
# TODO: Floating point stuff!
|
||||
mov 0x00(%ecx), %ebx
|
||||
mov 0x04(%ecx), %esi
|
||||
mov 0x08(%ecx), %edi
|
||||
mov 0x0C(%ecx), %ebp
|
||||
mov 0x10(%ecx), %esp
|
||||
mov 0x14(%ecx), %eax
|
||||
mov %eax, 0(%esp)
|
||||
mov %edx, %eax
|
||||
jmp .Lsetjmp_return
|
||||
jmp siglongjmp
|
||||
.size longjmp, . - longjmp
|
||||
|
||||
.global siglongjmp
|
||||
.type siglongjmp, @function
|
||||
siglongjmp:
|
||||
movl 4(%esp), %ecx
|
||||
movl 8(%esp), %eax
|
||||
testl %eax, %eax
|
||||
jnz 1f
|
||||
movl $1, %eax
|
||||
1: movl (6 * 4)(%ecx), %edx
|
||||
testl %edx, %edx
|
||||
jz 2f
|
||||
pushl %eax
|
||||
pushl %ecx
|
||||
pushl $0 # oldset
|
||||
leal (7 * 4)(%ecx), %edx
|
||||
pushl %edx # set
|
||||
pushl $SIG_SETMASK # how
|
||||
call sigprocmask
|
||||
addl $(3 * 4), %esp
|
||||
popl %ecx
|
||||
popl %eax
|
||||
2: movl (0 * 4)(%ecx), %ebx
|
||||
movl (1 * 4)(%ecx), %esi
|
||||
movl (2 * 4)(%ecx), %edi
|
||||
movl (3 * 4)(%ecx), %ebp
|
||||
movl (4 * 4)(%ecx), %esp
|
||||
movl (5 * 4)(%ecx), %edx
|
||||
movl %edx, 0(%esp)
|
||||
ret
|
||||
.size siglongjmp, . - siglongjmp
|
||||
|
|
|
@ -181,8 +181,6 @@ extern pthread_mutex_t __pthread_keys_lock;
|
|||
extern struct pthread_key* __pthread_keys;
|
||||
extern size_t __pthread_keys_used;
|
||||
extern size_t __pthread_keys_length;
|
||||
extern pthread_mutex_t __pthread_num_threads_lock;
|
||||
extern size_t __pthread_num_threads;
|
||||
|
||||
struct pthread* pthread_allocate_tls(void);
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -71,7 +72,7 @@ const unsigned long FLAGS_ID = 1 << 21; // 0x200000
|
|||
|
||||
#if defined(__i386__)
|
||||
static const unsigned long MINIMUM_STACK_SIZE = 4 * sizeof(unsigned long);
|
||||
static void setup_thread_state(struct pthread* thread, tforkregs_t* regs)
|
||||
static void setup_thread_state(struct pthread* thread, struct tfork* regs)
|
||||
{
|
||||
assert(MINIMUM_STACK_SIZE <= thread->uthread.stack_size);
|
||||
|
||||
|
@ -99,7 +100,7 @@ static void setup_thread_state(struct pthread* thread, tforkregs_t* regs)
|
|||
|
||||
#if defined(__x86_64__)
|
||||
static const unsigned long MINIMUM_STACK_SIZE = 2 * sizeof(unsigned long);
|
||||
static void setup_thread_state(struct pthread* thread, tforkregs_t* regs)
|
||||
static void setup_thread_state(struct pthread* thread, struct tfork* regs)
|
||||
{
|
||||
assert(MINIMUM_STACK_SIZE <= thread->uthread.stack_size);
|
||||
|
||||
|
@ -121,12 +122,6 @@ static void setup_thread_state(struct pthread* thread, tforkregs_t* regs)
|
|||
}
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
{
|
||||
pthread_mutex_t __pthread_num_threads_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
size_t __pthread_num_threads = 1;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
int pthread_create(pthread_t* restrict thread_ptr,
|
||||
const pthread_attr_t* restrict attr,
|
||||
|
@ -225,20 +220,19 @@ int pthread_create(pthread_t* restrict thread_ptr,
|
|||
}
|
||||
|
||||
// Prepare the registers and initial stack for the new thread.
|
||||
tforkregs_t regs;
|
||||
struct tfork regs;
|
||||
setup_thread_state(thread, ®s);
|
||||
memset(®s.altstack, 0, sizeof(regs.altstack));
|
||||
regs.altstack.ss_flags = SS_DISABLE;
|
||||
sigprocmask(SIG_SETMASK, NULL, ®s.sigmask);
|
||||
|
||||
// Create a new thread with the requested state.
|
||||
pthread_mutex_lock(&__pthread_num_threads_lock);
|
||||
if ( tfork(SFTHREAD, ®s) < 0 )
|
||||
{
|
||||
pthread_mutex_unlock(&__pthread_num_threads_lock);
|
||||
munmap(thread->uthread.stack_mmap, thread->uthread.stack_size);
|
||||
munmap(thread->uthread.tls_mmap, thread->uthread.tls_size);
|
||||
return errno;
|
||||
}
|
||||
__pthread_num_threads++;
|
||||
pthread_mutex_unlock(&__pthread_num_threads_lock);
|
||||
|
||||
*thread_ptr = thread;
|
||||
|
||||
|
|
|
@ -56,13 +56,9 @@ void pthread_exit(void* return_value)
|
|||
thread->keys_length = 0;
|
||||
pthread_mutex_unlock(&__pthread_keys_lock);
|
||||
|
||||
pthread_mutex_lock(&__pthread_num_threads_lock);
|
||||
size_t num_threads = __pthread_num_threads--;
|
||||
pthread_mutex_unlock(&__pthread_num_threads_lock);
|
||||
if ( num_threads == 1 )
|
||||
exit(0);
|
||||
pthread_mutex_lock(&thread->detach_lock);
|
||||
thread->exit_result = return_value;
|
||||
int exit_flags = EXIT_THREAD_UNMAP;
|
||||
struct exit_thread extended;
|
||||
memset(&extended, 0, sizeof(extended));
|
||||
extended.unmap_from = thread->uthread.stack_mmap;
|
||||
|
@ -71,13 +67,15 @@ void pthread_exit(void* return_value)
|
|||
{
|
||||
extended.zero_from = &thread->join_lock.lock;
|
||||
extended.zero_size = sizeof(thread->join_lock.lock);
|
||||
exit_thread(0, EXIT_THREAD_UNMAP | EXIT_THREAD_ZERO, &extended);
|
||||
__builtin_unreachable();
|
||||
exit_flags |= EXIT_THREAD_ZERO;
|
||||
}
|
||||
else
|
||||
{
|
||||
munmap(thread->uthread.tls_mmap, thread->uthread.tls_size);
|
||||
exit_thread(0, EXIT_THREAD_UNMAP, &extended);
|
||||
__builtin_unreachable();
|
||||
extended.tls_unmap_from = thread->uthread.tls_mmap;
|
||||
extended.tls_unmap_size = thread->uthread.tls_size;
|
||||
exit_flags |= EXIT_THREAD_TLS_UNMAP;
|
||||
}
|
||||
|
||||
exit_thread(0, EXIT_THREAD_ONLY_IF_OTHERS | exit_flags, &extended);
|
||||
exit(0);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue