aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2006-09-27 17:27:00 +0900
committerPaul Mundt <lethal@linux-sh.org>2006-09-27 17:27:00 +0900
commit9f23e7e94f7083d9705b595cbd6b30972be6fbbb (patch)
tree5fc6e90a9e361dca2e56bb03327078a2eb88cb4c
parenta2d1a5fae6296c2a3ac1aaa982c95464c46c0585 (diff)
downloadlinux-9f23e7e94f7083d9705b595cbd6b30972be6fbbb.tar.gz
sh: pselect6 and ppoll, along with signal trampoline rework.
This implements support for ppoll() and pselect6().. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
-rw-r--r--arch/sh/kernel/entry.S8
-rw-r--r--arch/sh/kernel/signal.c137
-rw-r--r--arch/sh/kernel/syscalls.S31
-rw-r--r--include/asm-sh/thread_info.h2
-rw-r--r--include/asm-sh/unistd.h66
5 files changed, 121 insertions, 123 deletions
diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S
index fcbf50d4ee1093..fd5fe2349f207d 100644
--- a/arch/sh/kernel/entry.S
+++ b/arch/sh/kernel/entry.S
@@ -371,12 +371,12 @@ work_pending:
! r8: current_thread_info
! t: result of "tst #_TIF_NEED_RESCHED, r0"
bf/s work_resched
- tst #_TIF_SIGPENDING, r0
+ tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
work_notifysig:
bt/s restore_all
mov r15, r4
- mov #0, r5
- mov r12, r6 ! set arg2(save_r0)
+ mov r12, r5 ! set arg1(save_r0)
+ mov r0, r6
mov.l 2f, r1
mova restore_all, r0
jmp @r1
@@ -414,7 +414,7 @@ work_resched:
.align 2
1: .long schedule
-2: .long do_signal
+2: .long do_notify_resume
.align 2
syscall_exit_work:
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index eb6a3b97e46c89..2f1c9545b49f58 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -29,13 +29,10 @@
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
-#define DEBUG_SIG 0
+#undef DEBUG
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset,
- unsigned int save_r0);
-
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -44,51 +41,17 @@ sys_sigsuspend(old_sigset_t mask,
unsigned long r5, unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
- sigset_t saveset;
-
mask &= _BLOCKABLE;
spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
+ current->saved_sigmask = current->blocked;
siginitset(&current->blocked, mask);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- regs.regs[0] = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(&regs, &saveset, regs.regs[0]))
- return -EINTR;
- }
-}
-
-asmlinkage int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
- unsigned long r6, unsigned long r7,
- struct pt_regs regs)
-{
- sigset_t saveset, newset;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
- current->blocked = newset;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- regs.regs[0] = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(&regs, &saveset, regs.regs[0]))
- return -EINTR;
- }
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ set_thread_flag(TIF_RESTORE_SIGMASK);
+ return -ERESTARTNOHAND;
}
asmlinkage int
@@ -349,7 +312,7 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
return (void __user *)((sp - frame_size) & -8ul);
}
-static void setup_frame(int sig, struct k_sigaction *ka,
+static int setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs *regs)
{
struct sigframe __user *frame;
@@ -369,10 +332,9 @@ static void setup_frame(int sig, struct k_sigaction *ka,
err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
- if (_NSIG_WORDS > 1) {
+ if (_NSIG_WORDS > 1)
err |= __copy_to_user(frame->extramask, &set->sig[1],
sizeof(frame->extramask));
- }
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
@@ -403,21 +365,22 @@ static void setup_frame(int sig, struct k_sigaction *ka,
set_fs(USER_DS);
-#if DEBUG_SIG
- printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
- current->comm, current->pid, frame, regs->pc, regs->pr);
-#endif
+ pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+ current->comm, current->pid, frame, regs->pc, regs->pr);
flush_cache_sigtramp(regs->pr);
+
if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
- return;
+
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
}
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
@@ -478,28 +441,31 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
set_fs(USER_DS);
-#if DEBUG_SIG
- printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
- current->comm, current->pid, frame, regs->pc, regs->pr);
-#endif
+ pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+ current->comm, current->pid, frame, regs->pc, regs->pr);
flush_cache_sigtramp(regs->pr);
+
if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
- return;
+
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
}
/*
* OK, we're invoking a handler
*/
-static void
+static int
handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *oldset, struct pt_regs *regs)
{
+ int ret;
+
/* Are we from a system call? */
if (regs->tra >= 0) {
/* If so, check system call restarting.. */
@@ -540,19 +506,23 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO)
- setup_rt_frame(sig, ka, info, oldset, regs);
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
else
- setup_frame(sig, ka, oldset, regs);
+ ret = setup_frame(sig, ka, oldset, regs);
if (ka->sa.sa_flags & SA_ONESHOT)
ka->sa.sa_handler = SIG_DFL;
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ if (ret == 0) {
+ spin_lock_irq(&current->sighand->siglock);
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NODEFER))
+ sigaddset(&current->blocked,sig);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+ }
+
+ return ret;
}
/*
@@ -564,11 +534,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
-int do_signal(struct pt_regs *regs, sigset_t *oldset, unsigned int save_r0)
+static void do_signal(struct pt_regs *regs, unsigned int save_r0)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
+ sigset_t *oldset;
/*
* We want the common case to go fast, which
@@ -577,19 +548,27 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, unsigned int save_r0)
* if so.
*/
if (!user_mode(regs))
- return 1;
+ return;
if (try_to_freeze())
goto no_signal;
- if (!oldset)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+ else
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
/* Whee! Actually deliver the signal. */
- handle_signal(signr, &ka, &info, oldset, regs);
- return 1;
+ if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
+ /* a signal was successfully delivered; the saved
+ * sigmask will have been stored in the signal frame,
+ * and will be restored by sigreturn, so we can simply
+ * clear the TIF_RESTORE_SIGMASK flag */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ }
}
no_signal:
@@ -606,5 +585,19 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset, unsigned int save_r0)
regs->regs[3] = __NR_restart_syscall;
}
}
- return 0;
+
+ /* if there's no signal to deliver, we just put the saved sigmask
+ * back */
+ if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
+ clear_thread_flag(TIF_RESTORE_SIGMASK);
+ sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
+ }
+}
+
+asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
+ __u32 thread_info_flags)
+{
+ /* deal with pending signal delivery */
+ if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+ do_signal(regs, save_r0);
}
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S
index ea23b213c77f6b..768334e950753f 100644
--- a/arch/sh/kernel/syscalls.S
+++ b/arch/sh/kernel/syscalls.S
@@ -319,34 +319,35 @@ ENTRY(sys_call_table)
.long sys_mq_getsetattr
.long sys_kexec_load
.long sys_waitid
- .long sys_add_key /* 285 */
+ .long sys_ni_syscall /* 285 */
+ .long sys_add_key
.long sys_request_key
.long sys_keyctl
.long sys_ioprio_set
- .long sys_ioprio_get
- .long sys_inotify_init /* 290 */
+ .long sys_ioprio_get /* 290 */
+ .long sys_inotify_init
.long sys_inotify_add_watch
.long sys_inotify_rm_watch
.long sys_migrate_pages
- .long sys_openat
- .long sys_mkdirat /* 295 */
+ .long sys_openat /* 295 */
+ .long sys_mkdirat
.long sys_mknodat
.long sys_fchownat
.long sys_futimesat
- .long sys_fstatat64
- .long sys_unlinkat /* 300 */
+ .long sys_fstatat64 /* 300 */
+ .long sys_unlinkat
.long sys_renameat
.long sys_linkat
.long sys_symlinkat
- .long sys_readlinkat
- .long sys_fchmodat /* 305 */
+ .long sys_readlinkat /* 305 */
+ .long sys_fchmodat
.long sys_faccessat
- .long sys_ni_syscall /* Reserved for pselect6 */
- .long sys_ni_syscall /* Reserved for ppoll */
- .long sys_unshare
- .long sys_set_robust_list /* 310 */
+ .long sys_pselect6
+ .long sys_ppoll
+ .long sys_unshare /* 310 */
+ .long sys_set_robust_list
.long sys_get_robust_list
.long sys_splice
.long sys_sync_file_range
- .long sys_tee
- .long sys_vmsplice /* 315 */
+ .long sys_tee /* 315 */
+ .long sys_vmsplice
diff --git a/include/asm-sh/thread_info.h b/include/asm-sh/thread_info.h
index b986a191447234..5eb874b065a691 100644
--- a/include/asm-sh/thread_info.h
+++ b/include/asm-sh/thread_info.h
@@ -94,6 +94,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+#define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */
#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */
#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 18
@@ -102,6 +103,7 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h
index 49c6a6ee0ab21d..080e5729f17dc0 100644
--- a/include/asm-sh/unistd.h
+++ b/include/asm-sh/unistd.h
@@ -292,39 +292,40 @@
#define __NR_mq_getsetattr (__NR_mq_open+5)
#define __NR_kexec_load 283
#define __NR_waitid 284
-#define __NR_add_key 285
-#define __NR_request_key 286
-#define __NR_keyctl 287
-#define __NR_ioprio_set 288
-#define __NR_ioprio_get 289
-#define __NR_inotify_init 290
-#define __NR_inotify_add_watch 291
-#define __NR_inotify_rm_watch 292
-#define __NR_migrate_pages 293
-#define __NR_openat 294
-#define __NR_mkdirat 295
-#define __NR_mknodat 296
-#define __NR_fchownat 297
-#define __NR_futimesat 298
-#define __NR_fstatat64 299
-#define __NR_unlinkat 300
-#define __NR_renameat 301
-#define __NR_linkat 302
-#define __NR_symlinkat 303
-#define __NR_readlinkat 304
-#define __NR_fchmodat 305
-#define __NR_faccessat 305
-#define __NR_pselect6 307
-#define __NR_ppoll 308
-#define __NR_unshare 309
-#define __NR_set_robust_list 310
-#define __NR_get_robust_list 311
-#define __NR_splice 312
-#define __NR_sync_file_range 313
-#define __NR_tee 314
-#define __NR_vmsplice 315
+/* #define __NR_sys_setaltroot 285 */
+#define __NR_add_key 286
+#define __NR_request_key 287
+#define __NR_keyctl 288
+#define __NR_ioprio_set 289
+#define __NR_ioprio_get 290
+#define __NR_inotify_init 291
+#define __NR_inotify_add_watch 292
+#define __NR_inotify_rm_watch 293
+#define __NR_migrate_pages 294
+#define __NR_openat 295
+#define __NR_mkdirat 296
+#define __NR_mknodat 297
+#define __NR_fchownat 298
+#define __NR_futimesat 299
+#define __NR_newfstatat 300
+#define __NR_unlinkat 301
+#define __NR_renameat 302
+#define __NR_linkat 303
+#define __NR_symlinkat 304
+#define __NR_readlinkat 305
+#define __NR_fchmodat 306
+#define __NR_faccessat 307
+#define __NR_pselect6 308
+#define __NR_ppoll 309
+#define __NR_unshare 310
+#define __NR_set_robust_list 311
+#define __NR_get_robust_list 312
+#define __NR_splice 313
+#define __NR_sync_file_range 314
+#define __NR_tee 315
+#define __NR_vmsplice 316
-#define NR_syscalls 316
+#define NR_syscalls 317
#ifdef __KERNEL__
@@ -466,6 +467,7 @@ __syscall_return(type,__sc0); \
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#ifdef __KERNEL_SYSCALLS__