]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] linux-2.5.66-signal-cleanup.patch
authorRoland McGrath <roland@redhat.com>
Fri, 4 Apr 2003 12:12:17 +0000 (04:12 -0800)
committerLinus Torvalds <torvalds@home.transmeta.com>
Fri, 4 Apr 2003 12:12:17 +0000 (04:12 -0800)
Here is the cleanup patch I promised back in February.  Sorry it took a
while.

The effects should be purely cosmetic in 2.5.66.  However, the new
interface for the proper way to send thread-specific of process-global
signals from inside the kernel is needed for correct implementation of
some fixes to timer stuff that Ulrich told me about.

This cleans up some obsolete comments and macros in kernel/signal.c,
restores send_sig_info to its original behavior, and adds a global entry
point send_group_sig_info.  I checked all the uses of send_sig and
send_sig_info and changed a few to send_group_sig_info.

I think it would be cleanest if the whole mess of *_sig* entry points were
reduced to two or three, but I did the change that minimized the number of
callers I had to fix up.

There should be no discernible difference, since the 2.5.66 send_sig_info
function did group semantics for those signals by number already.  The only
exception to that is pdeath_signal, which I guess can be any signal number
but I deemed ought to be process-wide.

I did not change any of the calls using SIGKILL, though that does have
process-wide semantics.  There is no need to change it since SIGKILL always
kills the whole group, though the code path for send_sig(SIGKILL,...) calls
in multithreaded processes will be different now.

drivers/char/tty_io.c
drivers/isdn/i4l/isdn_tty.c
fs/fcntl.c
include/linux/sched.h
kernel/exit.c
kernel/itimer.c
kernel/signal.c

index f3c2f35381acaf0659106bcb078448d31dae128f..c57b097ac38914d66a1047cbbd0f5469724a2bca 100644 (file)
@@ -506,8 +506,8 @@ void do_tty_hangup(void *data)
                                p->tty = NULL;
                        if (!p->leader)
                                continue;
-                       send_sig(SIGHUP, p, 1);
-                       send_sig(SIGCONT, p, 1);
+                       send_group_sig_info(SIGHUP, SEND_SIG_PRIV, p);
+                       send_group_sig_info(SIGCONT, SEND_SIG_PRIV, p);
                        if (tty->pgrp > 0)
                                p->tty_old_pgrp = tty->pgrp;
                }
index dd58066f73867a905b70c01b601ae8899802352f..0053c471fb16afb40c6252afc10e4843c053e820 100644 (file)
@@ -2036,7 +2036,7 @@ modem_write_profile(atemu * m)
        memcpy(m->pmsn, m->msn, ISDN_MSNLEN);
        memcpy(m->plmsn, m->lmsn, ISDN_LMSNLEN);
        if (dev->profd)
-               send_sig(SIGIO, dev->profd, 1);
+               group_send_sig_info(SIGIO, SEND_SIG_PRIV, dev->profd);
 }
 
 int
index fae2022ada195a4c2e596df1d35bc2d7579cc2d5..f1bf41ec99a55d0cb8fd38c55f78811835073144 100644 (file)
@@ -465,7 +465,7 @@ static void send_sigio_to_task(struct task_struct *p,
                                break;
                /* fall-through: fall back on the old plain SIGIO signal */
                case 0:
-                       send_sig(SIGIO, p, 1);
+                       send_group_sig_info(SIGIO, SEND_SIG_PRIV, p);
        }
 }
 
@@ -501,7 +501,7 @@ static void send_sigurg_to_task(struct task_struct *p,
                                 struct fown_struct *fown)
 {
        if (sigio_perm(p, fown))
-               send_sig(SIGURG, p, 1);
+               send_group_sig_info(SIGURG, SEND_SIG_PRIV, p);
 }
 
 int send_sigurg(struct fown_struct *fown)
index d001088e58b3c718b3c49945298ecb3135b581bd..f3b4c5891898bc2c99b533c9a01fc6f1fa045b4b 100644 (file)
@@ -541,6 +541,7 @@ extern void block_all_signals(int (*notifier)(void *priv), void *priv,
 extern void unblock_all_signals(void);
 extern void release_task(struct task_struct * p);
 extern int send_sig_info(int, struct siginfo *, struct task_struct *);
+extern int send_group_sig_info(int, struct siginfo *, struct task_struct *);
 extern int force_sig_info(int, struct siginfo *, struct task_struct *);
 extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp);
 extern int kill_pg_info(int, struct siginfo *, pid_t);
