Index: subr_bus.c =================================================================== --- subr_bus.c (revision 227031) +++ subr_bus.c (working copy) @@ -388,9 +388,10 @@ TAILQ_HEAD(devq, dev_event_info); +static MALLOC_DEFINE(M_DEVCTL, "devctl", "devctl device"); + static struct dev_softc { - int inuse; int nonblock; int queued; struct mtx mtx; @@ -398,40 +399,73 @@ struct selinfo sel; struct devq devq; struct proc *async_proc; -} devsoftc; + int waiting_threads; + int dead; + TAILQ_ENTRY(dev_softc) next; +}; +static TAILQ_HEAD(devctlq, dev_softc); +static mtx devctlmtx; +static struct devctlq devctlq; + static struct cdev *devctl_dev; static void +devdtor(void *data) +{ + struct dev_softc *devsoftc = data; + struct dev_event_info *n1; + + mtx_lock(&devctlmtx); + TAILQ_REMOVE(devctlq, devsoftc, next); + mtx_unlock(&devctlmtx); + + mtx_lock(&devsoftc->mtx); + devsoftc->dead = 1; + while (!TAILQ_EMPTY(&devsoftc->devq)) { + n1 = TAILQ_FIRST(&devsoftc->devq); + TAILQ_REMOVE(&devsoftc->devq, n1, dei_link); + free(n1->dei_data, M_BUS); + free(n1, M_BUS); + } + cv_broadcast(&devsoftc->cv); + while (devsoftc->waiting_threads > 0) + cv_wait_sig(&devsoftc->cv, &devsoftc->mtx); + cv_destroy(&devsoftc->cv); + mtx_unlock(&devsoftc->mtx); + mtx_destroy(&devsoftc->mtx); + free(devsoftc, M_DEVCTL); + +} + +static void devinit(void) { devctl_dev = make_dev_credf(MAKEDEV_ETERNAL, &dev_cdevsw, 0, NULL, UID_ROOT, GID_WHEEL, 0600, "devctl"); - mtx_init(&devsoftc.mtx, "dev mtx", "devd", MTX_DEF); - cv_init(&devsoftc.cv, "dev cv"); - TAILQ_INIT(&devsoftc.devq); + mtx_init(&devctlmtx); + + TAILQ_INIT(&devctlq); } static int devopen(struct cdev *dev, int oflags, int devtype, struct thread *td) { - if (devsoftc.inuse) - return (EBUSY); - /* move to init */ - devsoftc.inuse = 1; - devsoftc.nonblock = 0; - devsoftc.async_proc = NULL; - return (0); -} + struct dev_softc *devsoftc; -static int -devclose(struct cdev *dev, int fflag, int devtype, struct thread *td) -{ - devsoftc.inuse = 0; - mtx_lock(&devsoftc.mtx); - cv_broadcast(&devsoftc.cv); - mtx_unlock(&devsoftc.mtx); - devsoftc.async_proc = NULL; + devsoftc = malloc(sizeof(struct dev_softc), M_DEVCTL, M_WAITOK|M_ZERO); + mtx_init(&devsoftc->mtx, "dev mtx", "devd", MTX_DEF); + cv_init(&devsoftc->cv, "dev cv"); + TAILQ_INIT(&devsoftc->devq); + + devsoftc->nonblock = 0; + devsoftc->async_proc = NULL; + + devfs_set_cdevpriv(devsoftc, devdtor); + mtx_lock(&devctlmtx); + TAILQ_INSERT_TAIL(&devctlq, devsoftc, next); + mtx_unlock(&devctlmtx); + return (0); } @@ -447,27 +481,37 @@ devread(struct cdev *dev, struct uio *uio, int ioflag) { struct dev_event_info *n1; + struct dev_softc *devsoftc; int rv; + int error; - mtx_lock(&devsoftc.mtx); - while (TAILQ_EMPTY(&devsoftc.devq)) { - if (devsoftc.nonblock) { - mtx_unlock(&devsoftc.mtx); + error = devfs_get_cdevpriv((void **)&devsoftc); + if (error != 0) + return (error); + + mtx_lock(&devsoftc->mtx); + while (TAILQ_EMPTY(&devsoftc->devq)) { + if (devsoftc->nonblock) { + mtx_unlock(&devsoftc->mtx); return (EAGAIN); } - rv = cv_wait_sig(&devsoftc.cv, &devsoftc.mtx); - if (rv) { + devsoftc->waiting_threads++; + rv = cv_wait_sig(&devsoftc->cv, &devsoftc->mtx); + devsoftc->waiting_threads--; + if (rv || devsoftc->dead) { /* * Need to translate ERESTART to EINTR here? -- jake */ - mtx_unlock(&devsoftc.mtx); + if (devsoftc->dead && devsoftc->waiting_threads == 0) + cv_broadcast(&devsoftc->cv); + mtx_unlock(&devsoftc->mtx); return (rv); } } - n1 = TAILQ_FIRST(&devsoftc.devq); - TAILQ_REMOVE(&devsoftc.devq, n1, dei_link); - devsoftc.queued--; - mtx_unlock(&devsoftc.mtx); + n1 = TAILQ_FIRST(&devsoftc->devq); + TAILQ_REMOVE(&devsoftc->devq, n1, dei_link); + devsoftc->queued--; + mtx_unlock(&devsoftc->mtx); rv = uiomove(n1->dei_data, strlen(n1->dei_data), uio); free(n1->dei_data, M_BUS); free(n1, M_BUS); @@ -477,19 +521,26 @@ static int devioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread *td) { + struct dev_softc *devsoftc; + int error; + + error = devfs_get_cdevpriv((void **)&devsoftc); + if (error != 0) + return (error); + switch (cmd) { case FIONBIO: if (*(int*)data) - devsoftc.nonblock = 1; + devsoftc->nonblock = 1; else - devsoftc.nonblock = 0; + devsoftc->nonblock = 0; return (0); case FIOASYNC: if (*(int*)data) - devsoftc.async_proc = td->td_proc; + devsoftc->async_proc = td->td_proc; else - devsoftc.async_proc = NULL; + devsoftc->async_proc = NULL; return (0); /* (un)Support for other fcntl() calls. */ @@ -507,16 +558,22 @@ static int devpoll(struct cdev *dev, int events, struct thread *td) { + struct dev_softc *devsoftc; + int error; int revents = 0; - mtx_lock(&devsoftc.mtx); + error = devfs_get_cdevpriv((void **)&devsoftc); + if (error != 0) + return (error); + + mtx_lock(&devsoftc->mtx); if (events & (POLLIN | POLLRDNORM)) { - if (!TAILQ_EMPTY(&devsoftc.devq)) + if (!TAILQ_EMPTY(&devsoftc->devq)) revents = events & (POLLIN | POLLRDNORM); else - selrecord(td, &devsoftc.sel); + selrecord(td, &devsoftc->sel); } - mtx_unlock(&devsoftc.mtx); + mtx_unlock(&devsoftc->mtx); return (revents); } @@ -527,7 +584,7 @@ boolean_t devctl_process_running(void) { - return (devsoftc.inuse == 1); + return !TAILQ_EMPTY(devctlq); } /** @@ -538,7 +595,7 @@ * that @p data is allocated using the M_BUS malloc type. */ void -devctl_queue_data_f(char *data, int flags) +devctl_queue_data_f(struct dev_softc *devsoftc, char *data, int flags) { struct dev_event_info *n1 = NULL, *n2 = NULL; struct proc *p; @@ -551,27 +608,27 @@ if (n1 == NULL) goto out; n1->dei_data = data; - mtx_lock(&devsoftc.mtx); + mtx_lock(&devsoftc->mtx); if (devctl_queue_length == 0) { - mtx_unlock(&devsoftc.mtx); + mtx_unlock(&devsoftc->mtx); free(n1->dei_data, M_BUS); free(n1, M_BUS); return; } /* Leave at least one spot in the queue... */ - while (devsoftc.queued > devctl_queue_length - 1) { - n2 = TAILQ_FIRST(&devsoftc.devq); - TAILQ_REMOVE(&devsoftc.devq, n2, dei_link); + while (devsoftc->queued > devctl_queue_length - 1) { + n2 = TAILQ_FIRST(&devsoftc->devq); + TAILQ_REMOVE(&devsoftc->devq, n2, dei_link); free(n2->dei_data, M_BUS); free(n2, M_BUS); - devsoftc.queued--; + devsoftc->queued--; } - TAILQ_INSERT_TAIL(&devsoftc.devq, n1, dei_link); - devsoftc.queued++; - cv_broadcast(&devsoftc.cv); - mtx_unlock(&devsoftc.mtx); - selwakeup(&devsoftc.sel); - p = devsoftc.async_proc; + TAILQ_INSERT_TAIL(&devsoftc->devq, n1, dei_link); + devsoftc->queued++; + cv_broadcast(&devsoftc->cv); + mtx_unlock(&devsoftc->mtx); + selwakeup(&devsoftc->sel); + p = devsoftc->async_proc; if (p != NULL) { PROC_LOCK(p); kern_psignal(p, SIGIO); @@ -590,8 +647,13 @@ void devctl_queue_data(char *data) { + struct dev_softc *devsoftc; - devctl_queue_data_f(data, M_NOWAIT); + mtx_lock(&devctlmtx); + TAILQ_FOREACH(&devctlq, devsoftc, next) { + devctl_queue_data_f(devsoftc, data, M_NOWAIT); + } + mtx_unlock(&devctlmtx); } /** @@ -738,26 +800,31 @@ sysctl_devctl_disable(SYSCTL_HANDLER_ARGS) { struct dev_event_info *n1; + struct dev_softc *devsoftc; int dis, error; dis = devctl_queue_length == 0; error = sysctl_handle_int(oidp, &dis, 0, req); if (error || !req->newptr) return (error); - mtx_lock(&devsoftc.mtx); + mtx_lock(&devctlmtx); if (dis) { - while (!TAILQ_EMPTY(&devsoftc.devq)) { - n1 = TAILQ_FIRST(&devsoftc.devq); - TAILQ_REMOVE(&devsoftc.devq, n1, dei_link); - free(n1->dei_data, M_BUS); - free(n1, M_BUS); + TAILQ_FOREACH(&devctlq, devsoftc, next) { + mtx_lock(&devsoftc->mtx); + while (!TAILQ_EMPTY(&devsoftc->devq)) { + n1 = TAILQ_FIRST(&devsoftc->devq); + TAILQ_REMOVE(&devsoftc->devq, n1, dei_link); + free(n1->dei_data, M_BUS); + free(n1, M_BUS); + } + devsoftc->queued = 0; + devctl_queue_length = 0; + mtx_unlock(&devsoftc->mtx); } - devsoftc.queued = 0; - devctl_queue_length = 0; } else { devctl_queue_length = DEVCTL_DEFAULT_QUEUE_LEN; } - mtx_unlock(&devsoftc.mtx); + mtx_unlock(&devctlmtx); return (0); } @@ -765,6 +832,7 @@ sysctl_devctl_queue(SYSCTL_HANDLER_ARGS) { struct dev_event_info *n1; + struct dev_softc *devsoftc; int q, error; q = devctl_queue_length; @@ -773,16 +841,21 @@ return (error); if (q < 0) return (EINVAL); - mtx_lock(&devsoftc.mtx); + mtx_lock(&devctlmtx); devctl_queue_length = q; - while (devsoftc.queued > devctl_queue_length) { - n1 = TAILQ_FIRST(&devsoftc.devq); - TAILQ_REMOVE(&devsoftc.devq, n1, dei_link); - free(n1->dei_data, M_BUS); - free(n1, M_BUS); - devsoftc.queued--; + TAILQ_FOREACH(&devctlq, devsoftc, next) { + mtx_lock(&devsoftc->mtx); + while (devsoftc->queued > devctl_queue_length) { + n1 = TAILQ_FIRST(&devsoftc->devq); + TAILQ_REMOVE(&devsoftc->devq, n1, dei_link); + free(n1->dei_data, M_BUS); + free(n1, M_BUS); + devsoftc->queued--; + } + mtx_unlock(&devsoftc->mtx); } - mtx_unlock(&devsoftc.mtx); + mtx_unlock(&devctlmtx); + return (0); }