Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/nick-nhusb]: src/sys/dev/usb Make ucom(4) MP safe



details:   https://anonhg.NetBSD.org/src/rev/44fbd24d507a
branches:  nick-nhusb
changeset: 334242:44fbd24d507a
user:      skrll <skrll%NetBSD.org@localhost>
date:      Sat Sep 19 07:39:51 2015 +0000

description:
Make ucom(4) MP safe

diffstat:

 sys/dev/usb/ucom.c |  247 +++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 167 insertions(+), 80 deletions(-)

diffs (truncated from 685 to 300 lines):

diff -r 1084f7160a60 -r 44fbd24d507a sys/dev/usb/ucom.c
--- a/sys/dev/usb/ucom.c        Sun Sep 13 09:27:54 2015 +0000
+++ b/sys/dev/usb/ucom.c        Sat Sep 19 07:39:51 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ucom.c,v 1.108.2.7 2015/07/23 07:36:33 skrll Exp $     */
+/*     $NetBSD: ucom.c,v 1.108.2.8 2015/09/19 07:39:51 skrll Exp $     */
 
 /*
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.108.2.7 2015/07/23 07:36:33 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ucom.c,v 1.108.2.8 2015/09/19 07:39:51 skrll Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -179,7 +179,11 @@
 
        struct pps_state        sc_pps_state;   /* pps state */
 
-       krndsource_t    sc_rndsource;   /* random source */
+       krndsource_t            sc_rndsource;   /* random source */
+
+       kmutex_t                *sc_lock;
+       kcondvar_t              sc_opencv;
+       kcondvar_t              sc_detachcv;
 };
 
 dev_type_open(ucomopen);
@@ -203,7 +207,7 @@
        .d_mmap = nommap,
        .d_kqfilter = ttykqfilter,
        .d_discard = nodiscard,
-       .d_flag = D_TTY
+       .d_flag = D_TTY | D_MPSAFE
 };
 
 static void    ucom_cleanup(struct ucom_softc *);
@@ -278,7 +282,10 @@
        sc->sc_refcnt = 0;
        sc->sc_dying = 0;
 
-       sc->sc_si = softint_establish(SOFTINT_NET, ucom_softintr, sc);
+       sc->sc_si = softint_establish(SOFTINT_USB, ucom_softintr, sc);
+       sc->sc_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTUSB);
+       cv_init(&sc->sc_opencv, "ucomopen");
+       cv_init(&sc->sc_detachcv, "ucomdtch");
 
        tp = tty_alloc();
        tp->t_oproc = ucomstart;
@@ -303,14 +310,17 @@
        struct ucom_softc *sc = device_private(self);
        struct tty *tp = sc->sc_tty;
        int maj, mn;
-       int s, i;
+       int i;
 
        UCOMHIST_FUNC(); UCOMHIST_CALLED();
 
        DPRINTF("sc=%p flags=%d tp=%p", sc, flags, tp, 0);
        DPRINTF("... pipe=%d,%d",sc->sc_bulkin_no, sc->sc_bulkout_no, 0, 0);
 
+       mutex_enter(sc->sc_lock);
        sc->sc_dying = 1;
+       mutex_exit(sc->sc_lock);
+
        pmf_device_deregister(self);
 
        if (sc->sc_bulkin_pipe != NULL)
@@ -318,8 +328,8 @@
        if (sc->sc_bulkout_pipe != NULL)
                usbd_abort_pipe(sc->sc_bulkout_pipe);
 
-       s = splusb();
-       if (--sc->sc_refcnt >= 0) {
+       mutex_enter(sc->sc_lock);
+       while (sc->sc_refcnt > 0) {
                /* Wake up anyone waiting */
                if (tp != NULL) {
                        mutex_spin_enter(&tty_lock);
@@ -329,11 +339,11 @@
                        mutex_spin_exit(&tty_lock);
                }
                /* Wait for processes to go away. */
-               usb_detach_waitold(sc->sc_dev);
+               usb_detach_wait(sc->sc_dev, &sc->sc_detachcv, sc->sc_lock);
        }
 
        softint_disestablish(sc->sc_si);
-       splx(s);
+       mutex_exit(sc->sc_lock);
 
        /* locate the major number */
        maj = cdevsw_lookup_major(&ucom_cdevsw);
@@ -365,6 +375,10 @@
        /* Detach the random source */
        rnd_detach_source(&sc->sc_rndsource);
 
+       mutex_destroy(sc->sc_lock);
+       cv_destroy(&sc->sc_opencv);
+       cv_destroy(&sc->sc_detachcv);
+
        return 0;
 }
 
@@ -379,7 +393,9 @@
 
        switch (act) {
        case DVACT_DEACTIVATE:
+               mutex_enter(sc->sc_lock);
                sc->sc_dying = 1;
+               mutex_exit(sc->sc_lock);
                return 0;
        default:
                return EOPNOTSUPP;
@@ -393,13 +409,15 @@
 
        UCOMHIST_FUNC(); UCOMHIST_CALLED();
 
+       KASSERT(mutex_owned(sc->sc_lock));
        /*
         * Hang up if necessary.  Wait a bit, so the other side has time to
         * notice even if we immediately open the port again.
         */
        if (ISSET(tp->t_cflag, HUPCL)) {
                ucom_dtr(sc, 0);
-               (void)tsleep(sc, TTIPRI, ttclos, hz);
+               /* XXX will only timeout */
+               (void) kpause(ttclos, false, hz, sc->sc_lock);
        }
 }
 
