lkml.org 
[lkml]   [2003]   [Oct]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Subject[RFC][PATCH] Kernel thread signal handling.
From
Date
1. We need disallow_signal() to complement allow_signal().

2. We need a function which does dequeue_signal() _with_ locking.

3. We might need a better name for #2. Change if you care.

4. We need allow_signal() to actually allow signals other than
SIGKILL. Currently they get either converted to SIGKILL or
silently dropped, according to whether your kernel thread
happens to have sa_handler set for the signal in question.

It would be nicer to fix this in the signal delivery code
itself if (!tsk->mm) rather than by faking a handler in
allow_signal(). I'm not touching the signal delivery code
with a bargepole though. Hopefully the proposed change to
allow_signal() will provoke someone else into doing so.

===== include/linux/sched.h 1.171 vs edited =====
--- 1.171/include/linux/sched.h Thu Oct 9 23:13:53 2003
+++ edited/include/linux/sched.h Mon Oct 13 10:11:07 2003
@@ -576,6 +576,19 @@
extern void flush_signals(struct task_struct *);
extern void flush_signal_handlers(struct task_struct *, int force_default);
extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info);
+
+static inline int dequeue_signal_lock(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
+{
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&tsk->sighand->siglock, flags);
+ ret = dequeue_signal(tsk, mask, info);
+ spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+
+ return ret;
+}
+
extern void block_all_signals(int (*notifier)(void *priv), void *priv,
sigset_t *mask);
extern void unblock_all_signals(void);
@@ -673,6 +686,7 @@
extern void reparent_to_init(void);
extern void daemonize(const char *, ...);
extern int allow_signal(int);
+extern int disallow_signal(int);
extern task_t *child_reaper;

extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *);
===== kernel/exit.c 1.116 vs edited =====
--- 1.116/kernel/exit.c Thu Oct 9 23:13:54 2003
+++ edited/kernel/exit.c Mon Oct 13 11:19:04 2003
@@ -273,12 +273,33 @@

spin_lock_irq(&current->sighand->siglock);
sigdelset(&current->blocked, sig);
+ if (!current->mm) {
+ /* Kernel threads handle their own signals.
+ Let the signal code know it'll be handled, so
+ that they don't get converted to SIGKILL or
+ just silently dropped */
+ current->sighand->action[(sig)-1].sa.sa_handler = (void *)2;
+ }
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
return 0;
}

EXPORT_SYMBOL(allow_signal);
+
+int disallow_signal(int sig)
+{
+ if (sig < 1 || sig > _NSIG)
+ return -EINVAL;
+
+ spin_lock_irq(&current->sighand->siglock);
+ sigaddset(&current->blocked, sig);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+ return 0;
+}
+
+EXPORT_SYMBOL(disallow_signal);

/*
* Put all the gunge required to become a kernel thread without
===== fs/jffs2/background.c 1.20 vs edited =====
--- 1.20/fs/jffs2/background.c Sat Oct 11 15:47:54 2003
+++ edited/fs/jffs2/background.c Mon Oct 13 11:17:54 2003
@@ -19,6 +19,7 @@
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/unistd.h>
+#include <linux/suspend.h>
#include "nodelist.h"


@@ -75,6 +76,9 @@
struct jffs2_sb_info *c = _c;

daemonize("jffs2_gcd_mtd%d", c->mtd->index);
+ allow_signal(SIGKILL);
+ allow_signal(SIGSTOP);
+ allow_signal(SIGCONT);

c->gc_task = current;
up(&c->gc_thread_start);
@@ -82,10 +86,7 @@
set_user_nice(current, 10);

for (;;) {
- spin_lock_irq(&current_sig_lock);
- siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
- recalc_sigpending();
- spin_unlock_irq(&current_sig_lock);
+ allow_signal(SIGHUP);

if (!thread_should_wake(c)) {
set_current_state (TASK_INTERRUPTIBLE);
@@ -97,6 +98,13 @@
schedule();
}

+ if (current->flags & PF_FREEZE) {
+ refrigerator(0);
+ /* refrigerator() should recalc sigpending for us
+ but doesn't. No matter - allow_signal() will. */
+ continue;
+ }
+
cond_resched();

/* Put_super will send a SIGKILL and then wait on the sem.
@@ -105,9 +113,7 @@
siginfo_t info;
unsigned long signr;

- spin_lock_irq(&current_sig_lock);
- signr = dequeue_signal(current, &current->blocked, &info);
- spin_unlock_irq(&current_sig_lock);
+ signr = dequeue_signal_lock(current, &current->blocked, &info);

switch(signr) {
case SIGSTOP:
@@ -132,10 +138,7 @@
}
}
/* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
- spin_lock_irq(&current_sig_lock);
- siginitsetinv (&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
- recalc_sigpending();
- spin_unlock_irq(&current_sig_lock);
+ disallow_signal(SIGHUP);

D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n"));
if (jffs2_garbage_collect_pass(c) == -ENOSPC) {

--
dwmw2

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:49    [W:0.066 / U:0.148 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site