Re: signal stack problem

Richard Henderson (rth@dot.cygnus.com)
Wed, 8 Apr 1998 20:33:08 -0700


--9RHnE3ZwKMSgU+yN
Content-Type: text/plain; charset=us-ascii

On Tue, Mar 31, 1998 at 12:12:31PM -0600, Peter Hatch wrote:
> I'm porting a commercial unix app to linux (which version will, of course, be
> available free :-), and the app uses signal stacks so that it can efficently
> manage its own stack space (which makes it quite fast). The problem,
> obviously, is that signal stacks aren't implimented in the linux kernel
> (yet?). Our release is targeted mostly to 2.0.x linux users.

You mean sigaltstack(2)? I have a patch for that for 2.1 that I've
been meaning to get merged in.

r~

--9RHnE3ZwKMSgU+yN
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=d-sigstk

diff -rup /nfs/dot/bang/rth/linux/2.1.86/arch/alpha/kernel/entry.S 2.1.86/arch/alpha/kernel/entry.S
--- /nfs/dot/bang/rth/linux/2.1.86/arch/alpha/kernel/entry.S Wed Feb 11 03:10:34 1998
+++ 2.1.86/arch/alpha/kernel/entry.S Wed Feb 11 03:15:53 1998
@@ -854,7 +854,7 @@ sys_call_table:
.quad alpha_ni_syscall
.quad alpha_ni_syscall /* 110 */
.quad sys_sigsuspend
- .quad sys_ni_syscall
+ .quad osf_sigstack
.quad sys_recvmsg
.quad sys_sendmsg
.quad alpha_ni_syscall /* 115 */
@@ -977,7 +977,7 @@ sys_call_table:
.quad alpha_ni_syscall
.quad sys_getpgid
.quad sys_getsid
- .quad alpha_ni_syscall /* 235 */
+ .quad sys_sigaltstack /* 235 */
.quad alpha_ni_syscall
.quad alpha_ni_syscall
.quad alpha_ni_syscall
diff -rup /nfs/dot/bang/rth/linux/2.1.86/arch/alpha/kernel/osf_sys.c 2.1.86/arch/alpha/kernel/osf_sys.c
--- /nfs/dot/bang/rth/linux/2.1.86/arch/alpha/kernel/osf_sys.c Wed Feb 11 03:10:31 1998
+++ 2.1.86/arch/alpha/kernel/osf_sys.c Wed Feb 11 03:15:53 1998
@@ -742,6 +742,43 @@ asmlinkage long osf_proplist_syscall(enu
return error;
}

+asmlinkage int osf_sigstack(struct sigstack *uss, struct sigstack *uoss)
+{
+ stack_t st, ost;
+ void *usp = (void *) rdusp();
+ int ret;
+
+ if (uss) {
+ struct sigstack s;
+ if (copy_from_user(&s, uss, sizeof(s)))
+ return -EFAULT;
+
+ st.ss_flags = SS_DISABLE;
+ if (s.ss_sp) {
+ st.ss_flags = 0;
+ st.ss_sp = s.ss_sp - MINSIGSTKSZ;
+ st.ss_size = MINSIGSTKSZ;
+ }
+ if (s.ss_onstack)
+ st.ss_flags |= SS_ONSTACK;
+ }
+
+ /* Not exactly right, since sigaltstack won't let you set
+ SS_ONSTACK, but close enough. */
+ ret = do_sigaltstack(uss ? &st : NULL, uoss ? &ost : NULL, usp);
+
+ if (uoss) {
+ struct sigstack s;
+ s.ss_sp = ost.ss_sp + ost.ss_size;
+ s.ss_onstack = (ost.ss_flags & SS_ONSTACK);
+
+ if (copy_to_user(uoss, &s, sizeof(s)))
+ return -EFAULT;
+ }
+
+ return ret;
+}
+
/*
* The Linux kernel isn't good at returning values that look
* like negative longs (they are mistaken as error values).
diff -rup /nfs/dot/bang/rth/linux/2.1.86/arch/alpha/kernel/signal.c 2.1.86/arch/alpha/kernel/signal.c
--- /nfs/dot/bang/rth/linux/2.1.86/arch/alpha/kernel/signal.c Wed Feb 11 03:10:31 1998
+++ 2.1.86/arch/alpha/kernel/signal.c Wed Feb 11 03:15:53 1998
@@ -203,6 +203,24 @@ do_rt_sigsuspend(sigset_t *uset, size_t
}
}

+asmlinkage int
+sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+ stack_t ss, oss;
+ void *usp = (void *) rdusp();
+ int ret;
+
+ if (uss && copy_from_user(&ss, uss, sizeof(ss)))
+ return -EFAULT;
+
+ ret = do_sigaltstack(uss ? &ss : NULL, uoss ? &oss : NULL, usp);
+
+ if (uoss && copy_to_user(uoss, &oss, sizeof(oss)))
+ return -EFAULT;
+
+ return ret;
+}
+
/*
* Do a signal return; undo the signal stack.
*/
@@ -225,7 +243,6 @@ struct rt_sigframe
#define INSN_LDI_R0 0x201f0000
#define INSN_CALLSYS 0x00000083

