[PATCH] Improving send_sigio() scalability

Richard Gooch (rgooch@atnf.csiro.au)
Tue, 18 May 1999 23:40:20 +1000


Alexander Kjeldaas writes:
> On Mon, May 17, 1999 at 01:17:59PM +1000, Richard Gooch wrote:
> > Hi, all. I just noticed that send_sigio() walks the task list,
> > looking for the process(es) to send a signal to. This appears to be a
> > potential scalability problem, as a large number of tasks is going to
> > slow this down.
> >
> > Has anyone done any benchmarking to evaluate the effect of this? In
> > the absence of numbers, how about some convincing handwaving? Is it
> > worth exploring options to fix this?
> >
> > I can think of one quick and simple hack to fix this for 90% (maybe
> > 99%) of cases: record the task pointer at fcntl() time. Then at
> > send_sigio() time, if the recorded pid and task match, skip the
> > task list walk.
>
> In the case where send_sigio is sending a signal to a specific
> process, why isn't it using find_task_by_pid()?.

As promised, here's the patch to do this. Not only is it good (it
compiles), but it is perfect (it boots). Up 9 minutes so far without
problems.

Regards,

Richard....

diff -urN linux-2.3.3/fs/fcntl.c linux/fs/fcntl.c
--- linux-2.3.3/fs/fcntl.c Sat Nov 14 05:07:26 1998
+++ linux/fs/fcntl.c Tue May 18 23:21:47 1999
@@ -183,26 +183,15 @@
return err;
}

-static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa)
+static void send_sigio_to_task(struct task_struct *p,
+ struct fown_struct *fown, struct fasync_struct *fa)
{
- struct task_struct * p;
- int pid = fown->pid;
- uid_t uid = fown->uid;
- uid_t euid = fown->euid;
-
- read_lock(&tasklist_lock);
- for_each_task(p) {
- int match = p->pid;
- if (pid < 0)
- match = -p->pgrp;
- if (pid != match)
- continue;
- if ((euid != 0) &&
- (euid ^ p->suid) && (euid ^ p->uid) &&
- (uid ^ p->suid) && (uid ^ p->uid))
- continue;
- switch (fown->signum) {
- siginfo_t si;
+ if ((fown->euid != 0) &&
+ (fown->euid ^ p->suid) && (fown->euid ^ p->uid) &&
+ (fown->uid ^ p->suid) && (fown->uid ^ p->uid))
+ return;
+ switch (fown->signum) {
+ siginfo_t si;
default:
/* Queue a rt signal with the appropriate fd as its
value. We use SI_SIGIO as the source, not
@@ -213,16 +202,36 @@
si.si_signo = fown->signum;
si.si_errno = 0;
si.si_code = SI_SIGIO;
- si.si_pid = pid;
- si.si_uid = uid;
+ si.si_pid = fown->pid;
+ si.si_uid = fown->uid;
si.si_fd = fa->fa_fd;
if (!send_sig_info(fown->signum, &si, p))
break;
/* fall-through: fall back on the old plain SIGIO signal */
case 0:
send_sig(SIGIO, p, 1);
- }
}
+}
+
+static void send_sigio(struct fown_struct *fown, struct fasync_struct *fa)
+{
+ struct task_struct * p;
+ int pid = fown->pid;
+
+ read_lock(&tasklist_lock);
+ if ( (pid > 0) && (p = find_task_by_pid(pid)) ) {
+ send_sigio_to_task(p, fown, fa);
+ goto out;
+ }
+ for_each_task(p) {
+ int match = p->pid;
+ if (pid < 0)
+ match = -p->pgrp;
+ if (pid != match)
+ continue;
+ send_sigio_to_task(p, fown, fa);
+ }
+out:
read_unlock(&tasklist_lock);
}

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