diff --git a/.gitignore b/.gitignore index 83212ad0..ea12c3c2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /*.so /*.a builds +sysroot diff --git a/Makefile b/Makefile index 7a2adb52..f18fde64 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,11 @@ ifndef CPU CPU=x86 + MFLAGS:=CPU=$(CPU) +endif + +ifndef SYSROOT + SYSROOT:=$(shell pwd)/sysroot + MFLAGS:=SYSROOT=$(SYSROOT) endif REMOTE=192.168.2.6 @@ -22,9 +28,10 @@ INITRD=sortix/sortix.initrd all: $(INITRD) suball: - (for D in $(MODULES); do $(MAKE) all $(MFLAGS) --directory $$D || exit $?; done) + (for D in $(MODULES); do ($(MAKE) all $(MFLAGS) --directory $$D && $(MAKE) install $(MFLAGS) --directory $$D) || exit $?; done) clean: + rm -rf $(SYSROOT) rm -f $(INITRD) rm -f initrd/* (for D in $(MODULES); do $(MAKE) clean $(MFLAGS) --directory $$D || exit $?; done) diff --git a/libmaxsi/Makefile b/libmaxsi/Makefile index 6e2693fd..c3beaa4f 100644 --- a/libmaxsi/Makefile +++ b/libmaxsi/Makefile @@ -45,6 +45,7 @@ c/h/sys/stat.h \ c/h/sys/types.h \ c/h/sys/wait.h \ c/h/stdio.h \ +c/h/signal.h \ COMMONOBJS=c++.o memory.o string.o error.o format.o SORTIXOBJS:=$(addprefix sortix/,$(COMMONOBJS)) @@ -56,10 +57,12 @@ process.o \ thread.o \ io.o \ init.o \ +signal.o \ +$(CPU)/signal.o \ start.o \ random.o \ -HEADERS=\ +MAXSIHEADERS=\ error.h \ io.h \ memory.h \ @@ -72,6 +75,8 @@ types.h \ format.h \ keyboard.h \ sortedlist.h \ +signal.h \ +signalnum.h \ sortix-vga.h \ sortix-keyboard.h \ sortix-sound.h \ @@ -100,7 +105,7 @@ ifndef LIBMAXSI_NO_LIBC BINS:=$(BINS) libc.a endif - HEADERS:=$(HEADERS) $(CHEADERS) + HEADERS:=$(MAXSIHEADERS) $(CHEADERS) else DEFINES:=$(DEFINES) -DLIBMAXSI_NO_LIBC @@ -173,3 +178,18 @@ sortix/%.o: sortix/%.cpp clean: rm -f *.o sortix/*.o c/*.o x86/*.o x64/*.o *.a *.so $(CHEADERS) $(HEADERS) +# Installation into sysroot +install: + mkdir -p $(SYSROOT)/usr/lib + for F in $(BINS); do cp --preserve=links $$F $(SYSROOT)/usr/lib || exit $?; done + mkdir -p $(SYSROOT)/usr/include + for F in $(CHEADERS); do F=`echo $$F | sed 's/c\/h\///g'`; mkdir -p $(SYSROOT)/usr/include/`dirname $$F`; cp c/h/$$F $(SYSROOT)/usr/include/$$F || exit $?; done + mkdir -p $(SYSROOT)/usr/include/libmaxsi + for F in $(MAXSIHEADERS); do cp $$F $(SYSROOT)/usr/include/libmaxsi || exit $?; done + cp start.o $(SYSROOT)/usr/lib/crt1.o + touch deleteme.cpp + g++ $(CPUFLAGS) -c deleteme.cpp -o deleteme.o + for F in crt0.o crtn.o crtbegin.o crtend.o crtbeginT.o crti.o; do cp deleteme.o $(SYSROOT)/usr/lib/$$F; done + for F in libgcc.so libm.so libstdc++.so; do ld $(CPULDFLAGS) -shared deleteme.o -o $(SYSROOT)/usr/lib/$$F; done + rm -f deleteme.o deleteme.cpp + diff --git a/libmaxsi/c/hsrc/signal.h b/libmaxsi/c/hsrc/signal.h new file mode 100644 index 00000000..b38e59a9 --- /dev/null +++ b/libmaxsi/c/hsrc/signal.h @@ -0,0 +1,80 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi 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. + + LibMaxsi 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 LibMaxsi. If not, see . + + signal.h + Signals. + +******************************************************************************/ + +/* TODO: This does not fully implement POSIX 2008-1 yet! */ + +#ifndef _SIGNAL_H +#define _SIGNAL_H 1 + +#include + +__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 */ + +@include(pid_t.h); + +typedef void (*sighandler_t)(int); + +void SIG_DFL(int signum); +void SIG_IGN(int signum); +void SIG_ERR(int signum); + +sighandler_t signal(int signum, sighandler_t handler); +int kill(pid_t pid, int sig); + +__END_DECLS + +#endif diff --git a/libmaxsi/decl/errno_values.h b/libmaxsi/decl/errno_values.h index 4dfaf979..08a39af8 100644 --- a/libmaxsi/decl/errno_values.h +++ b/libmaxsi/decl/errno_values.h @@ -19,5 +19,6 @@ #define EIO 27 #define ENOEXEC 28 #define EACCESS 29 +#define ESRCH 30 #endif diff --git a/libmaxsi/error.cpp b/libmaxsi/error.cpp index 69956b96..b3f4cdd8 100644 --- a/libmaxsi/error.cpp +++ b/libmaxsi/error.cpp @@ -62,6 +62,7 @@ namespace Maxsi case EIO: return (char*) "Input/output error"; case ENOEXEC: return (char*) "Not executable"; case EACCESS: return (char*) "Permission denied"; + case ESRCH: return (char*) "No such process"; default: return (char*) "Unknown error condition"; } } diff --git a/libmaxsi/hsrc/signal.h b/libmaxsi/hsrc/signal.h new file mode 100644 index 00000000..e0b8e760 --- /dev/null +++ b/libmaxsi/hsrc/signal.h @@ -0,0 +1,42 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi 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. + + LibMaxsi 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 LibMaxsi. If not, see . + + signal.h + Handles the good old unix signals. + +******************************************************************************/ + +#ifndef LIBMAXSI_SIGNAL_H +#define LIBMAXSI_SIGNAL_H + +#include "signalnum.h" + +namespace Maxsi +{ + namespace Signal + { + typedef void (*Handler)(int); + + void Init(); + Handler RegisterHandler(int signum, Handler handler); + } +} + +#endif + diff --git a/libmaxsi/hsrc/signalnum.h b/libmaxsi/hsrc/signalnum.h new file mode 100644 index 00000000..5dc0085f --- /dev/null +++ b/libmaxsi/hsrc/signalnum.h @@ -0,0 +1,71 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi 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. + + LibMaxsi 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 LibMaxsi. If not, see . + + signalnum.h + Declares the signal-related constants. + +******************************************************************************/ + +#ifndef LIBMAXSI_SIGNALNUM_H +#define LIBMAXSI_SIGNALNUM_H + +namespace Maxsi +{ + namespace Signal + { + const int HUP = 1; /* Hangup */ + const int INT = 2; /* Interrupt */ + const int QUIT = 3; /* Quit */ + const int ILL = 4; /* Illegal Instruction */ + const int TRAP = 5; /* Trace/Breakpoint Trap */ + const int ABRT = 6; /* Abort */ + const int EMT = 7; /* Emulation Trap */ + const int FPE = 8; /* Arithmetic Exception */ + const int KILL = 9; /* Killed */ + const int BUS = 10; /* Bus Error */ + const int SEGV = 11; /* Segmentation Fault */ + const int SYS = 12; /* Bad System Call */ + const int PIPE = 13; /* Broken Pipe */ + const int ALRM = 14; /* Alarm Clock */ + const int TERM = 15; /* Terminated */ + const int USR1 = 16; /* User Signal 1 */ + const int USR2 = 17; /* User Signal 2 */ + const int CHLD = 18; /* Child Status */ + const int PWR = 19; /* Power Fail/Restart */ + const int WINCH = 20; /* Window Size Change */ + const int URG = 21; /* Urgent Socket Condition */ + const int STOP = 23; /* Stopped (signal) */ + const int TSTP = 24; /* Stopped (user) */ + const int CONT = 25; /* Continued */ + const int TTIN = 26; /* Stopped (tty input) */ + const int TTOU = 27; /* Stopped (tty output) */ + const int VTALRM = 28; /* Virtual Timer Expired */ + const int XCPU = 30; /* CPU time limit exceeded */ + const int XFSZ = 31; /* File size limit exceeded */ + const int WAITING = 32; /* All LWPs blocked */ + const int LWP = 33; /* Virtual Interprocessor Interrupt for Threads Library */ + const int AIO = 34; /* Asynchronous I/O */ + const int NUMSIGNALS = 35; + + typedef void (*Handler)(int); + } +} + +#endif + diff --git a/libmaxsi/init.cpp b/libmaxsi/init.cpp index 7a9c5eef..7047ec0e 100644 --- a/libmaxsi/init.cpp +++ b/libmaxsi/init.cpp @@ -24,6 +24,7 @@ ******************************************************************************/ #include "platform.h" +#include "signal.h" namespace Maxsi { @@ -31,6 +32,10 @@ namespace Maxsi extern "C" void initialize_standard_library() { + // Initialize stuff such as errno. init_error_functions(); + + // It's probably best to initialize the Unix signals early on. + Signal::Init(); } } diff --git a/libmaxsi/signal.cpp b/libmaxsi/signal.cpp new file mode 100644 index 00000000..4c09889a --- /dev/null +++ b/libmaxsi/signal.cpp @@ -0,0 +1,127 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi 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. + + LibMaxsi 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 LibMaxsi. If not, see . + + signal.cpp + Handles the good old unix signals. + +******************************************************************************/ + +#include "platform.h" +#include "string.h" +#include "memory.h" +#include "syscall.h" +#include "process.h" +#include "signal.h" +#include + +namespace Maxsi +{ + namespace Signal + { + void Core(int signum) + { + Process::Exit(128 + signum); + } + + extern "C" void SIG_DFL(int signum) + { + if ( signum == Signal::HUP ) { Process::Exit(128 + signum); } else + if ( signum == Signal::INT ) { Process::Exit(128 + signum); } else + if ( signum == Signal::QUIT ) { Core(signum); } else + if ( signum == Signal::TRAP ) { Core(signum); } else + if ( signum == Signal::ABRT ) { Core(signum); } else + if ( signum == Signal::EMT ) { Core(signum); } else + if ( signum == Signal::FPE ) { Core(signum); } else + if ( signum == Signal::KILL ) { Process::Exit(128 + signum); } else + if ( signum == Signal::BUS ) { Core(signum); } else + if ( signum == Signal::SEGV ) { Core(signum); } else + if ( signum == Signal::SYS ) { Core(signum); } else + if ( signum == Signal::PIPE ) { Process::Exit(128 + signum); } else + if ( signum == Signal::ALRM ) { Process::Exit(128 + signum); } else + if ( signum == Signal::TERM ) { Process::Exit(128 + signum); } else + if ( signum == Signal::USR1 ) { Process::Exit(128 + signum); } else + if ( signum == Signal::USR2 ) { Process::Exit(128 + signum); } else + if ( signum == Signal::CHLD ) { /* Ignore this signal. */ } else + if ( signum == Signal::PWR ) { /* Ignore this signal. */ } else + if ( signum == Signal::WINCH ) { /* Ignore this signal. */ } else + if ( signum == Signal::URG ) { /* Ignore this signal. */ } else + if ( signum == Signal::CONT ) { /* Ignore this signal. */ } else + if ( signum == Signal::VTALRM ) { /* Ignore this signal. */ } else + if ( signum == Signal::XCPU ) { Core(signum); } else + if ( signum == Signal::XFSZ ) { Core(signum); } else + if ( signum == Signal::WAITING ) { /* Ignore this signal. */ } else + if ( signum == Signal::LWP ) { /* Ignore this signal. */ } else + if ( signum == Signal::AIO ) { /* Ignore this signal. */ } else + { /* Ignore this signal. */ } + } + + extern "C" void SIG_IGN(int /*signum*/) + { + + } + + extern "C" void SIG_ERR(int /*signum*/) + { + Process::Abort(); + } + + const int MAX_SIGNALS = 128; + sighandler_t handlers[MAX_SIGNALS]; + + extern "C" void SignalHandlerAssembly(int signum); + extern "C" void SignalHandler(int signum) + { + if ( 0 <= signum && signum < (int) MAX_SIGNALS ) + { + handlers[signum](signum); + } + } + + DEFN_SYSCALL1_VOID(SysRegisterSignalHandler, 29, sighandler_t); + DEFN_SYSCALL0_VOID(SysSigReturn, 30); + DEFN_SYSCALL2(int, SysKill, 31, pid_t, int); + + void Init() + { + for ( int i = 0; i < MAX_SIGNALS; i++ ) + { + handlers[i] = SIG_DFL; + } + + // Tell the kernel which function we want called upon signals. + SysRegisterSignalHandler(&SignalHandlerAssembly); + } + + Handler RegisterHandler(int signum, Handler handler) + { + if ( signum < 0 || MAX_SIGNALS <= signum ) { return SIG_ERR; } + return handlers[signum] = handler; + } + + extern "C" sighandler_t signal(int signum, sighandler_t handler) + { + return RegisterHandler(signum, handler); + } + + extern "C" int kill(pid_t pid, int signum) + { + return SysKill(pid, signum); + } + } +} diff --git a/libmaxsi/x64/signal.s b/libmaxsi/x64/signal.s new file mode 100644 index 00000000..0fc1c2f7 --- /dev/null +++ b/libmaxsi/x64/signal.s @@ -0,0 +1,38 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi 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. + + LibMaxsi 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 LibMaxsi. If not, see . + + signal.s + An assembly stub that for handling unix signals. + +******************************************************************************/ + +.globl SignalHandlerAssembly + +.section .text + +.type SignalHandlerAssembly, @function +SignalHandlerAssembly: + + # The kernel put the signal id in edi. + call SignalHandler + + # Return control to the kernel, so normal computation can resume normally. + movl $3, %eax + int $0x80 + diff --git a/libmaxsi/x86/signal.s b/libmaxsi/x86/signal.s new file mode 100644 index 00000000..aa311db4 --- /dev/null +++ b/libmaxsi/x86/signal.s @@ -0,0 +1,43 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi 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. + + LibMaxsi 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 LibMaxsi. If not, see . + + signal.s + An assembly stub that for handling unix signals. + +******************************************************************************/ + +.globl SignalHandlerAssembly + +.section .text + +.type SignalHandlerAssembly, @function +SignalHandlerAssembly: + + # The kernel put the signal id in edi. + pushl %edi + call SignalHandler + + # Restore the stack as it was. + addl $4, %esp + + # Now that the stack is intact, return control to the kernel, so normal + # computation can resume normally. + movl $30, %eax # SysSigReturn + int $0x80 + diff --git a/mkinitrd/Makefile b/mkinitrd/Makefile index b849e402..a008f0eb 100644 --- a/mkinitrd/Makefile +++ b/mkinitrd/Makefile @@ -11,3 +11,5 @@ all: $(BINARIES) clean: rm -f $(BINARIES) +install: + diff --git a/sortix/Makefile b/sortix/Makefile index af2b8be9..893e3340 100644 --- a/sortix/Makefile +++ b/sortix/Makefile @@ -74,10 +74,11 @@ pipe.o \ filesystem.o \ directory.o \ mount.o \ +signal.o \ fs/devfs.o \ fs/initfs.o \ fs/ramfs.o \ -../libmaxsi/libmaxsi-sortix.a +../libmaxsi/libmaxsi-sortix.a \ JSOBJS:=$(subst .o,-js.o,$(OBJS)) @@ -127,20 +128,8 @@ sortix.bin: sortix-$(BUILDID).tmp clean: for D in $(DIRS); do rm -fv $$D/*.o $$D/*.bin $$D/*.out $$D/*.tmp; done -# Local machine +# Installation into sysroot +install: + mkdir -p $(SYSROOT)/usr/include/sortix + cp $(CPU)/bits.h $(SYSROOT)/usr/include/sortix/bits.h -install: sortix.bin - cp sortix.bin /boot - -uninstall: - rm -f /boot/sortix.bin - -# Remote machine - -install-remote: sortix.bin - scp -r ./ 192.168.2.6:/home/sortie/Desktop/sortix - scp sortix.bin root@192.168.2.6:/boot - ssh root@192.168.2.6 "init 6" - -uninstall-remote: - ssh root@192.168.2.6 "rm /boot/sortix.bin" diff --git a/sortix/kernel.cpp b/sortix/kernel.cpp index 78961352..b7b8c5bb 100644 --- a/sortix/kernel.cpp +++ b/sortix/kernel.cpp @@ -241,6 +241,9 @@ namespace Sortix // Initialize the process system. Process::Init(); + // Initialize the thread system. + Thread::Init(); + // Initialize the IO system. IO::Init(); diff --git a/sortix/process.cpp b/sortix/process.cpp index b4fd9604..b2cfc9b2 100644 --- a/sortix/process.cpp +++ b/sortix/process.cpp @@ -153,7 +153,7 @@ namespace Sortix if ( clonesegments == NULL ) { delete clone; return NULL; } } - // Fork address-space here and copy memory somehow. + // Fork address-space here and copy memory. clone->addrspace = Memory::Fork(); if ( !clone->addrspace ) { diff --git a/sortix/scheduler.cpp b/sortix/scheduler.cpp index 4fbdec08..136edd41 100644 --- a/sortix/scheduler.cpp +++ b/sortix/scheduler.cpp @@ -132,6 +132,8 @@ namespace Sortix Memory::SwitchAddressSpace(newaddrspace); currentthread = nextthread; + nextthread->HandleSignal(regs); + LogEndContextSwitch(currentthread, regs); if ( currentthread->scfunc ) { Syscall::Resume(regs); } diff --git a/sortix/signal.cpp b/sortix/signal.cpp new file mode 100644 index 00000000..ce18013b --- /dev/null +++ b/sortix/signal.cpp @@ -0,0 +1,244 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + 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 . + + signal.cpp + Classes and functions making it easier to handle Unix signals. + +******************************************************************************/ + +#include "platform.h" +#include +#include "panic.h" +#include "signal.h" + +using namespace Maxsi; + +namespace Sortix +{ + const int PRIORITY_NORMAL = 0; + const int PRIORITY_HIGH = 1; + const int PRIORITY_STOP = 2; + const int PRIORITY_CORE = 3; + const int PRIORITY_KILL = 4; + + const int PRIORITIES[Maxsi::Signal::NUMSIGNALS] = + { + PRIORITY_NORMAL, // unused + PRIORITY_NORMAL, // SIGHUP + PRIORITY_NORMAL, // SIGINT + PRIORITY_NORMAL, // SIGQUIT + PRIORITY_CORE, // SIGILL + PRIORITY_CORE, // SIGTRAP + PRIORITY_CORE, // SIGABRT + PRIORITY_CORE, // SIGEMT + PRIORITY_CORE, // SIGFPE + PRIORITY_KILL, // SIGKILL + PRIORITY_CORE, // SIGBUS + PRIORITY_CORE, // SIGSEGV + PRIORITY_CORE, // SIGSYS + PRIORITY_NORMAL, // SIGPIPE + PRIORITY_NORMAL, // SIGALRM + PRIORITY_NORMAL, // SIGTERM + PRIORITY_NORMAL, // SIGUSR1 + PRIORITY_NORMAL, // SIGUSR2 + PRIORITY_NORMAL, // SIGCHLD + PRIORITY_HIGH, // SIGPWR + PRIORITY_NORMAL, // SIGWINCH + PRIORITY_NORMAL, // SIGURG + PRIORITY_NORMAL, // obsolete + PRIORITY_STOP, // SIGSTOP + PRIORITY_STOP, // SIGTSTP + PRIORITY_STOP, // SIGCONT + PRIORITY_STOP, // SIGTTIN + PRIORITY_STOP, // SIGTTOU + PRIORITY_NORMAL, // SIGVTALRM + PRIORITY_NORMAL, // obsolete + PRIORITY_CORE, // SIGXCPU + PRIORITY_CORE, // SIGXFSZ + PRIORITY_NORMAL, // SIGCORE + PRIORITY_NORMAL, // SIGLWP + PRIORITY_NORMAL, // SIGAIO + }; + + // Returns true of the exact ordering of this signal version others aren't + // important - if it returns false, then this signal will be put in the + // queue according to priority, instead of being merged into another signal + // with the same signum. + bool Unifiable(int /*signum*/) + { + return true; + } + + // Returns whether a specific signal is more important to deliver than + // another. This is used to schedule signals. + int CompareSignalPriority(int siga, int sigb) + { + int prioa = PRIORITY_NORMAL; + int priob = PRIORITY_NORMAL; + + if ( siga < Maxsi::Signal::NUMSIGNALS ) { prioa = PRIORITIES[siga]; } + if ( sigb < Maxsi::Signal::NUMSIGNALS ) { priob = PRIORITIES[sigb]; } + + if ( prioa < priob ) { return -1; } else + if ( prioa > priob ) { return 1; } + return 0; + } + + SignalQueue::SignalQueue() + { + queue = NULL; + } + + SignalQueue::~SignalQueue() + { + while ( queue ) + { + Signal* todelete = queue; + queue = queue->nextsignal; + delete todelete; + } + } + + // Queues the signal and schedules it for processing. + bool SignalQueue::Push(int signum) + { + ASSERT(0 <= signum && signum < 128); + + if ( Unifiable(signum) ) + { + for ( Signal* signal = queue; signal != NULL; signal = signal->nextsignal ) + { + if ( signal->signum != signum ) { continue; } + + signal->numpending++; + return true; + } + } + + Signal* signal = new Signal; + if ( !signal ) { return false; } + + signal->signum = signum; + signal->numpending = 1; + signal->nextsignal = NULL; + signal->returncode = 128 + signum; + + Insert(signal); + + return true; + } + + // Insert the signal in O(N), which is pretty fast for small Ns. + void SignalQueue::Insert(Signal* signal) + { + if ( !queue ) + { + queue = signal; + last = signal; + return; + } + + // If the signal is to be inserted last, then just do it quickly. + if ( last != NULL && 0 <= CompareSignalPriority(last->signum, signal->signum) ) + { + last->nextsignal = signal; + signal->nextsignal = NULL; + last = signal; + return; + } + + // Check if the signal should be inserted first. + if ( queue != NULL && CompareSignalPriority(queue->signum, signal->signum) < 0 ) + { + signal->nextsignal = queue; + queue = signal; + return; + } + + // Find where the signal should be inserted. + for ( Signal* tmp = queue; tmp != NULL; tmp = tmp->nextsignal ) + { + Signal* next = tmp->nextsignal; + + if ( next != NULL && CompareSignalPriority(next->signum, signal->signum) < 0 ) + { + tmp->nextsignal = signal; + signal->nextsignal = next; + return; + } + + if ( next == NULL ) + { + tmp->nextsignal = signal; + signal->nextsignal = NULL; + last = signal; + return; + } + } + } + + // Given the stack of currently processing signals, return a new signal if + // it is more important to handle at this point. + Signal* SignalQueue::Pop(Signal* current) + { + if ( queue == NULL ) { return NULL; } + + bool returnqueue = false; + + // If we are currently handling no signal, then just return the first. + if ( current == NULL ) { returnqueue = true; } + + // If we are handling a signal, only override it with another if it is + // more important. + else if ( CompareSignalPriority(current->signum, queue->signum) < 0 ) + { + returnqueue = true; + } + + if ( returnqueue ) + { + Signal* result = queue; + queue = queue->nextsignal; + result->nextsignal = NULL; + return result; + } + + return NULL; + } + + Signal* Signal::Fork() + { + Signal* clone = new Signal(); + if ( !clone ) { return NULL; } + + Memory::Copy(clone, this, sizeof(Signal)); + + Signal* nextsignalclone = NULL; + if ( nextsignal ) + { + nextsignalclone = nextsignal->Fork(); + if ( !nextsignalclone ) { delete clone; return NULL; } + } + + clone->nextsignal = nextsignalclone; + + return clone; + } +} + diff --git a/sortix/signal.h b/sortix/signal.h new file mode 100644 index 00000000..557b8092 --- /dev/null +++ b/sortix/signal.h @@ -0,0 +1,99 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + 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 . + + signal.h + Classes and functions making it easier to handle Unix signals. + +******************************************************************************/ + +#ifndef SORTIX_SIGNAL_H +#define SORTIX_SIGNAL_H + +#include + +namespace Sortix +{ + #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 */ + + struct Signal + { + int signum; + int returncode; + unsigned numpending; + CPU::InterruptRegisters regs; + Signal* nextsignal; + + public: + Signal* Fork(); + + }; + + class SignalQueue + { + public: + SignalQueue(); + ~SignalQueue(); + + private: + Signal* queue; + Signal* last; + + public: + bool Push(int signum); + Signal* Pop(Signal* current); + + private: + void Insert(Signal* signal); + + }; +} + +#endif + diff --git a/sortix/syscallnum.h b/sortix/syscallnum.h index b07a59a2..6f4d71e6 100644 --- a/sortix/syscallnum.h +++ b/sortix/syscallnum.h @@ -54,7 +54,10 @@ #define SYSCALL_GETCWD 26 #define SYSCALL_UNLINK 27 #define SYSCALL_REGISTER_ERRNO 28 -#define SYSCALL_MAX_NUM 29 /* index of highest constant + 1 */ +#define SYSCALL_REGISTER_SIGNAL_HANDLER 29 +#define SYSCALL_SIGRETURN 30 +#define SYSCALL_KILL 31 +#define SYSCALL_MAX_NUM 32 /* index of highest constant + 1 */ #endif diff --git a/sortix/thread.cpp b/sortix/thread.cpp index 21e4f2ee..fed4172f 100644 --- a/sortix/thread.cpp +++ b/sortix/thread.cpp @@ -23,12 +23,16 @@ ******************************************************************************/ #include "platform.h" +#include #include #include "process.h" #include "thread.h" #include "scheduler.h" #include "memorymanagement.h" #include "time.h" +#include "syscall.h" + +using namespace Maxsi; namespace Sortix { @@ -46,6 +50,8 @@ namespace Sortix Maxsi::Memory::Set(®isters, 0, sizeof(registers)); ready = false; scfunc = NULL; + currentsignal = NULL; + sighandler = NULL; ResetCallbacks(); } @@ -65,6 +71,7 @@ namespace Sortix schedulerlistprev = NULL; schedulerlistnext = NULL; scfunc = NULL; + sighandler = forkfrom->sighandler; ResetCallbacks(); } @@ -78,6 +85,14 @@ namespace Sortix ASSERT(CurrentProcess() == process); ASSERT(nextsleepingthread == NULL); + // Delete information about signals being processed. + while ( currentsignal ) + { + Signal* todelete = currentsignal; + currentsignal = currentsignal->nextsignal; + delete todelete; + } + Memory::UnmapRangeUser(stackpos, stacksize); } @@ -85,8 +100,26 @@ namespace Sortix { ASSERT(ready); + Signal* clonesignal = NULL; + if ( currentsignal ) + { + clonesignal = currentsignal->Fork(); + if ( !clonesignal ) { return NULL; } + } + Thread* clone = new Thread(this); - if ( !clone ) { return NULL; } + if ( !clone ) + { + while ( clonesignal ) + { + Signal* todelete = clonesignal; + clonesignal = clonesignal->nextsignal; + delete todelete; + } + return NULL; + } + + clone->currentsignal = clonesignal; return clone; } @@ -154,4 +187,83 @@ namespace Sortix Scheduler::SetThreadState(this, State::RUNNABLE); } } + + void Thread::HandleSignal(CPU::InterruptRegisters* regs) + { + Signal* override = signalqueue.Pop(currentsignal); + if ( !override ) { return; } + if ( !sighandler ) { delete override; return; } + + if ( override->signum == SIGKILL ) + { + + } + + + override->nextsignal = currentsignal; + Maxsi::Memory::Copy(&override->regs, regs, sizeof(override->regs)); + currentsignal = override; + + HandleSignalCPU(regs); + } + + void SysSigReturn() + { + Thread* thread = CurrentThread(); + if ( !thread->currentsignal ) { return; } + + CPU::InterruptRegisters* dest = Syscall::InterruptRegs(); + CPU::InterruptRegisters* src = &thread->currentsignal->regs; + + Maxsi::Memory::Copy(dest, src, sizeof(CPU::InterruptRegisters)); + thread->currentsignal = thread->currentsignal->nextsignal; + Syscall::AsIs(); + } + + void SysRegisterSignalHandler(sighandler_t sighandler) + { + CurrentThread()->sighandler = sighandler; + } + + int SysKill(pid_t pid, int signum) + { + if ( signum < 0 || 128 <= signum ) { Error::Set(EINVAL); return -1; } + + // Protect the system idle process. + if ( pid == 0 ) { Error::Set(EPERM); return -1; } + + Process* process = Process::Get(pid); + if ( !process ) { Error::Set(ESRCH); return -1; } + + // TODO: Protect init? + // TODO: Check for permission. + // TODO: Check for zombies. + + Thread* currentthread = CurrentThread(); + Thread* thread = NULL; + if ( currentthread->process->pid == pid ) { thread = currentthread; } + if ( !thread ) { thread = process->firstthread; } + if ( !thread ) { Error::Set(ESRCH); return -1; /* TODO: Zombie? */ } + + // TODO: If thread is not runnable, wake it and runs its handler? + if ( !thread->signalqueue.Push(signum) ) + { + // TODO: Possibly kill the process? + } + + if ( thread == currentthread ) + { + Syscall::SyscallRegs()->result = 0; + thread->HandleSignal(Syscall::InterruptRegs()); + } + + return 0; + } + + void Thread::Init() + { + Syscall::Register(SYSCALL_KILL, (void*) SysKill); + Syscall::Register(SYSCALL_REGISTER_SIGNAL_HANDLER, (void*) SysRegisterSignalHandler); + Syscall::Register(SYSCALL_SIGRETURN, (void*) SysSigReturn); + } } diff --git a/sortix/thread.h b/sortix/thread.h index 8823c683..f2126d7a 100644 --- a/sortix/thread.h +++ b/sortix/thread.h @@ -25,6 +25,8 @@ #ifndef SORTIX_THREAD_H #define SORTIX_THREAD_H +#include "signal.h" + namespace Sortix { class Process; @@ -34,6 +36,8 @@ namespace Sortix Thread* CreateThread(addr_t entry, size_t stacksize = 0); Thread* CurrentThread(); + typedef void (*sighandler_t)(int); + class Thread { friend Thread* CreateThread(addr_t entry, size_t stacksize); @@ -41,6 +45,9 @@ namespace Sortix public: enum State { NONE, RUNNABLE, BLOCKING }; + public: + static void Init(); + private: Thread(); Thread(const Thread* forkfrom); @@ -67,6 +74,9 @@ namespace Sortix public: addr_t stackpos; size_t stacksize; + Signal* currentsignal; + SignalQueue signalqueue; + sighandler_t sighandler; // After being created/forked, a thread is not inserted into the scheduler. // Whenever the thread has been safely established within a process, then @@ -84,6 +94,10 @@ namespace Sortix Thread* Fork(); void SaveRegisters(const CPU::InterruptRegisters* src); void LoadRegisters(CPU::InterruptRegisters* dest); + void HandleSignal(CPU::InterruptRegisters* regs); + + private: + void HandleSignalCPU(CPU::InterruptRegisters* regs); public: void* scfunc; diff --git a/sortix/x86/thread.cpp b/sortix/x86/thread.cpp index 92884634..988b13da 100644 --- a/sortix/x86/thread.cpp +++ b/sortix/x86/thread.cpp @@ -106,4 +106,10 @@ namespace Sortix thread->SaveRegisters(®s); } + + void Thread::HandleSignalCPU(CPU::InterruptRegisters* regs) + { + regs->edi = currentsignal->signum; + regs->eip = (size_t) sighandler; + } } diff --git a/utils/Makefile b/utils/Makefile index cfda47a9..84e6410d 100644 --- a/utils/Makefile +++ b/utils/Makefile @@ -16,6 +16,7 @@ help \ uname \ idle \ editor \ +kill \ BINARIES:=$(addprefix $(INITRDDIR)/,$(LOCALBINARIES)) diff --git a/utils/kill.cpp b/utils/kill.cpp new file mode 100644 index 00000000..08434401 --- /dev/null +++ b/utils/kill.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include + +int usage() +{ + printf("usage: kill [-n] pid ...\n"); + return 0; +} + +int main(int argc, char* argv[]) +{ + if ( argc < 2 ) { return usage(); } + + int first = 1; + int signum = SIGTERM; + if ( argv[1][0] == '-' ) + { + signum = atoi(argv[first++]); + if ( argc < 3 ) { return usage(); } + } + + int result = 0; + + for ( int i = first; i < argc; i++ ) + { + pid_t pid = atoi(argv[i]); + if ( kill(pid, signum) ) + { + printf("kill: (%u): %s\n", pid, strerror(errno)); + result |= 1; + } + } + + return result; +}