-
static void
restore_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
struct switch_stack *sw)
@@ -300,6 +317,14 @@ do_sigreturn(struct sigframe *frame, str

restore_sigcontext(&frame->sc, regs, sw);

+ if (current->sigaltstack.ss_flags & SS_ONSTACK) {
+ void *sp = (void *) rdusp();
+ if (sp < current->sigaltstack.ss_sp
+ || sp >= (current->sigaltstack.ss_sp
+ + current->sigaltstack.ss_size))
+ current->sigaltstack.ss_flags &= ~SS_ONSTACK;
+ }
+
/* Send SIGTRAP if we're single-stepping: */
if (ptrace_cancel_bpt (current))
send_sig(SIGTRAP, current, 1);
@@ -316,6 +341,7 @@ do_rt_sigreturn(struct rt_sigframe *fram
{
unsigned long ps;
sigset_t set;
+ stack_t st;

/* Verify that it's a good sigcontext before using it */
if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
@@ -333,6 +359,14 @@ do_rt_sigreturn(struct rt_sigframe *fram

restore_sigcontext(&frame->uc.uc_mcontext, regs, sw);

+ if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+ goto give_sigsegv;
+ if (st.ss_flags != current->sigaltstack.ss_flags
+ || st.ss_sp != current->sigaltstack.ss_sp
+ || st.ss_size != current->sigaltstack.ss_size) {
+ do_sigaltstack(&st, NULL, (void *)rdusp());
+ }
+
/* Send SIGTRAP if we're single-stepping: */
if (ptrace_cancel_bpt (current))
send_sig(SIGTRAP, current, 1);
@@ -354,7 +388,7 @@ setup_sigcontext(struct sigcontext *sc,
{
long i;

- __put_user(0, &sc->sc_onstack);
+ __put_user(current->sigaltstack.ss_flags & SS_ONSTACK, &sc->sc_onstack);
__put_user(mask, &sc->sc_mask);
__put_user(regs->pc, &sc->sc_pc);
__put_user(8, &sc->sc_ps);
@@ -406,13 +440,20 @@ static void
setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
struct pt_regs *regs, struct switch_stack * sw)
{
- unsigned long oldsp;
+ unsigned long oldsp, newsp;
struct sigframe *frame;

oldsp = rdusp();
- frame = (struct sigframe *)((oldsp - sizeof(*frame)) & -32);

- /* XXX: Check here if we would need to switch stacks.. */
+ newsp = oldsp;
+ if ((ka->sa.sa_flags & SA_ONSTACK)
+ && !current->sigaltstack.ss_flags) {
+ current->sigaltstack.ss_flags |= SS_ONSTACK;
+ newsp = ((unsigned long) current->sigaltstack.ss_sp
+ + current->sigaltstack.ss_size);
+ }
+ frame = (struct sigframe *)((newsp - sizeof(*frame)) & -32);
+
if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;

@@ -440,7 +481,7 @@ setup_frame(int sig, struct k_sigaction
regs->r17 = 0; /* a1: exception code */
regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */
wrusp((unsigned long) frame);
-
+
#if DEBUG_SIG
printk("SIG deliver (%s:%d): sp=%p pc=%p ra=%p\n",
current->comm, current->pid, frame, regs->pc, regs->r26);
@@ -457,25 +498,36 @@ static void
setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs, struct switch_stack * sw)
{
- unsigned long oldsp;
+ unsigned long oldsp, newsp, onstack = 0;
struct rt_sigframe *frame;

oldsp = rdusp();
- frame = (struct rt_sigframe *)((oldsp - sizeof(*frame)) & -32);

- /* XXX: Check here if we would need to switch stacks.. */
+ newsp = oldsp;
+ if ((ka->sa.sa_flags & SA_ONSTACK)
+ && !current->sigaltstack.ss_flags) {
+ newsp = ((unsigned long) current->sigaltstack.ss_sp
+ + current->sigaltstack.ss_size);
+ onstack = 1;
+ }
+ frame = (struct rt_sigframe *)((newsp - sizeof(*frame)) & -32);
+
if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
goto give_sigsegv;

__copy_to_user(&frame->info, info, sizeof(siginfo_t));

- /* Zero all bits of the ucontext besides the sigcontext. */
- __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
-
- /* Copy in the bits we actually use. */
+ /* Create the ucontext. */
+ __put_user(0, &frame->uc.uc_flags);
+ __put_user(0, &frame->uc.uc_link);
__put_user(set->sig[0], &frame->uc.uc_osf_sigmask);
+ __copy_to_user(&frame->uc.uc_stack, &current->sigaltstack,
+ sizeof(stack_t));
setup_sigcontext(&frame->uc.uc_mcontext, regs, sw, set->sig[0], oldsp);
__copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+ if (onstack)
+ current->sigaltstack.ss_flags |= SS_ONSTACK;

/* Set up to return from userspace. If provided, use a stub
already in userspace. */
diff -rup /nfs/dot/bang/rth/linux/2.1.86/arch/i386/kernel/entry.S 2.1.86/arch/i386/kernel/entry.S
--- /nfs/dot/bang/rth/linux/2.1.86/arch/i386/kernel/entry.S Wed Feb 11 03:10:34 1998
+++ 2.1.86/arch/i386/kernel/entry.S Wed Feb 11 03:33:40 1998
@@ -533,7 +533,8 @@ ENTRY(sys_call_table)
.long SYMBOL_NAME(sys_pread) /* 180 */
.long SYMBOL_NAME(sys_pwrite)
.long SYMBOL_NAME(sys_chown)
+ .long SYMBOL_NAME(sys_sigaltstack)

- .rept NR_syscalls-182
+ .rept NR_syscalls-183
.long SYMBOL_NAME(sys_ni_syscall)
.endr
diff -rup /nfs/dot/bang/rth/linux/2.1.86/arch/i386/kernel/signal.c 2.1.86/arch/i386/kernel/signal.c
--- /nfs/dot/bang/rth/linux/2.1.86/arch/i386/kernel/signal.c Wed Feb 11 03:10:34 1998
+++ 2.1.86/arch/i386/kernel/signal.c Wed Feb 11 03:23:48 1998
@@ -116,6 +116,25 @@ sys_sigaction(int sig, const struct old_
return ret;
}

+asmlinkage int
+sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+{
+ struct pt_regs *regs = (struct pt_regs *) &uss;
+ stack_t ss, oss;
+ int ret;
+
+ if (uss && copy_from_user(&ss, uss, sizeof(ss)))
+ return -EFAULT;
+
+ ret = do_sigaltstack(uss ? &ss : NULL, uoss ? &oss : NULL,
+ (void *) regs->esp);
+
+ if (uoss && copy_to_user(uoss, &oss, sizeof(oss)))
+ return -EFAULT;
+
+ return ret;
+}
+

/*
* Do a signal return; undo the signal stack.
@@ -241,6 +260,7 @@ asmlinkage int sys_sigreturn(unsigned lo
struct pt_regs *regs = (struct pt_regs *) &__unused;
struct sigframe *frame = (struct sigframe *)(regs->esp - 8);
sigset_t set;
+ int ret;

if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
@@ -256,7 +276,17 @@ asmlinkage int sys_sigreturn(unsigned lo
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);

- return restore_sigcontext(regs, &frame->sc);
+ ret = restore_sigcontext(regs, &frame->sc);
+
+ if (current->sigaltstack.ss_flags & SS_ONSTACK) {
+ void *sp = (void *) regs->esp;
+ if (sp < current->sigaltstack.ss_sp
+ || sp >= (current->sigaltstack.ss_sp
+ + current->sigaltstack.ss_size))
+ current->sigaltstack.ss_flags &= ~SS_ONSTACK;
+ }
+
+ return ret;

badframe:
lock_kernel();
@@ -268,6 +298,8 @@ asmlinkage int sys_rt_sigreturn(unsigned
struct pt_regs *regs = (struct pt_regs *) &__unused;
struct rt_sigframe *frame = (struct rt_sigframe *)(regs->esp - 4);
sigset_t set;
+ stack_t st;
+ int ret;

if (verify_area(VERIFY_READ, frame, sizeof(*frame)))
goto badframe;
@@ -280,7 +312,17 @@ asmlinkage int sys_rt_sigreturn(unsigned
recalc_sigpending(current);
spin_unlock_irq(&current->sigmask_lock);

- return restore_sigcontext(regs, &frame->uc.uc_mcontext);
+ ret = restore_sigcontext(regs, &frame->uc.uc_mcontext);
+
+ if (__copy_from_user(&st, &frame->uc.uc_stack, sizeof(st)))
+ goto badframe;
+ if (st.ss_flags != current->sigaltstack.ss_flags
+ || st.ss_sp != current->sigaltstack.ss_sp
+ || st.ss_size != current->sigaltstack.ss_size) {
+ do_sigaltstack(&st, NULL, (void *) regs->esp);
+ }
+
+ return ret;

badframe:
lock_kernel();
@@ -370,18 +412,28 @@ setup_sigcontext(struct sigcontext *sc,
/*
* Determine which stack to use..
*/
-static inline unsigned long sigstack_esp(struct k_sigaction *ka, struct pt_regs * regs)
+static inline unsigned long
+sigstack_esp(struct k_sigaction *ka, struct pt_regs * regs)
{
unsigned long esp;

/* Default to using normal stack */
esp = regs->esp;

+ /* This is the X/Open sanctioned signal stack switching. */
+ if ((ka->sa.sa_flags & SA_ONSTACK) != 0 &&
+ current->sigaltstack.ss_flags == 0) {
+ current->sigaltstack.ss_flags |= SS_ONSTACK;
+ esp = ((unsigned long) current->sigaltstack.ss_sp
+ + current->sigaltstack.ss_size);
+ }
+
/* This is the legacy signal stack switching. */
- if ((regs->xss & 0xffff) != __USER_DS &&
- !(ka->sa.sa_flags & SA_RESTORER) &&
- ka->sa.sa_restorer)
+ else if ((regs->xss & 0xffff) != __USER_DS &&
+ !(ka->sa.sa_flags & SA_RESTORER) &&
+ ka->sa.sa_restorer) {
esp = (unsigned long) ka->sa.sa_restorer;
+ }

return esp;
}
@@ -391,7 +443,7 @@ static void setup_frame(int sig, struct
{
struct sigframe *frame;

- frame = (struct sigframe *)((sigstack_esp(ka, regs) - sizeof(*frame)) & -8);
+ frame = (struct sigframe *)((sigstack_esp(ka, regs) - sizeof(*frame)) & -16);

if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto segv_and_exit;
@@ -452,8 +504,9 @@ static void setup_rt_frame(int sig, stru
sigset_t *set, struct pt_regs * regs)
{
struct rt_sigframe *frame;
+ int ss_flags = current->sigaltstack.ss_flags;

- frame = (struct rt_sigframe *)((sigstack_esp(ka, regs) - sizeof(*frame)) & -8);
+ frame = (struct rt_sigframe *)((sigstack_esp(ka, regs) - sizeof(*frame)) & -16);

if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
goto segv_and_exit;
@@ -468,9 +521,12 @@ static void setup_rt_frame(int sig, stru
__put_user(&frame->uc, &frame->puc);
__copy_to_user(&frame->info, info, sizeof(*info));

- /* Clear all the bits of the ucontext we don't use. */
- __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
-
+ /* Create the ucontext. */
+ __put_user(0, &frame->uc.uc_flags);
+ __put_user(0, &frame->uc.uc_link);
+ __put_user(current->sigaltstack.ss_sp, &frame->uc.uc_stack.ss_sp);
+ __put_user(ss_flags, &frame->uc.uc_stack.ss_flags);
+ __put_user(current->sigaltstack.ss_size, &frame->uc.uc_stack.ss_size);
setup_sigcontext(&frame->uc.uc_mcontext, &frame->fpstate,
regs, set->sig[0]);
__copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
diff -rup /nfs/dot/bang/rth/linux/2.1.86/include/asm-alpha/signal.h 2.1.86/include/asm-alpha/signal.h
--- /nfs/dot/bang/rth/linux/2.1.86/include/asm-alpha/signal.h Wed Feb 11 03:10:36 1998
+++ 2.1.86/include/asm-alpha/signal.h Wed Feb 11 03:15:53 1998
@@ -76,7 +76,7 @@ typedef unsigned long sigset_t;
/*
* SA_FLAGS values:
*
- * SA_ONSTACK is not currently supported, but will allow sigaltstack(2).
+ * SA_ONSTACK indicates that a registered stack_t will be used.
* SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
* SA_RESTART flag to get restarting signals (which were the default long ago)
* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
@@ -100,6 +100,16 @@ typedef unsigned long sigset_t;
#define SA_NOMASK SA_NODEFER
#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */

+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK 1
+#define SS_DISABLE 2
+
+#define MINSIGSTKSZ 4096
+#define SIGSTKSZ 16384
+
+
#ifdef __KERNEL__
/*
* These values of sa_flags are used only by the kernel as part of the
@@ -163,6 +173,15 @@ typedef struct sigaltstack {
int ss_flags;
size_t ss_size;
} stack_t;
+
+/* sigstack(2) is deprecated, and will be withdrawn in a future version
+ of the X/Open CAE Specification. Use sigaltstack instead. It is only
+ implemented here for OSF/1 compatability. */
+
+struct sigstack {
+ void *ss_sp;
+ int ss_onstack;
+};

#ifdef __KERNEL__
#include <asm/sigcontext.h>
diff -rup /nfs/dot/bang/rth/linux/2.1.86/include/asm-alpha/unistd.h 2.1.86/include/asm-alpha/unistd.h
--- /nfs/dot/bang/rth/linux/2.1.86/include/asm-alpha/unistd.h Wed Feb 11 03:10:36 1998
+++ 2.1.86/include/asm-alpha/unistd.h Wed Feb 11 03:15:53 1998
@@ -113,7 +113,7 @@
#define __NR_osf_old_sigblock 109 /* not implemented */
#define __NR_osf_old_sigsetmask 110 /* not implemented */
#define __NR_sigsuspend 111
-#define __NR_osf_sigstack 112 /* not implemented */
+#define __NR_osf_sigstack 112
#define __NR_recvmsg 113
#define __NR_sendmsg 114
#define __NR_osf_old_vtrace 115 /* not implemented */
@@ -205,7 +205,7 @@

#define __NR_getpgid 233
#define __NR_getsid 234
-#define __NR_osf_sigaltstack 235 /* not implemented */
+#define __NR_sigaltstack 235
#define __NR_osf_waitid 236 /* not implemented */
#define __NR_osf_priocntlset 237 /* not implemented */
#define __NR_osf_sigsendset 238 /* not implemented */
diff -rup /nfs/dot/bang/rth/linux/2.1.86/include/asm-i386/signal.h 2.1.86/include/asm-i386/signal.h
--- /nfs/dot/bang/rth/linux/2.1.86/include/asm-i386/signal.h Wed Feb 11 03:10:36 1998
+++ 2.1.86/include/asm-i386/signal.h Wed Feb 11 03:15:53 1998
@@ -72,7 +72,7 @@ typedef unsigned long sigset_t;
/*
* SA_FLAGS values:
*
- * SA_ONSTACK is not currently supported, but will allow sigaltstack(2).
+ * SA_ONSTACK indicates that a registered stack_t will be used.
* SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
* SA_RESTART flag to get restarting signals (which were the default long ago)
* SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
@@ -96,6 +96,15 @@ typedef unsigned long sigset_t;
#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */

#define SA_RESTORER 0x04000000
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK 1
+#define SS_DISABLE 2
+
+#define MINSIGSTKSZ 2048
+#define SIGSTKSZ 8192

#ifdef __KERNEL__

diff -rup /nfs/dot/bang/rth/linux/2.1.86/include/asm-i386/unistd.h 2.1.86/include/asm-i386/unistd.h
--- /nfs/dot/bang/rth/linux/2.1.86/include/asm-i386/unistd.h Wed Feb 11 03:10:36 1998
+++ 2.1.86/include/asm-i386/unistd.h Wed Feb 11 03:32:54 1998
@@ -188,6 +188,7 @@
#define __NR_pread 180
#define __NR_pwrite 181
#define __NR_chown 182
+#define __NR_sigaltstack 183

/* user-visible error numbers are in the range -1 - -122: see <asm-i386/errno.h> */

diff -rup /nfs/dot/bang/rth/linux/2.1.86/include/linux/sched.h 2.1.86/include/linux/sched.h
--- /nfs/dot/bang/rth/linux/2.1.86/include/linux/sched.h Wed Feb 11 03:10:37 1998
+++ 2.1.86/include/linux/sched.h Wed Feb 11 03:15:59 1998
@@ -266,6 +266,7 @@ struct task_struct {
struct signal_struct *sig;
sigset_t signal, blocked;
struct signal_queue *sigqueue, **sigqueue_tail;
+ stack_t sigaltstack;
/* SMP state */
int has_cpu;
int processor;
@@ -346,6 +347,7 @@ struct task_struct {
/* files */ &init_files, \
/* mm */ &init_mm, \
/* signals */ &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, \
+ { ss_flags: SS_DISABLE }, \
/* SMP */ 0,0,0,0, \
/* locks */ INIT_LOCKS \
}
@@ -475,6 +477,7 @@ extern int kill_sl(pid_t, int, int);
extern int kill_proc(pid_t, int, int);
extern int do_sigaction(int sig, const struct k_sigaction *act,
struct k_sigaction *oact);
+extern int do_sigaltstack(stack_t *ss, stack_t *oss, void *sp);

extern inline int signal_pending(struct task_struct *p)
{
diff -rup /nfs/dot/bang/rth/linux/2.1.86/kernel/signal.c 2.1.86/kernel/signal.c
--- /nfs/dot/bang/rth/linux/2.1.86/kernel/signal.c Wed Feb 11 03:10:32 1998
+++ 2.1.86/kernel/signal.c Wed Feb 11 03:15:53 1998
@@ -830,6 +830,53 @@ do_sigaction(int sig, const struct k_sig
return 0;
}

+int
+do_sigaltstack (stack_t *ss, stack_t *oss, void *sp)
+{
+ int error;
+
+ if (ss) {
+ if (current->sigaltstack.ss_flags & SS_ONSTACK) {
+ /* The task may have used longjmp to exit the
+ signal handler. If the stack pointer is no
+ longer within the memory range, consider us
+ off-stack. */
+ error = -EPERM;
+ if (sp >= current->sigaltstack.ss_sp
+ && sp < (current->sigaltstack.ss_sp
+ + current->sigaltstack.ss_size))
+ goto out;
+ current->sigaltstack.ss_flags &= ~SS_ONSTACK;
+ }
+
+ error = -EINVAL;
+ if (ss->ss_flags & ~SS_DISABLE)
+ goto out;
+
+ if (ss->ss_flags & SS_DISABLE) {
+ ss->ss_size = 0;
+ ss->ss_sp = NULL;
+ } else {
+ error = -ENOMEM;
+ if (ss->ss_size < MINSIGSTKSZ)
+ goto out;
+ }
+
+ if (oss) {
+ *oss = current->sigaltstack;
+ }
+
+ current->sigaltstack = *ss;
+ }
+ else if (oss) {
+ *oss = current->sigaltstack;
+ }
+
+ error = 0;
+out:
+ return error;
+}
+
#if !defined(__alpha__)
/* Alpha has its own versions with special arguments. */

--9RHnE3ZwKMSgU+yN--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu