summaryrefslogtreecommitdiff
path: root/sys/kern/sys_generic.c
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>2007-03-24 16:01:23 +0000
committerArtur Grabowski <art@cvs.openbsd.org>2007-03-24 16:01:23 +0000
commitb85e9ba20c14a428d67fc578018fd8a539c89f7b (patch)
treeb40dafa9a5122b8fb1353291f58602e22cbd30a1 /sys/kern/sys_generic.c
parentbb009c4c0bea668c35c72a9601e752153bc19d8a (diff)
Kill the horrible hack of storing the pid in struct selinfo.
Instead, keep the proc pointer in it and put the selinfo on a list in struct proc in selrecord. Then clean up the list when leaving sys_select and sys_poll. miod@ ok, testing by many, including Bobs spamd boxes.
Diffstat (limited to 'sys/kern/sys_generic.c')
-rw-r--r--sys/kern/sys_generic.c56
1 files changed, 36 insertions, 20 deletions
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index 31cbafefff7..a79c121c00c 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sys_generic.c,v 1.55 2007/03/15 10:22:30 art Exp $ */
+/* $OpenBSD: sys_generic.c,v 1.56 2007/03/24 16:01:22 art Exp $ */
/* $NetBSD: sys_generic.c,v 1.24 1996/03/29 00:25:32 cgd Exp $ */
/*
@@ -66,6 +66,8 @@ int selscan(struct proc *, fd_set *, fd_set *, int, int, register_t *);
int seltrue(dev_t, int, struct proc *);
void pollscan(struct proc *, struct pollfd *, u_int, register_t *);
+void sel_clean_proclist(struct proc *);
+
/*
* Read system call.
*/
@@ -708,6 +710,7 @@ retry:
if (error == 0)
goto retry;
done:
+ sel_clean_proclist(p);
atomic_clearbits_int(&p->p_flag, P_SELECT);
/* select is not restarted after signals... */
if (error == ERESTART)
@@ -781,17 +784,12 @@ seltrue(dev_t dev, int events, struct proc *p)
void
selrecord(struct proc *selector, struct selinfo *sip)
{
- struct proc *p;
- pid_t mypid;
-
- mypid = selector->p_pid;
- if (sip->si_selpid == mypid)
- return;
- if (sip->si_selpid && (p = pfind(sip->si_selpid)) &&
- p->p_wchan == (caddr_t)&selwait)
+ if (sip->si_selproc == NULL) {
+ sip->si_selproc = selector;
+ TAILQ_INSERT_TAIL(&selector->p_selects, sip, si_list);
+ } else if (sip->si_selproc != selector) {
sip->si_flags |= SI_COLL;
- else
- sip->si_selpid = mypid;
+ }
}
/*
@@ -803,25 +801,42 @@ selwakeup(struct selinfo *sip)
struct proc *p;
int s;
- if (sip->si_selpid == 0)
- return;
if (sip->si_flags & SI_COLL) {
nselcoll++;
sip->si_flags &= ~SI_COLL;
wakeup(&selwait);
}
- p = pfind(sip->si_selpid);
- sip->si_selpid = 0;
- if (p != NULL) {
- SCHED_LOCK(s);
- if (p->p_wchan == (caddr_t)&selwait) {
+
+ /*
+ * We check the process once before locking.
+ * Then we wake the process and clean up its
+ * selects list.
+ */
+ if (sip->si_selproc == NULL)
+ return;
+
+ SCHED_LOCK(s);
+ if ((p = sip->si_selproc) != NULL) {
+ if (p->p_wchan != NULL) {
if (p->p_stat == SSLEEP)
setrunnable(p);
else
unsleep(p);
- } else if (p->p_flag & P_SELECT)
+ } else {
atomic_clearbits_int(&p->p_flag, P_SELECT);
- SCHED_UNLOCK(s);
+ }
+ }
+ SCHED_UNLOCK(s);
+}
+
+void
+sel_clean_proclist(struct proc *p)
+{
+ struct selinfo *sip;
+
+ while ((sip = TAILQ_FIRST(&p->p_selects)) != NULL) {
+ sip->si_selproc = NULL;
+ TAILQ_REMOVE(&p->p_selects, sip, si_list);
}
}
@@ -932,6 +947,7 @@ retry:
goto retry;
done:
+ sel_clean_proclist(p);
atomic_clearbits_int(&p->p_flag, P_SELECT);
/*
* NOTE: poll(2) is not restarted after a signal and EWOULDBLOCK is