- Fix ncp_poll() to not panic if the socket doesn't have any pending data.

We have to adjust curthread's state enough so that it appears to be
  in a poll(2) or select(2) call so that selrecord() will work and then
  teardown that state after calling sopoll().
- Fix some minor nits in nearby ncp_sock_rselect() and in the identical
  nbssn_rselect() function in the netsmb code:
  - Don't call nb_poll()/ncp_poll() now that ncp_poll() already fakes up
    poll(2) state since the rselect() functions already do that.  Just
    invoke sopoll() directly.
  - To make things slightly more intuitive, store the results of sopoll()
    in a new 'revents' variable rather than 'error' since that's what
    sopoll() actually returns.
  - If the requested timeout time has been exceeded by the time we get
    ready to block, then return EWOULDBLOCK rather than 0 to signal a
    timeout as this is what the calling code expects.

Tested by:	Eric Christeson <eric.j.christeson AT gmail> (1)
MFC after:	1 week
This commit is contained in:
John Baldwin 2006-08-03 15:31:52 +00:00
parent 60c6061882
commit ac695ab41b
2 changed files with 33 additions and 17 deletions

View File

@ -185,10 +185,28 @@ ncp_sock_send(struct socket *so, struct mbuf *top, struct ncp_rq *rqp)
int
ncp_poll(struct socket *so, int events)
{
struct thread *td = curthread;
struct ucred *cred = NULL;
struct thread *td = curthread;
int revents;
return (sopoll(so, events, cred, td));
/* Fake up enough state to look like we are in poll(2). */
mtx_lock(&sellock);
mtx_lock_spin(&sched_lock);
td->td_flags |= TDF_SELECT;
mtx_unlock_spin(&sched_lock);
mtx_unlock(&sellock);
TAILQ_INIT(&td->td_selq);
revents = sopoll(so, events, NULL, td);
/* Tear down the fake poll(2) state. */
mtx_lock(&sellock);
clear_selinfo_list(td);
mtx_lock_spin(&sched_lock);
td->td_flags &= ~TDF_SELECT;
mtx_unlock_spin(&sched_lock);
mtx_unlock(&sellock);
return (revents);
}
int
@ -196,7 +214,7 @@ ncp_sock_rselect(struct socket *so, struct thread *td, struct timeval *tv,
int events)
{
struct timeval atv, rtv, ttv;
int ncoll, timo, error = 0;
int ncoll, timo, error, revents;
if (tv) {
atv = *tv;
@ -218,16 +236,18 @@ ncp_sock_rselect(struct socket *so, struct thread *td, struct timeval *tv,
mtx_unlock(&sellock);
TAILQ_INIT(&td->td_selq);
error = ncp_poll(so, events);
revents = sopoll(so, events, NULL, td);
mtx_lock(&sellock);
if (error) {
if (revents) {
error = 0;
goto done;
}
if (tv) {
getmicrouptime(&rtv);
if (timevalcmp(&rtv, &atv, >=))
if (timevalcmp(&rtv, &atv, >=)) {
error = EWOULDBLOCK;
goto done;
}
ttv = atv;
timevalsub(&ttv, &rtv);
timo = tvtohz(&ttv);

View File

@ -94,18 +94,12 @@ nb_setsockopt_int(struct socket *so, int level, int name, int val)
return sosetopt(so, &sopt);
}
static __inline int
nb_poll(struct nbpcb *nbp, int events, struct thread *td)
{
return sopoll(nbp->nbp_tso, events, NULL, td);
}
static int
nbssn_rselect(struct nbpcb *nbp, struct timeval *tv, int events,
struct thread *td)
{
struct timeval atv, rtv, ttv;
int ncoll, timo, error;
int ncoll, timo, error, revents;
if (tv) {
atv = *tv;
@ -128,16 +122,18 @@ nbssn_rselect(struct nbpcb *nbp, struct timeval *tv, int events,
/* XXX: Should be done when the thread is initialized. */
TAILQ_INIT(&td->td_selq);
error = nb_poll(nbp, events, td);
revents = sopoll(nbp->nbp_tso, events, NULL, td);
mtx_lock(&sellock);
if (error) {
if (revents) {
error = 0;
goto done;
}
if (tv) {
getmicrouptime(&rtv);
if (timevalcmp(&rtv, &atv, >=))
if (timevalcmp(&rtv, &atv, >=)) {
error = EWOULDBLOCK;
goto done;
}
ttv = atv;
timevalsub(&ttv, &rtv);
timo = tvtohz(&ttv);