RFC: 'more signals' patch, 2.1.33

Ingo Molnar (mingo@pc5829.hil.siemens.at)
Tue, 15 Apr 1997 02:26:44 +0200 (MET DST)


Hi kernel hackers,

the attached patch adds more signals to Linux. I'm kindof stuck how to do
it right, thats why i dump it here, suggestions would be more than welcome
at this stage ...

current concepts:

- make action[] is a single indirection sparse array, NULL means a { 0,
0, 0, 0 } sigaction element. Allocation via SLAB cache, thus no latency
problems. [lmbench agrees with me ;)]

- NR_KERNEL_SIGNALS, most assumptions about the number of signals
removed. due to the SLAB solution, memory requirements for more signals
are not nearly that drastical as before. (no more static arrays)

now where the thing becomes ugly:

- big assumption: signal #32 is abused as an 'extended' bit. Thus no need
to push the new signal code down to the assembly level and deep into
kernel drivers. 'extended signals' can only be sent between processes,
the first 31 signals serve as 'kernel-internal fast signals'

I'm not sure what POSIX says about this, maybe it's impossible to do it
this way. And if you take a look at arch/i386/kernel/signal.c, it's quite
ugly to separate this 'extended bit' from normal signals again, which
raises the question wether it's worth doing ... the main reason was that
this way i didnt have to dig down into entry.S ;)

The 'dualness' of signal handling seems to be the correct thing, as we do
not need the POSIX specialities like SIGCHLD SIGSTOP and all the other
special semantics.

As i've made the 'extended bitmap' a 32 bits fields as well, the thing is
limited to 64 signals, but thats not a conceptual limitation.

- A bigger problem seems to be that sa->sa_mask has to be a bitfield too,
which in turn makes it a more natural solution to split extended signals
and 'normal' signals totally? I didnt do it this way because such dual
APIs are a rather microsoftish approach, but maybe it's still the
cleanest one ;)

plus we most probably need the 'old' sigaction structure anyways, for
iBCS2 compliance? [and generally we need the asm/signal.h structure
strictly on other platforms too, for ABI compliance]

The patch works, there is one signal wierdness i couldnt sort out so far
(do a Ctrl-C on a bash prompt ...), but there are no kernel crashes. But
it's experimental code anyways.

Comments more than welcome.

diff -ru linux-2.1.33_vanilla/Makefile linux/Makefile
--- linux-2.1.33_vanilla/Makefile Thu Apr 10 08:28:33 1997
+++ linux/Makefile Mon Apr 14 21:29:40 1997
@@ -11,10 +11,10 @@
#
# NOTE! SMP is experimental. See the file Documentation/SMP.txt
#
-SMP = 1
+# SMP = 1
#
# SMP profiling options
-SMP_PROF = 1
+# SMP_PROF = 1

.EXPORT_ALL_VARIABLES:

diff -ru linux-2.1.33_vanilla/arch/i386/kernel/signal.c linux/arch/i386/kernel/signal.c
--- linux-2.1.33_vanilla/arch/i386/kernel/signal.c Sun Jan 26 11:07:04 1997
+++ linux/arch/i386/kernel/signal.c Tue Apr 15 03:26:52 1997
@@ -16,6 +16,7 @@
#include <linux/wait.h>
#include <linux/ptrace.h>
#include <linux/unistd.h>
+#include <linux/malloc.h>

#include <asm/uaccess.h>

