]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] Kernel thread signal handling.
authorDavid Woodhouse <dwmw2@infradead.org>
Mon, 13 Oct 2003 02:35:05 +0000 (19:35 -0700)
committerLinus Torvalds <torvalds@home.osdl.org>
Mon, 13 Oct 2003 02:35:05 +0000 (19:35 -0700)
 - add disallow_signal() to complement allow_signal(), rather than
   having different subsystems try to do it by hand.

 - add a version of dequeue_signal() which does the necessary locking on
   its own, again to avoid having modules have to care.

 - let 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.

   (Barf alert: we do this by just installing a dummy handler)

 - make jffs2 use the cleaned up infrastructure

fs/jffs2/background.c
include/linux/sched.h
kernel/exit.c

index 8d60e62800b0ae95e5214aba2c568e8f7a959686..ebef6567753c8ec149c30785e248d1dc9dbb53a7 100644 (file)
@@ -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 @@ static int jffs2_garbage_collect_thread(void *_c)
        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 @@ static int jffs2_garbage_collect_thread(void *_c)
        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 @@ static int jffs2_garbage_collect_thread(void *_c)
                        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 @@ static int jffs2_garbage_collect_thread(void *_c)
                        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 @@ static int jffs2_garbage_collect_thread(void *_c)
                        }
                }
                /* 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) {
index a7a92f6a70da2140d14863d709855589f9840582..a15d95aa34b5cf4b4fc9a8fc2af1728270c57be9 100644 (file)
@@ -576,6 +576,19 @@ extern void proc_caches_init(void);
 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 NORET_TYPE void do_group_exit(int);
 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 *);
index 08e2068e2ae5ebd7371eac655d85bb3a2a10a94e..25b62f5971be614d7d3112cce2a068f81ecab5a1 100644 (file)
@@ -273,6 +273,13 @@ int allow_signal(int sig)
 
        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;
@@ -280,6 +287,20 @@ int allow_signal(int sig)
 
 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
  *     attached user resources in one place where it belongs.