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;
+}