@@ -558,6 +559,11 @@ extern int kill_proc(pid_t, int, int);
 extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *);
 extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long);
 
+/* These can be the second arg to send_sig_info/send_group_sig_info.  */
+#define SEND_SIG_NOINFO ((struct siginfo *) 0)
+#define SEND_SIG_PRIV  ((struct siginfo *) 1)
+#define SEND_SIG_FORCED        ((struct siginfo *) 2)
+
 /* True if we are on the alternate signal stack.  */
 
 static inline int on_sig_stack(unsigned long sp)
index ffc0973ab07476f50cc442d0878c0da1ef969cb7..b393a46247c4dfc367be6422ad0516fbd767f803 100644 (file)
@@ -488,7 +488,7 @@ static inline void reparent_thread(task_t *p, task_t *father, int traced)
        p->self_exec_id++;
 
        if (p->pdeath_signal)
-               send_sig(p->pdeath_signal, p, 0);
+               send_group_sig_info(p->pdeath_signal, 0, p);
 
        /* Move the child from its dying parent to the new one.  */
        if (unlikely(traced)) {
index 4fc29f3de5e831e725d438a822f91eaf830c5555..4db3b24ec41e7ba90dd5ba7350c92d81872f2eaf 100644 (file)
@@ -67,7 +67,7 @@ void it_real_fn(unsigned long __data)
        struct task_struct * p = (struct task_struct *) __data;
        unsigned long interval;
 
-       send_sig(SIGALRM, p, 1);
+       send_group_sig_info(SIGALRM, SEND_SIG_PRIV, p);
        interval = p->it_real_incr;
        if (interval) {
                if (interval > (unsigned long) LONG_MAX)
index 488134eec0e2ad8d07a3f1f099060fcff6949d1d..096d58ad5237ce7fee5237be90f46baf6a24f1c8 100644 (file)
@@ -33,64 +33,79 @@ static kmem_cache_t *sigqueue_cachep;
 atomic_t nr_queued_signals;
 int max_queued_signals = 1024;
 
-/*********************************************************
-
-    POSIX thread group signal behavior:
-
-----------------------------------------------------------
-|                    |  userspace       |  kernel        |
-----------------------------------------------------------
-|  SIGHUP            |  load-balance    |  kill-all      |
-|  SIGINT            |  load-balance    |  kill-all      |
-|  SIGQUIT           |  load-balance    |  kill-all+core |
-|  SIGILL            |  specific        |  kill-all+core |
-|  SIGTRAP           |  specific        |  kill-all+core |
-|  SIGABRT/SIGIOT    |  specific        |  kill-all+core |
-|  SIGBUS            |  specific        |  kill-all+core |
-|  SIGFPE            |  specific        |  kill-all+core |
-|  SIGKILL           |  n/a             |  kill-all      |
-|  SIGUSR1           |  load-balance    |  kill-all      |
-|  SIGSEGV           |  specific        |  kill-all+core |
-|  SIGUSR2           |  load-balance    |  kill-all      |
-|  SIGPIPE           |  specific        |  kill-all      |
-|  SIGALRM           |  load-balance    |  kill-all      |
-|  SIGTERM           |  load-balance    |  kill-all      |
-|  SIGCHLD           |  load-balance    |  ignore        |
-|  SIGCONT           |  load-balance    |  ignore        |
-|  SIGSTOP           |  n/a             |  stop-all      |
-|  SIGTSTP           |  load-balance    |  stop-all      |
-|  SIGTTIN           |  load-balance    |  stop-all      |
-|  SIGTTOU           |  load-balance    |  stop-all      |
-|  SIGURG            |  load-balance    |  ignore        |
-|  SIGXCPU           |  specific        |  kill-all+core |
-|  SIGXFSZ           |  specific        |  kill-all+core |
-|  SIGVTALRM         |  load-balance    |  kill-all      |
-|  SIGPROF           |  specific        |  kill-all      |
-|  SIGPOLL/SIGIO     |  load-balance    |  kill-all      |
-|  SIGSYS/SIGUNUSED  |  specific        |  kill-all+core |
-|  SIGSTKFLT         |  specific        |  kill-all      |
-|  SIGWINCH          |  load-balance    |  ignore        |
-|  SIGPWR            |  load-balance    |  kill-all      |
-|  SIGRTMIN-SIGRTMAX |  load-balance    |  kill-all      |
-----------------------------------------------------------
-
-    non-POSIX signal thread group behavior:
-
-----------------------------------------------------------
-|                    |  userspace       |  kernel        |
-----------------------------------------------------------
-|  SIGEMT            |  specific        |  kill-all+core |
-----------------------------------------------------------
-*/
-
-/* Some systems do not have a SIGSTKFLT and the kernel never
- * generates such signals anyways.
+/*
+ * In POSIX a signal is sent either to a specific thread (Linux task)
+ * or to the process as a whole (Linux thread group).  How the signal
+ * is sent determines whether it's to one thread or the whole group,
+ * which determines which signal mask(s) are involved in blocking it
+ * from being delivered until later.  When the signal is delivered,
+ * either it's caught or ignored by a user handler or it has a default
+ * effect that applies to the whole thread group (POSIX process).
+ *
+ * The possible effects an unblocked signal set to SIG_DFL can have are:
+ *   ignore    - Nothing Happens
+ *   terminate - kill the process, i.e. all threads in the group,
+ *               similar to exit_group.  The group leader (only) reports
+ *               WIFSIGNALED status to its parent.
+ *   coredump  - write a core dump file describing all threads using
+ *               the same mm and then kill all those threads
+ *   stop      - stop all the threads in the group, i.e. TASK_STOPPED state
+ *
+ * SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
+ * Other signals when not blocked and set to SIG_DFL behaves as follows.
+ * The job control signals also have other special effects.
+ *
+ *     +--------------------+------------------+
+ *     |  POSIX signal      |  default action  |
+ *     +--------------------+------------------+
+ *     |  SIGHUP            |  terminate       |
+ *     |  SIGINT            |  terminate       |
+ *     |  SIGQUIT           |  coredump        |
+ *     |  SIGILL            |  coredump        |
+ *     |  SIGTRAP           |  coredump        |
+ *     |  SIGABRT/SIGIOT    |  coredump        |
+ *     |  SIGBUS            |  coredump        |
+ *     |  SIGFPE            |  coredump        |
+ *     |  SIGKILL           |  terminate(+)    |
+ *     |  SIGUSR1           |  terminate       |
+ *     |  SIGSEGV           |  coredump        |
+ *     |  SIGUSR2           |  terminate       |
+ *     |  SIGPIPE           |  terminate       |
+ *     |  SIGALRM           |  terminate       |
+ *     |  SIGTERM           |  terminate       |
+ *     |  SIGCHLD           |  ignore          |
+ *     |  SIGCONT           |  ignore(*)       |
+ *     |  SIGSTOP           |  stop(*)(+)      |
+ *     |  SIGTSTP           |  stop(*)         |
+ *     |  SIGTTIN           |  stop(*)         |
+ *     |  SIGTTOU           |  stop(*)         |
+ *     |  SIGURG            |  ignore          |
+ *     |  SIGXCPU           |  coredump        |
+ *     |  SIGXFSZ           |  coredump        |
+ *     |  SIGVTALRM         |  terminate       |
+ *     |  SIGPROF           |  terminate       |
+ *     |  SIGPOLL/SIGIO     |  terminate       |
+ *     |  SIGSYS/SIGUNUSED  |  coredump        |
+ *     |  SIGSTKFLT         |  terminate       |
+ *     |  SIGWINCH          |  ignore          |
+ *     |  SIGPWR            |  terminate       |
+ *     |  SIGRTMIN-SIGRTMAX |  terminate       |
+ *     +--------------------+------------------+
+ *     |  non-POSIX signal  |  default action  |
+ *     +--------------------+------------------+
+ *     |  SIGEMT            |  coredump        |
+ *     +--------------------+------------------+
+ *
+ * (+) For SIGKILL and SIGSTOP the action is "always", not just "default".
+ * (*) Special job control effects:
+ * When SIGCONT is sent, it resumes the process (all threads in the group)
+ * from TASK_STOPPED state and also clears any pending/queued stop signals
+ * (any of those marked with "stop(*)").  This happens regardless of blocking,
+ * catching, or ignoring SIGCONT.  When any stop signal is sent, it clears
+ * any pending/queued SIGCONT signals; this happens regardless of blocking,
+ * catching, or ignored the stop signal, though (except for SIGSTOP) the
+ * default action of stopping the process may happen later or never.
  */
-#ifdef SIGSTKFLT
-#define M_SIGSTKFLT    M(SIGSTKFLT)
-#else
-#define M_SIGSTKFLT    0
-#endif
 
 #ifdef SIGEMT
 #define M_SIGEMT       M(SIGEMT)
@@ -105,16 +120,6 @@ int max_queued_signals = 1024;
 #endif
 #define T(sig, mask) (M(sig) & (mask))
 
-#define SIG_KERNEL_BROADCAST_MASK (\
-       M(SIGHUP)    |  M(SIGINT)    |  M(SIGQUIT)   |  M(SIGILL)    | \
-       M(SIGTRAP)   |  M(SIGABRT)   |  M(SIGBUS)    |  M(SIGFPE)    | \
-       M(SIGKILL)   |  M(SIGUSR1)   |  M(SIGSEGV)   |  M(SIGUSR2)   | \
-       M(SIGPIPE)   |  M(SIGALRM)   |  M(SIGTERM)   |  M(SIGXCPU)   | \
-       M(SIGXFSZ)   |  M(SIGVTALRM) |  M(SIGPROF)   |  M(SIGPOLL)   | \
-       M(SIGSYS)    |  M_SIGSTKFLT  |  M(SIGPWR)    |  M(SIGCONT)   | \
-        M(SIGSTOP)   |  M(SIGTSTP)   |  M(SIGTTIN)   |  M(SIGTTOU)   | \
-        M_SIGEMT )
-
 #define SIG_KERNEL_ONLY_MASK (\
        M(SIGKILL)   |  M(SIGSTOP)                                   )
 
