On 15/12/20(Tue) 17:23, Visa Hankala wrote:
> On Tue, Dec 15, 2020 at 07:46:01AM -0300, Martin Pieuchot wrote:
> > @@ -636,43 +651,59 @@ dopselect(struct proc *p, int nd, fd_set
> > if (sigmask)
> > dosigsuspend(p, *sigmask &~ sigcantmask);
> >
> > -retry:
> > - ncoll = nselcoll;
> > - atomic_setbits_int(&p->p_flag, P_SELECT);
> > - error = selscan(p, pibits[0], pobits[0], nd, ni, retval);
> > - if (error || *retval)
> > + /* Register kqueue events */
> > + if ((error = pselregister(p, pibits[0], nd, ni, &nevents) != 0))
> > goto done;
>
> The above has parentheses wrong and returns 1 (EPERM) as error.
> The lines should read:
>
> if ((error = pselregister(p, pibits[0], nd, ni, &nevents)) != 0)
> goto done;
Thanks fixed.
> In addition to the above, I noticed that select(2) behaves differently
> than before when a file descriptor that is being monitored is closed by
> another thread. The old implementation returns EBADF. The new code keeps
> on waiting on the underlying object.
>
> The diff below makes kqueue clear kqpoll's fd event registration on
> fd close. However, it does not make select(2) return an error, the fd
> just will not cause a wakeup any longer. I think I have an idea on how
> to correct that but I need to consider it some more.
Are you saying that knote_fdclose() can't cleanup the knotes on the
per-thread kqueue?
If so, should we replace the call of kqueue_free() in kqpoll_exit() by
a KQRELE()? The original intend was to not put the per-thread kqueue to
the fdp list. As you just pointed out this is necessary. So I don't
see any need for kqueue_free(). We could even assert that the refcount
is 1.
Diff below does that, feel free to commit it.
Index: kern/kern_event.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_event.c,v
retrieving revision 1.148
diff -u -p -r1.148 kern_event.c
--- kern/kern_event.c 15 Dec 2020 04:48:18 -0000 1.148
+++ kern/kern_event.c 16 Dec 2020 11:19:01 -0000
@@ -168,12 +168,11 @@ KQREF(struct kqueue *kq)
void
KQRELE(struct kqueue *kq)
{
- struct filedesc *fdp;
+ struct filedesc *fdp = kq->kq_fdp;
if (atomic_dec_int_nv(&kq->kq_refs) > 0)
return;
- fdp = kq->kq_fdp;
if (rw_status(&fdp->fd_lock) == RW_WRITE) {
LIST_REMOVE(kq, kq_next);
} else {
@@ -182,12 +181,6 @@ KQRELE(struct kqueue *kq)
fdpunlock(fdp);
}
- kqueue_free(kq);
-}
-
-void
-kqueue_free(struct kqueue *kq)
-{
free(kq->kq_knlist, M_KEVENT, kq->kq_knlistsize *
sizeof(struct knlist));
hashfree(kq->kq_knhash, KN_HASHSIZE, M_KEVENT);
@@ -509,12 +502,17 @@ void
kqpoll_init(void)
{
struct proc *p = curproc;
+ struct filedesc *fdp;
if (p->p_kq != NULL)
return;
p->p_kq = kqueue_alloc(p->p_fd);
p->p_kq_serial = arc4random();
+ fdp = p->p_fd;
+ fdplock(fdp);
+ LIST_INSERT_HEAD(&fdp->fd_kqlist, p->p_kq, kq_next);
+ fdpunlock(fdp);
}
void
@@ -526,7 +524,8 @@ kqpoll_exit(void)
return;
kqueue_terminate(p, p->p_kq);
- kqueue_free(p->p_kq);
+ KASSERT(p->p_kq->kq_refs == 1);
+ KQRELE(p->p_kq);
p->p_kq = NULL;
}