#include #include #include #include #if 0 /* Usage example */ struct driver_softc { ... struct weakobj sc_weakobj; ... }; struct driver_file { ... struct weakref df_weaksc; ... }; int driver_read(struct driver_file *fp, ...) { struct driver_file file = fp->f_data; struct weakobj *weakobj; struct driver_softc *sc; struct psref psref; int error; if ((weakobj = weakref_psref_acquire(&file->df_weaksc, &psref, driver_psref_class)) == NULL) return ENXIO; sc = container_of(weakobj, struct driver_softc, sc_weakobj); error = do_read(sc, ...); weakref_psref_release(weakobj, &psref, driver_psref_class); return error; } int driver_close(struct driver_file *fp, ...) { struct driver_file file = fp->f_data; struct weakobj *weakobj; struct driver_softc *sc; struct psref psref; int error; if ((weakobj = weakref_psref_acquire(&file->df_weaksc, &psref, driver_psref_class)) == NULL) return ENXIO; sc = container_of(weakobj, struct driver_softc, sc_weakobj); mutex_enter(&sc->sc_lock); weakref_put(&file->df_weaksc, weakobj); ...do close cleanup actions....; mutex_exit(&sc->sc_lock); weakref_psref_release(weakobj, &psref, driver_psref_class); return error; } #endif struct weakref { struct weakobj wr_obj; SLIST_ENTRY(weakref) wr_entry; }; struct weakobj { SLIST_HEAD(, weakref) wo_refs; struct psref_target wo_psref; }; /* * weakref_get(ref, obj) * * Get a weak reference to an object. The object can later be * used with weakref_try until weakref_break. * * Caller must hold an exclusive lock for obj. */ void weakref_get(struct weakref *ref, struct weakobj *obj) { SLIST_INSERT_HEAD(obj->wo_refs, ref, weakref, wr_entry); ref->wr_obj = obj; } /* * weakref_put(ref, obj) * * Release a weak reference to an object. The reference may no * longer be used after this. * * Caller must hold an exclusive lock for obj. */ void weakref_put(struct weakref *wr, struct weakobj *obj) { if (wr->wr_obj) { KASSERT(wr->wr_obj == obj); SLIST_REMOVE(&obj->wo_refs, wr, struct weakref, wr_entry); } } /* * weakref_psref_acquire(ref, psref, class) * * Try to acquire a passive reference to the referent of ref. * Return NULL on failure. On success, caller must later do * weakref_psref_release(obj, psref, class). */ struct weakobj * weakref_psref_acquire(struct weakref *ref, struct psref *psref, struct psref_class *class) { struct weakobj *obj; int s; s = pserialize_read_enter(); if ((obj = atomic_load_relaxed(&ref->wr_obj)) == NULL) { pserialize_read_exit(s); return NULL; } psref_acquire(psref, &obj->wo_psref, class); pserialize_read_exit(s); return obj; } /* * weakref_psref_release(obj, psref, class) * * Release a passive reference to an object obtained with * weakref_psref_acquire. */ void weakref_psref_release(struct weakobj *obj, struct psref *psref, struct psref_class *class) { psref_release(psref, &obj->wo_psref, class); } /* * weakref_break(obj) * * Break all weak references to obj. Subsequent attempts to * weakref_psref_acquire will return NULL. However, there may be * passive references in use; caller must wait for them to drain * with weakref_drain(obj, class). * * Caller must hold an exclusive lock for obj. */ void weakref_break(struct weakobj *obj) { struct weakref *ref; while ((ref = SLIST_FIRST(&obj->wo_refs)) != NULL) { SLIST_REMOVE_HEAD(&obj->wo_refs, wr_entry); atomic_store_relaxed(&ref->wr_obj, NULL); } } /* * weakref_drain(obj, class) * * Wait for all passive references to obj to be released. Caller * must have previously called weakref_break. * * Caller must have exclusive access to obj except for outstanding * passive references. */ void weakref_drain(struct weakobj *obj, struct psref_class *clas) { ASSERT_SLEEPABLE(); xc_barrier(XC_HIGHPRI); psref_target_destroy(&obj->wo_psref, class); }