@@ -189,8 +190,10 @@
{
unsigned long * frame;

+#warning DEBUGGING PRINTK
+ printk("<frame()>");
frame = (unsigned long *) regs->esp;
- if ((regs->xss & 0xffff) != USER_DS && sa->sa_restorer)
+ if (sa && (regs->xss & 0xffff) != USER_DS && sa->sa_restorer)
frame = (unsigned long *) sa->sa_restorer;
frame -= 64;
if (!access_ok(VERIFY_WRITE,frame,64*4))
@@ -248,7 +251,10 @@

/* Set up registers for signal handler */
regs->esp = (unsigned long) frame;
- regs->eip = (unsigned long) sa->sa_handler;
+ if (sa)
+ regs->eip = (unsigned long) sa->sa_handler;
+ else
+ regs->eip = 0;
{
unsigned long seg = USER_DS;
__asm__("mov %w0,%%fs ; mov %w0,%%gs":"=r" (seg) :"0" (seg));
@@ -264,9 +270,11 @@
/*
* OK, we're invoking a handler
*/
-static void handle_signal(unsigned long signr, struct sigaction *sa,
+static void handle_signal(unsigned long signr, struct sigaction * * sa,
unsigned long oldmask, struct pt_regs * regs)
{
+#warning DEBUGGING PRINTK
+ printk("<handle()>");
/* are we from a system call? */
if (regs->orig_eax >= 0) {
/* If so, check system call restarting.. */
@@ -276,7 +284,7 @@
break;

case -ERESTARTSYS:
- if (!(sa->sa_flags & SA_RESTART)) {
+ if ((*sa) && !((*sa)->sa_flags & SA_RESTART)) {
regs->eax = -EINTR;
break;
}
@@ -288,12 +296,23 @@
}

/* set up the stack frame */
- setup_frame(sa, regs, signr, oldmask);
+ setup_frame(*sa, regs, signr, oldmask);

- if (sa->sa_flags & SA_ONESHOT)
- sa->sa_handler = NULL;
- if (!(sa->sa_flags & SA_NOMASK))
- current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE;
+ if (*sa) {
+ if (!((*sa)->sa_flags & SA_NOMASK))
+ current->blocked |= ((*sa)->sa_mask | _S(signr)) &
+ _BLOCKABLE;
+ } else
+ current->blocked |= _S(signr) & _BLOCKABLE;
+
+ if ((*sa) && ((*sa)->sa_flags & SA_ONESHOT))
+ (*sa)->sa_handler = NULL;
+/* FIXME:
+ {
+ kfree(*sa);
+ *sa = &init_DFL_SIGHANDLER;
+ }
+ */
}

/*
@@ -308,11 +327,13 @@
asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
{
unsigned long mask;
- unsigned long signr;
- struct sigaction * sa;
+ unsigned long signr, sigoffset=0;
+ struct sigaction * * sa;
int res;

lock_kernel();
+#warning DEBUGGING PRINTK
+ printk("<do_sig()>");
mask = ~current->blocked;
while ((signr = current->signal & mask)) {
/*
@@ -325,6 +346,38 @@
"btrl %1,%0"
:"=m" (t->signal),"=r" (signr)
:"0" (t->signal), "1" (signr));
+
+ /*
+ * Special case for extended signals:
+ */
+ if (signr == 31) {
+ mask = ~current->extended_blocked;
+ while ((signr = current->extended_signal & mask)) {
+ struct task_struct *t=current;
+ __asm__("bsf %3,%1\n\t"
+ "btrl %1,%0"
+ :"=m" (t->extended_signal),"=r" (signr)
+ :"0" (t->extended_signal), "1" (signr));
+ /*
+ * No POSIX special cases:
+ */
+
+ if ((*sa) && ((*sa)->sa_handler == SIG_IGN))
+ continue;
+ if ((!*sa) || ((*sa)->sa_handler == SIG_DFL)) {
+ if (current->pid == 1)
+ continue;
+ current->signal |= _S(signr & 0x7f);
+ current->flags |= PF_SIGNALED;
+ do_exit(signr+32);
+ }
+ handle_signal(signr+32, sa, oldmask, regs);
+ res = 1;
+ goto out;
+ }
+ break;
+ }
+
sa = current->sig->action + signr;
signr++;
if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
@@ -343,7 +396,7 @@
}
sa = current->sig->action + signr - 1;
}
- if (sa->sa_handler == SIG_IGN) {
+ if ((*sa) && ((*sa)->sa_handler == SIG_IGN)) {
if (signr != SIGCHLD)
continue;
/* check for SIGCHLD: it's special */
@@ -351,7 +404,7 @@
/* nothing */;
continue;
}
- if (sa->sa_handler == SIG_DFL) {
+ if ((!*sa) || ((*sa)->sa_handler == SIG_DFL)) {
if (current->pid == 1)
continue;
switch (signr) {
@@ -366,8 +419,8 @@
continue;
current->state = TASK_STOPPED;
current->exit_code = signr;
- if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
- SA_NOCLDSTOP))
+ if ((!*sa) || (!(current->p_pptr->sig->action[SIGCHLD-1]->sa_flags &
+ SA_NOCLDSTOP)))
notify_parent(current);
schedule();
continue;
diff -ru linux-2.1.33_vanilla/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- linux-2.1.33_vanilla/arch/i386/kernel/traps.c Tue Apr 8 03:52:09 1997
+++ linux/arch/i386/kernel/traps.c Tue Apr 15 00:39:06 1997
@@ -187,6 +187,7 @@
console_verbose();
printk("%s: %04lx\n", str, err & 0xffff);
show_registers(regs);
+ for(;;) cli();
do_exit(SIGSEGV);
}

diff -ru linux-2.1.33_vanilla/drivers/char/n_tty.c linux/drivers/char/n_tty.c
--- linux-2.1.33_vanilla/drivers/char/n_tty.c Sat Mar 1 00:00:53 1997
+++ linux/drivers/char/n_tty.c Tue Apr 15 01:36:59 1997
@@ -623,7 +623,8 @@
int is_ignored(int sig)
{
return ((current->blocked & (1<<(sig-1))) ||
- (current->sig->action[sig-1].sa_handler == SIG_IGN));
+ ((current->sig->action[sig-1]) &&
+ (current->sig->action[sig-1]->sa_handler == SIG_IGN)));
}

static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
diff -ru linux-2.1.33_vanilla/fs/exec.c linux/fs/exec.c
--- linux-2.1.33_vanilla/fs/exec.c Thu Apr 3 19:56:23 1997
+++ linux/fs/exec.c Tue Apr 15 02:44:53 1997
@@ -412,13 +412,15 @@
static inline void flush_old_signals(struct signal_struct *sig)
{
int i;
- struct sigaction * sa = sig->action;
+ struct sigaction * * sa = sig->action;

- for (i=32 ; i != 0 ; i--) {
- sa->sa_mask = 0;
- sa->sa_flags = 0;
- if (sa->sa_handler != SIG_IGN)
- sa->sa_handler = NULL;
+ for (i=NR_KERNEL_SIGNALS ; i != 0 ; i--) {
+ if (*sa) {
+ (*sa)->sa_mask = 0;
+ (*sa)->sa_flags = 0;
+ if ((*sa)->sa_handler != SIG_IGN)
+ (*sa)->sa_handler = SIG_DFL;
+ }
sa++;
}
}
diff -ru linux-2.1.33_vanilla/fs/proc/array.c linux/fs/proc/array.c
--- linux-2.1.33_vanilla/fs/proc/array.c Fri Mar 21 02:11:52 1997
+++ linux/fs/proc/array..c Tue Apr 15 01:47:07 1997
@@ -630,20 +630,22 @@
"SigBlk:\t%08lx\n",
p->signal, p->blocked);
if (p->sig) {
- struct sigaction * action = p->sig->action;
+ struct sigaction * * action = p->sig->action;
unsigned long sig_ign = 0, sig_caught = 0;
unsigned long bit = 1;
int i;

- for (i = 0; i < 32; i++) {
- switch((unsigned long) action->sa_handler) {
- case 0:
- break;
- case 1:
- sig_ign |= bit;
- break;
- default:
- sig_caught |= bit;
+ for (i = 0; i < NR_KERNEL_SIGNALS; i++) {
+ if (*action) {
+ switch((unsigned long) (*action)->sa_handler) {
+ case 0:
+ break;
+ case 1:
+ sig_ign |= bit;
+ break;
+ default:
+ sig_caught |= bit;
+ }
}
bit <<= 1;
action++;
@@ -701,15 +703,17 @@
wchan = get_wchan(tsk);
if (tsk->sig) {
unsigned long bit = 1;
- for(i=0; i<32; ++i) {
- switch((unsigned long) tsk->sig->action[i].sa_handler) {
- case 0:
- break;
- case 1:
- sigignore |= bit;
- break;
- default:
- sigcatch |= bit;
+ for(i=0; i<NR_KERNEL_SIGNALS; ++i) {
+ if (tsk->sig->action[i]) {
+ switch((unsigned long) tsk->sig->action[i]->sa_handler) {
+ case 0:
+ break;
+ case 1:
+ sigignore |= bit;
+ break;
+ default:
+ sigcatch |= bit;
+ }
}
bit <<= 1;
}
diff -ru linux-2.1.33_vanilla/include/linux/sched.h linux/include/linux/sched.h
--- linux-2.1.33_vanilla/include/linux/sched.h Thu Apr 10 08:31:13 1997
+++ linux/include/linux/sched.h Tue Apr 15 03:11:55 1997
@@ -162,15 +162,20 @@
0, \
&init_mmap, &init_mmap, MUTEX }

+#define NR_KERNEL_SIGNALS 64
+
struct signal_struct {
int count;
- struct sigaction action[32];
+ struct sigaction * action[NR_KERNEL_SIGNALS];
};

+extern struct sigaction init_DFL_SIGHANDLER,
+ init_IGN_SIGHANDLER,
+ init_ERR_SIGHANDLER;

#define INIT_SIGNALS { \
1, \
- { {0,}, } }
+ { &init_DFL_SIGHANDLER, } }

struct task_struct {
/* these are hardcoded - don't touch */
@@ -246,6 +251,9 @@
struct mm_struct *mm;
/* signal handlers */
struct signal_struct *sig;
+/* extended POSIX signals */
+ unsigned long extended_blocked;
+ unsigned long extended_signal;
/* SMP state */
int processor;
int last_processor;
diff -ru linux-2.1.33_vanilla/init/main.c linux/init/main.c
--- linux-2.1.33_vanilla/init/main.c Thu Apr 10 06:30:31 1997
+++ linux/init/main.c Tue Apr 15 02:22:20 1997
@@ -72,6 +72,7 @@
extern long sbus_init(long, long);
extern void sysctl_init(void);

+extern void setup_signals(void);
extern void smp_setup(char *str, int *ints);
extern void no_scroll(char *str, int *ints);
extern void swap_setup(char *str, int *ints);
@@ -893,6 +894,7 @@
#endif
memory_start = kmalloc_init(memory_start,memory_end);
memory_start = kmem_cache_init(memory_start, memory_end);
+
sti();
calibrate_delay();
memory_start = inode_init(memory_start,memory_end);
@@ -911,6 +913,13 @@
#endif
kmem_cache_sizes_init();
vma_init();
+
+ /*
+ * setup_signals() needs the SLAB cache, and init needs valid
+ * signal structures as well ... we hope this isnt too late.
+ */
+ setup_signals();
+
buffer_init();
sock_init();
#if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
diff -ru linux-2.1.33_vanilla/kernel/exit.c linux/kernel/exit.c
--- linux-2.1.33_vanilla/kernel/exit.c Mon Apr 7 20:17:31 1997
+++ linux/kernel/exit.c Tue Apr 15 03:42:43 1997
@@ -20,6 +20,8 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/module.h>
+#include <linux/slab.h>
+

#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -29,13 +31,17 @@
extern void acct_process (long exitcode);
extern void kerneld_exit(void);

+extern kmem_cache_t * sigaction_cachep;
+
int getrusage(struct task_struct *, int, struct rusage *);

static inline void generate(unsigned long sig, struct task_struct * p)
{
unsigned long mask = 1 << (sig-1);
- struct sigaction * sa = sig + p->sig->action - 1;
+ struct sigaction * * sa = sig + p->sig->action - 1;

+#warning DEBUGGING PRINTK
+ printk("<gen(%ld/%p)/",sig,*sa);
/*
* Optimize away the signal, if it's a signal that can
* be handled immediately (ie non-blocked and untraced)
@@ -43,32 +49,80 @@
*/
if (!(mask & p->blocked) && !(p->flags & PF_PTRACED)) {
/* don't bother with ignored signals (but SIGCHLD is special) */
- if (sa->sa_handler == SIG_IGN && sig != SIGCHLD)
+ if ((*sa) && ((*sa)->sa_handler == SIG_IGN) &&
+ (sig != SIGCHLD)) {
+#warning DEBUGGING PRINTK
+ printk("IGN>");
return;
+ }
/* some signals are ignored by default.. (but SIGCONT already did its deed) */
- if ((sa->sa_handler == SIG_DFL) &&
- (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH || sig == SIGURG))
+ if ( ((!*sa) || ((*sa)->sa_handler == SIG_DFL)) &&
+ (sig == SIGCONT || sig == SIGCHLD ||
+ sig == SIGWINCH || sig == SIGURG)) {
+#warning DEBUGGING PRINTK
+ printk("IGN>");
return;
+ }
}
+#warning DEBUGGING PRINTK
+ printk("ACC>");
p->signal |= mask;
if (p->state == TASK_INTERRUPTIBLE && (p->signal & ~p->blocked))
wake_up_process(p);
}

+static inline void extended_generate(unsigned long sig, struct task_struct * p)
+{
+ unsigned long mask = 1 << (sig-33);
+ struct sigaction * * sa = sig + p->sig->action - 1;
+
+#warning DEBUGGING PRINTK
+ printk("<extgen(%ld/%p)/",sig,*sa);
+ /*
+ * Optimize away the signal, if it's a signal that can
+ * be handled immediately (ie non-blocked and untraced)
+ * and that is ignored (either explicitly or by default)
+ *
+ * extended signals do not have to deal with POSIX braindamage
+ */
+ if (!(mask & p->blocked) && !(p->flags & PF_PTRACED)) {
+ /* don't bother with ignored signals (but SIGCHLD is special) */
+ if ((*sa) && ((*sa)->sa_handler == SIG_IGN)) {
+#warning DEBUGGING PRINTK
+ printk("IGN>");
+ return;
+ }
+ if ( ((!*sa) || ((*sa)->sa_handler == SIG_DFL)) ) {
+#warning DEBUGGING PRINTK
+ printk("IGN>");
+ return;
+ }
+ }
+#warning DEBUGGING PRINTK
+ printk("ACC>");
+ p->extended_signal |= mask;
+
+ /*
+ * No wake-up done here.
+ */
+}
+
/*
* Force a signal that the process can't ignore: if necessary
* we unblock the signal and change any SIG_IGN to SIG_DFL.
*/
void force_sig(unsigned long sig, struct task_struct * p)
{
+#warning DEBUGGING PRINTK
+ printk("<forc>");
sig--;
if (p->sig) {
unsigned long mask = 1UL << sig;
- struct sigaction *sa = p->sig->action + sig;
+ struct sigaction * * sa = p->sig->action + sig;
p->signal |= mask;
p->blocked &= ~mask;
- if (sa->sa_handler == SIG_IGN)
- sa->sa_handler = SIG_DFL;
+ if ((*sa) && ((*sa)->sa_handler == SIG_IGN))
+ (*sa)->sa_handler = SIG_DFL;
if (p->state == TASK_INTERRUPTIBLE)
wake_up_process(p);
}
@@ -77,7 +131,7 @@

int send_sig(unsigned long sig,struct task_struct * p,int priv)
{
- if (!p || sig > 32)
+ if (!p || sig > NR_KERNEL_SIGNALS)
return -EINVAL;
if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
(current->euid ^ p->suid) && (current->euid ^ p->uid) &&
@@ -101,6 +155,26 @@
if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU)
p->signal &= ~(1<<(SIGCONT-1));
/* Actually generate the signal */
+
+ /*
+ * Extended signals are 'hidden' into bit 31, plus there is
+ * a bitfield in task_struct. Thus do_signal notices that
+ * there is a job to do, still we dont penaltize normal kernel
+ * code that doesnt need extended signals and is just happy
+ * with the old 32 signals.
+ */
+
+ if (sig>31) {
+ /*
+ * i >hope< this doesnt break POSIX ...
+ */
+ if (sig==32)
+ return -EINVAL;
+
+ extended_generate(sig,p);
+ generate(32,p);
+ return 0;
+ }
generate(sig,p);
return 0;
}
@@ -307,7 +381,7 @@
{
struct task_struct *p;

- if (sig<0 || sig>32)
+ if (sig<0 || sig>NR_KERNEL_SIGNALS)
return -EINVAL;
for_each_task(p) {
if (p && p->pid == pid)
@@ -468,9 +542,19 @@
{
struct signal_struct * sig = tsk->sig;

+ printk("<EXIT()>");
if (sig) {
tsk->sig = NULL;
if (!--sig->count) {
+ int i;
+ struct sigaction * sa;
+
+ for (i=0; i<NR_KERNEL_SIGNALS; i++) {
+ sa = sig->action[i];
+
+ if (sa)
+ kmem_cache_free(sigaction_cachep, sa);
+ }
kfree(sig);
}
}
diff -ru linux-2.1.33_vanilla/kernel/fork.c linux/kernel/fork.c
--- linux-2.1.33_vanilla/kernel/fork.c Thu Apr 10 06:25:44 1997
+++ linux/kernel/fork.c Tue Apr 15 02:55:54 1997
@@ -22,6 +22,7 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/module.h>
+#include <linux/slab.h>

#include <asm/system.h>
#include <asm/pgtable.h>
@@ -33,6 +34,8 @@
unsigned long int total_forks=0; /* Handle normal Linux uptimes. */
int last_pid=0;

+extern kmem_cache_t * sigaction_cachep;
+
static inline int find_empty_process(void)
{
int i;
@@ -202,6 +205,10 @@

static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk)
{
+ int i;
+
+#warning DEBUGGING PRINTK
+ printk("<copy_sighand()>");
if (clone_flags & CLONE_SIGHAND) {
current->sig->count++;
return 0;
@@ -211,6 +218,25 @@
return -1;
tsk->sig->count = 1;
memcpy(tsk->sig->action, current->sig->action, sizeof(tsk->sig->action));
+ for (i=0; i<NR_KERNEL_SIGNALS; i++) {
+ if (current->sig->action[i]) {
+ tsk->sig->action[i] = kmem_cache_alloc(sigaction_cachep, SLAB_KERNEL);
+ /*
+ * If we fail we have to free them:
+ */
+ if (!tsk->sig->action[i]) {
+ for (; i; i--)
+ if (tsk->sig->action[i-1])
+ kmem_cache_free(sigaction_cachep,
+ tsk->sig->action[i-1]);
+ return -1;
+ }
+ memcpy(tsk->sig->action[i],
+ current->sig->action[i],
+ sizeof(struct sigaction));
+ } else
+ tsk->sig->action[i] = NULL;
+ }
return 0;
}

diff -ru linux-2.1.33_vanilla/kernel/sched.c linux/kernel/sched.c
--- linux-2.1.33_vanilla/kernel/sched.c Wed Apr 9 07:11:27 1997
+++ linux/kernel/sched.c Tue Apr 15 02:18:27 1997
@@ -32,6 +32,7 @@
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/slab.h>

#include <asm/system.h>
#include <asm/io.h>
@@ -86,6 +87,14 @@

#define _S(nr) (1<<((nr)-1))

+/*
+ * These are 'placeholder' structures. They should never be modified, only
+ * read.
+ */
+struct sigaction init_DFL_SIGHANDLER = { SIG_DFL, 0, 0, NULL };
+struct sigaction init_IGN_SIGHANDLER = { SIG_IGN, 0, 0, NULL };
+struct sigaction init_ERR_SIGHANDLER = { SIG_ERR, 0, 0, NULL };
+
extern void mem_use(void);

static unsigned long init_kernel_stack[1024] = { STACK_MAGIC, };
@@ -99,6 +108,27 @@
struct task_struct init_task = INIT_TASK;

unsigned long volatile jiffies=0;
+
+/*
+ * SLAB cache for sigaction struct's
+ */
+kmem_cache_t * sigaction_cachep;
+
+void setup_signals(void)
+{
+ int i;
+
+ printk("setup_signals().\n");
+ for (i=0; i<NR_KERNEL_SIGNALS; i++)
+ init_signals.action[i]=NULL;
+
+ sigaction_cachep = kmem_cache_create("sigaction_struct",
+ sizeof(struct sigaction),
+ sizeof(struct sigaction), SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if(!sigaction_cachep)
+ panic("setup_signals: Cannot alloc sigaction cache.");
+}

/*
* Init task must be ok at boot for the ix86 as we will check its signals
diff -ru linux-2.1.33_vanilla/kernel/signal.c linux/kernel/signal.c
--- linux-2.1.33_vanilla/kernel/signal.c Mon Mar 17 02:10:07 1997
+++ linux/kernel/signal.c Tue Apr 15 03:02:51 1997
@@ -14,6 +14,7 @@
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/slab.h>

#include <asm/uaccess.h>

@@ -21,6 +22,8 @@

#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))

+extern kmem_cache_t * sigaction_cachep;
+
#ifndef __alpha__

/*
@@ -117,14 +120,16 @@
*/
inline void check_pending(int signum)
{
- struct sigaction *p;
+ struct sigaction * * p;

+#warning DEBUGGING PRINTK
+ printk("<check_pending()>");
p = signum - 1 + current->sig->action;
- if (p->sa_handler == SIG_IGN) {
+ if ((*p) && ((*p)->sa_handler == SIG_IGN)) {
current->signal &= ~_S(signum);
return;
}
- if (p->sa_handler == SIG_DFL) {
+ if ((!*p) || ((*p)->sa_handler == SIG_DFL)) {
if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH)
return;
current->signal &= ~_S(signum);
@@ -141,6 +146,13 @@
unsigned long err;
struct sigaction tmp;

+#warning DEBUGGING PRINTK
+ printk("<sys_signal()>");
+ /*
+ * FIXME: implement new signal handling here. Now Just Die.
+ */
+ *(char *)0=0;
+
lock_kernel();
err = -EINVAL;
if (signum<1 || signum>32)
@@ -155,8 +167,8 @@
memset(&tmp, 0, sizeof(tmp));
tmp.sa_handler = handler;
tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
- handler = current->sig->action[signum-1].sa_handler;
- current->sig->action[signum-1] = tmp;
+ handler = current->sig->action[signum-1]->sa_handler;
+ *current->sig->action[signum-1] = tmp;
check_pending(signum);
err = (unsigned long) handler;
out:
@@ -165,15 +177,22 @@
}
#endif

+#include <linux/malloc.h>
+
#ifndef __sparc__
+
asmlinkage int sys_sigaction(int signum, const struct sigaction * action,
struct sigaction * oldaction)
{
- struct sigaction new_sa, *p;
+ struct sigaction new_sa, * * p;

- if (signum<1 || signum>32)
+#warning DEBUGGING PRINTK
+ printk("<sys_sigaction()>");
+ if (signum<1 || signum>NR_KERNEL_SIGNALS)
return -EINVAL;
- p = signum - 1 + current->sig->action;
+
+ p = current->sig->action + signum - 1;
+
if (action) {
if (copy_from_user(&new_sa, action, sizeof(struct sigaction)))
return -EFAULT;
@@ -181,11 +200,25 @@
return -EINVAL;
}
if (oldaction) {
- if (copy_to_user(oldaction, p, sizeof(struct sigaction)))
- return -EFAULT;
+ if (*p)
+ if (copy_to_user(oldaction, *p,
+ sizeof(struct sigaction)))
+ return -EFAULT;
+ else
+ if (copy_to_user(oldaction, &init_DFL_SIGHANDLER,
+ sizeof(struct sigaction)))
+ return -EFAULT;
}
if (action) {
- *p = new_sa;
+ if (!*p)
+ *p=kmem_cache_alloc(sigaction_cachep, SLAB_KERNEL);
+ /*
+ * FIXME: is it legal to return ENOMEM in sigaction() ?
+ */
+ if (!*p)
+ return -ENOMEM;
+
+ **p = new_sa;
check_pending(signum);
}
return 0;
diff -ru linux-2.1.33_vanilla/mm/memory.c linux/mm/memory.c
--- linux-2.1.33_vanilla/mm/memory.c Wed Jan 1 15:20:45 1997
+++ linux/mm/memory.c Tue Apr 15 01:45:55 1997
@@ -79,8 +79,7 @@
void oom(struct task_struct * task)
{
printk("\nOut of memory for %s.\n", task->comm);
- task->sig->action[SIGKILL-1].sa_handler = NULL;
- task->blocked &= ~(1<<(SIGKILL-1));
+ force_sig(SIGKILL,task);
send_sig(SIGKILL,task,1);
}

diff -ru linux-2.1.33_vanilla/net/sunrpc/clnt.c linux/net/sunrpc/clnt.c
--- linux-2.1.33_vanilla/net/sunrpc/clnt.c Tue Apr 8 03:43:43 1997
+++ linux/net/sunrpc/clnt.c Tue Apr 15 01:39:14 1997
@@ -189,10 +189,12 @@

/* Turn off various signals */
if (clnt->cl_intr) {
- struct sigaction *action = current->sig->action;
- if (action[SIGINT-1].sa_handler == SIG_DFL)
+ struct sigaction * * action = current->sig->action;
+ if ((!action[SIGINT-1]) ||
+ (action[SIGINT-1]->sa_handler == SIG_DFL))
sigallow |= _S(SIGINT);
- if (action[SIGQUIT-1].sa_handler == SIG_DFL)
+ if ((!action[SIGQUIT-1]) ||
+ (action[SIGQUIT-1]->sa_handler == SIG_DFL))
sigallow |= _S(SIGQUIT);
}
oldmask = current->blocked;