@@ -411,7 +429,7 @@
        struct ucom_softc *sc = device_lookup_private(&ucom_cd, unit);
        struct ucom_buffer *ub;
        struct tty *tp;
-       int s, i;
+       int i;
        int error;
 
        UCOMHIST_FUNC(); UCOMHIST_CALLED();
@@ -419,31 +437,38 @@
        if (sc == NULL)
                return ENXIO;
 
-       if (sc->sc_dying)
+       mutex_enter(sc->sc_lock);
+       if (sc->sc_dying) {
+               mutex_exit(sc->sc_lock);
                return EIO;
+       }
 
-       if (!device_is_active(sc->sc_dev))
+       if (!device_is_active(sc->sc_dev)) {
+               mutex_exit(sc->sc_lock);
                return ENXIO;
+       }
 
        tp = sc->sc_tty;
 
        DPRINTF("unit=%d, tp=%p\n", unit, tp, 0, 0);
 
-       if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
+       if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) {
+               mutex_exit(sc->sc_lock);
                return EBUSY;
-
-       s = spltty();
+       }
 
        /*
         * Do the following iff this is a first open.
         */
-       while (sc->sc_opening)
-               tsleep(&sc->sc_opening, PRIBIO, "ucomop", 0);
+       while (sc->sc_opening) {
+               error = cv_wait_sig(&sc->sc_opencv, sc->sc_lock);
 
-       if (sc->sc_dying) {
-               splx(s);
-               return EIO;
+               if (error) {
+                       mutex_exit(sc->sc_lock);
+                       return error;
+               }
        }
+
        sc->sc_opening = 1;
 
        if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
@@ -457,8 +482,8 @@
                        if (error) {
                                ucom_cleanup(sc);
                                sc->sc_opening = 0;
-                               wakeup(&sc->sc_opening);
-                               splx(s);
+                               cv_signal(&sc->sc_opencv);
+                               mutex_exit(sc->sc_lock);
                                return error;
                        }
                }
@@ -577,8 +602,8 @@
 
        }
        sc->sc_opening = 0;
-       wakeup(&sc->sc_opening);
-       splx(s);
+       cv_signal(&sc->sc_opencv);
+       mutex_exit(sc->sc_lock);
 
        error = ttyopen(tp, UCOMDIALOUT(dev), ISSET(flag, O_NONBLOCK));
        if (error)
@@ -614,13 +639,15 @@
        usbd_close_pipe(sc->sc_bulkin_pipe);
        sc->sc_bulkin_pipe = NULL;
 fail_0:
+       mutex_enter(sc->sc_lock);
        sc->sc_opening = 0;
-       wakeup(&sc->sc_opening);
-       splx(s);
+       cv_signal(&sc->sc_opencv);
+       mutex_exit(sc->sc_lock);
+
        return error;
 
 bad:
-       s = spltty();
+       mutex_spin_enter(&tty_lock);
        CLR(tp->t_state, TS_BUSY);
        if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
                /*
@@ -629,7 +656,7 @@
                 */
                ucom_cleanup(sc);
        }
-       splx(s);
+       mutex_spin_exit(&tty_lock);
 
        return error;
 }
@@ -639,7 +666,6 @@
 {
        struct ucom_softc *sc = device_lookup_private(&ucom_cd, UCOMUNIT(dev));
        struct tty *tp;
-       int s;
 
        UCOMHIST_FUNC(); UCOMHIST_CALLED();
 
@@ -648,12 +674,13 @@
        if (sc == NULL)
                return 0;
 
+       mutex_enter(sc->sc_lock);
        tp = sc->sc_tty;
 
-       if (!ISSET(tp->t_state, TS_ISOPEN))
-               return 0;
+       if (!ISSET(tp->t_state, TS_ISOPEN)) {
+               goto out;
+       }
 
-       s = spltty();
        sc->sc_refcnt++;
 
        (*tp->t_linesw->l_close)(tp, flag);
@@ -672,8 +699,10 @@
                sc->sc_methods->ucom_close(sc->sc_parent, sc->sc_portno);
 
        if (--sc->sc_refcnt < 0)
-               usb_detach_wakeupold(sc->sc_dev);
-       splx(s);
+               usb_detach_broadcast(sc->sc_dev, &sc->sc_detachcv);
+
+out:
+       mutex_exit(sc->sc_lock);
 
        return 0;
 }
@@ -687,15 +716,26 @@
 
        UCOMHIST_FUNC(); UCOMHIST_CALLED();
 
-       if (sc == NULL || sc->sc_dying)
+       if (sc == NULL)
                return EIO;
 
+       mutex_enter(sc->sc_lock);
+       if (sc->sc_dying) {
+               mutex_exit(sc->sc_lock);
+               return EIO;
+       }
+
        tp = sc->sc_tty;
 
        sc->sc_refcnt++;
+       mutex_exit(sc->sc_lock);
        error = ((*tp->t_linesw->l_read)(tp, uio, flag));
+       mutex_enter(sc->sc_lock);



Home | Main Index | Thread Index | Old Index