patch-2.4.0-test7 linux/kernel/signal.c
Next file: linux/kernel/timer.c
Previous file: linux/kernel/sched.c
Back to the patch index
Back to the overall index
- Lines: 140
- Date:
Mon Aug 21 11:46:57 2000
- Orig file:
v2.4.0-test6/linux/kernel/signal.c
- Orig date:
Fri Jun 23 21:55:23 2000
diff -u --recursive --new-file v2.4.0-test6/linux/kernel/signal.c linux/kernel/signal.c
@@ -45,6 +45,42 @@
}
+/* Given the mask, find the first available signal that should be serviced. */
+
+static int
+next_signal(sigset_t *signal, sigset_t *mask)
+{
+ unsigned long i, *s, *m, x;
+ int sig = 0;
+
+ s = signal->sig;
+ m = mask->sig;
+ switch (_NSIG_WORDS) {
+ default:
+ for (i = 0; i < _NSIG_WORDS; ++i, ++s, ++m)
+ if ((x = *s &~ *m) != 0) {
+ sig = ffz(~x) + i*_NSIG_BPW + 1;
+ break;
+ }
+ break;
+
+ case 2: if ((x = s[0] &~ m[0]) != 0)
+ sig = 1;
+ else if ((x = s[1] &~ m[1]) != 0)
+ sig = _NSIG_BPW + 1;
+ else
+ break;
+ sig += ffz(~x);
+ break;
+
+ case 1: if ((x = *s &~ *m) != 0)
+ sig = ffz(~x) + 1;
+ break;
+ }
+
+ return sig;
+}
+
/*
* Flush all pending signals for a task.
*/
@@ -86,6 +122,32 @@
}
}
+/* Notify the system that a driver wants to block all signals for this
+ * process, and wants to be notified if any signals at all were to be
+ * sent/acted upon. If the notifier routine returns non-zero, then the
+ * signal will be acted upon after all. If the notifier routine returns 0,
+ * then then signal will be blocked. Only one block per process is
+ * allowed. priv is a pointer to private data that the notifier routine
+ * can use to determine if the signal should be blocked or not. */
+
+void
+block_all_signals(int (*notifier)(void *priv), void *priv, sigset_t *mask)
+{
+ current->notifier_mask = mask;
+ current->notifier_data = priv;
+ current->notifier = notifier;
+}
+
+/* Notify the system that blocking has ended. */
+
+void
+unblock_all_signals(void)
+{
+ current->notifier = NULL;
+ current->notifier_data = NULL;
+ recalc_sigpending(current);
+}
+
/*
* Dequeue a signal and return the element to the caller, which is
* expected to free it.
@@ -96,7 +158,6 @@
int
dequeue_signal(sigset_t *mask, siginfo_t *info)
{
- unsigned long i, *s, *m, x;
int sig = 0;
#if DEBUG_SIG
@@ -104,30 +165,22 @@
signal_pending(current));
#endif
- /* Find the first desired signal that is pending. */
- s = current->signal.sig;
- m = mask->sig;
- switch (_NSIG_WORDS) {
- default:
- for (i = 0; i < _NSIG_WORDS; ++i, ++s, ++m)
- if ((x = *s &~ *m) != 0) {
- sig = ffz(~x) + i*_NSIG_BPW + 1;
- break;
- }
- break;
-
- case 2: if ((x = s[0] &~ m[0]) != 0)
- sig = 1;
- else if ((x = s[1] &~ m[1]) != 0)
- sig = _NSIG_BPW + 1;
- else
- break;
- sig += ffz(~x);
- break;
-
- case 1: if ((x = *s &~ *m) != 0)
- sig = ffz(~x) + 1;
- break;
+ sig = next_signal(¤t->signal, mask);
+ if (current->notifier) {
+ sigset_t merged;
+ int i;
+ int altsig;
+
+ for (i = 0; i < _NSIG_WORDS; i++)
+ merged.sig[i] = mask->sig[i]
+ | current->notifier_mask->sig[i];
+ altsig = next_signal(¤t->signal, &merged);
+ if (sig != altsig) {
+ if (!(current->notifier)(current->notifier_data)) {
+ current->sigpending = 0;
+ return 0;
+ }
+ }
}
if (sig) {
@@ -657,6 +710,8 @@
EXPORT_SYMBOL(recalc_sigpending);
EXPORT_SYMBOL(send_sig);
EXPORT_SYMBOL(send_sig_info);
+EXPORT_SYMBOL(block_all_signals);
+EXPORT_SYMBOL(unblock_all_signals);
/*
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)