@@ -599,7 +604,7 @@ static void do_notify_parent_cldstop(struct task_struct *tsk,
                                     struct task_struct *parent);
 
 /*
- * Handle magic process-wide effects of stop/continue signals, and SIGKILL.
+ * Handle magic process-wide effects of stop/continue signals.
  * Unlike the signal actions, these happen immediately at signal-generation
  * time regardless of blocking, ignoring, or handling.  This does the
  * actual continuing for SIGCONT, but not the actual stopping for stop
@@ -1134,9 +1139,8 @@ static int kill_something_info(int sig, struct siginfo *info, int pid)
  */
 
 /*
- * XXX should probably nix these interfaces and update the kernel
- * to specify explicitly whether the signal is a group signal or
- * specific to a thread.
+ * These two are the most common entry points.  They send a signal
+ * just to the specific thread.
  */
 int
 send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
@@ -1150,13 +1154,9 @@ send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
         * going away or changing from under us.
         */
        read_lock(&tasklist_lock);  
-       if (T(sig, SIG_KERNEL_BROADCAST_MASK)) {
-               ret = group_send_sig_info(sig, info, p);
-       } else {
-               spin_lock_irq(&p->sighand->siglock);
-               ret = specific_send_sig_info(sig, info, p);
-               spin_unlock_irq(&p->sighand->siglock);
-       }
+       spin_lock_irq(&p->sighand->siglock);
+       ret = specific_send_sig_info(sig, info, p);
+       spin_unlock_irq(&p->sighand->siglock);
        read_unlock(&tasklist_lock);
        return ret;
 }
@@ -1167,6 +1167,20 @@ send_sig(int sig, struct task_struct *p, int priv)
        return send_sig_info(sig, (void*)(long)(priv != 0), p);
 }
 
+/*
+ * This is the entry point for "process-wide" signals.
+ * They will go to an appropriate thread in the thread group.
+ */
+int
+send_group_sig_info(int sig, struct siginfo *info, struct task_struct *p)
+{
+       int ret;
+       read_lock(&tasklist_lock);
+       ret = group_send_sig_info(sig, info, p);
+       read_unlock(&tasklist_lock);
+       return ret;
+}
+
 void
 force_sig(int sig, struct task_struct *p)
 {
@@ -1642,6 +1656,7 @@ EXPORT_SYMBOL(kill_sl_info);
 EXPORT_SYMBOL(notify_parent);
 EXPORT_SYMBOL(send_sig);
 EXPORT_SYMBOL(send_sig_info);
+EXPORT_SYMBOL(send_group_sig_info);
 EXPORT_SYMBOL(sigprocmask);
 EXPORT_SYMBOL(block_all_signals);
 EXPORT_SYMBOL(unblock_all_signals);