tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: struct ifnet and ifaddr handling [was: Re: Making global variables of if.c MPSAFE]
On Wed, Nov 19, 2014 at 3:11 AM, Taylor R Campbell
<campbell+netbsd-tech-kern%mumble.net@localhost> wrote:
> Date: Tue, 18 Nov 2014 13:31:49 +0900
> From: Ryota Ozaki <ozaki-r%netbsd.org@localhost>
>
> I have to say sorry for my bad writing; I misled you about
> "free an ifnet object" due to my forgetfulness about the fact that
> an ifnet object is normally embedded into a softc of each driver
> (via ethercom) in NetBSD. (I.e., we cannot free an ifnet object
> independently.) So with the current implementation, if_detach
> have to wait for ifput releasing the ifnet object, to prevent
> the driver from freeing sc. So it's a little bit difficult to use
> "GC objects later" strategy for ifnet objects.
>
> Normally in cases like this, where there is some resource that many
> things can use (various parts of the network stack) but only one owns
> (the NIC driver), the resource can be destroyed when the owner chooses
> to destroy it (inside the NIC driver's *_detach routine) only after
> (a) locking out new users, and then (b) waiting for all extant users
> to drain:
Yes. That's what I'm doing for ifnet with ifget/ifput. Nevertheless,
I'd copy the optimization of mumble_put where refcnt > 1 :)
>
> void
> mumble_destroy(struct mumble *m)
> {
>
> mutex_enter(&m->m_lock);
> m->m_flags |= MUMBLE_DYING; /* Lock out new users. */
> while (0 < m->m_refcnt) /* Wait for extant ones to drain. */
> cv_wait(&m->m_cv, &m->m_lock);
> /* We now have exclusive access. */
> mutex_exit(&m->m_lock);
> mutex_destroy(&m->m_lock);
> cv_destroy(&m->m_cv);
> pool_put(&mumble_pool, m);
> }
>
> int
> mumble_get(unsigned id, struct mumble **mp)
> {
> int error = ENOENT;
>
> MUMBLE_FOREACH(m) {
> if (m->m_id == id) {
> mutex_enter(&m->m_lock);
> if (!ISSET(m->m_flags, MUMBLE_DYING)) {
> atomic_inc_uint(&m->m_refcnt);
> error = 0;
> *mp = m;
> }
> mutex_exit(&m->m_lock);
> break;
> }
> }
>
> return error;
> }
>
> void
> mumble_put(struct mumble *m)
> {
> unsigned refcnt;
>
> do {
> refcnt = m->m_refcnt;
> if (refcnt == 1) {
> mutex_enter(&m->m_lock);
> refcnt = atomic_dec_uint_nv(&m->m_refcnt);
> if (refcnt == 0)
> cv_broadcast(&m->m_cv);
> mutex_exit(&m->m_lock);
> }
> } while (atomic_cas_uint(&m->m_refcnt, refcnt, refcnt - 1) != refcnt);
> }
BTW, do we need break after mutex_exit? Otherwise, m->m_refcnt is likely
to be decremented twice when refcnt == 1.
Thanks,
ozaki-r
Home |
Main Index |
Thread Index |
Old Index