From owner-p4-projects Wed Mar 5 14:15:58 2003 Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id 2585237B405; Wed, 5 Mar 2003 14:15:52 -0800 (PST) Delivered-To: perforce@freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id AAE5437B401 for ; Wed, 5 Mar 2003 14:15:51 -0800 (PST) Received: from repoman.freebsd.org (repoman.freebsd.org [216.136.204.115]) by mx1.FreeBSD.org (Postfix) with ESMTP id 3934543F75 for ; Wed, 5 Mar 2003 14:15:51 -0800 (PST) (envelope-from jhb@freebsd.org) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.12.6/8.12.6) with ESMTP id h25MFp0U004421 for ; Wed, 5 Mar 2003 14:15:51 -0800 (PST) (envelope-from jhb@freebsd.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.12.6/8.12.6/Submit) id h25MFoYh004418 for perforce@freebsd.org; Wed, 5 Mar 2003 14:15:50 -0800 (PST) Date: Wed, 5 Mar 2003 14:15:50 -0800 (PST) Message-Id: <200303052215.h25MFoYh004418@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to jhb@freebsd.org using -f From: John Baldwin Subject: PERFORCE change 26396 for review To: Perforce Change Reviews Sender: owner-p4-projects@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG http://perforce.freebsd.org/chv.cgi?CH=26396 Change 26396 by jhb@jhb_laptop on 2003/03/05 14:15:49 - Sort more of the static function prototypes into alphabetical order and add some new ones. - Make the stuff to print out the name of dead witnesses conditional on #if 1 for now to make it easier to remove later. - Add a depart() function to remove a dead witness from the lock order hierarchy and free it and call depart() from witness_destroy() when the refcount hits zero. - Change rebalancetree() to take the type list pointer as an argument so that it will actually compile. - Add a reparentchildren() function to take all the children of one witness and add them as direct children of another witness. We use this in depart() to reparent all the children of a dead witness to each of its parents. Affected files ... .. //depot/projects/smpng/sys/kern/subr_witness.c#80 edit Differences ... ==== //depot/projects/smpng/sys/kern/subr_witness.c#80 (text+ko) ==== @@ -152,17 +152,20 @@ struct lock_class *w_class; }; +#ifdef BLESSING +static int blessed(struct witness *, struct witness *); +#endif +static int depart(struct witness *w); static struct witness *enroll(const char *description, struct lock_class *lock_class); static int insertchild(struct witness *parent, struct witness *child); +static int isitmychild(struct witness *parent, struct witness *child); +static int isitmydescendant(struct witness *parent, struct witness *child); static int itismychild(struct witness *parent, struct witness *child); +static int rebalancetree(struct witness_list *list); static void removechild(struct witness *parent, struct witness *child); -static int isitmychild(struct witness *parent, struct witness *child); -static int isitmydescendant(struct witness *parent, struct witness *child); -static int rebalancetree(void); -#ifdef BLESSING -static int blessed(struct witness *, struct witness *); -#endif +static int reparentchildren(struct witness *newparent, + struct witness *oldparent); static void witness_displaydescendants(void(*)(const char *fmt, ...), struct witness *); static void witness_leveldescendents(struct witness *parent, int level); @@ -442,7 +445,9 @@ witness_destroy(struct lock_object *lock) { struct witness *w; - int print; +#if 1 + const char *name = NULL; +#endif if (witness_cold) panic("lock (%s) %s destroyed while witness_cold", @@ -457,29 +462,20 @@ mtx_lock_spin(&w_mtx); MPASS(w->w_refcount > 0); w->w_refcount--; - print = 0; - if (w->w_refcount == 0) { - /* - * If no locks for this witness were ever acquired, - * then return the witness to the free list. - */ - if (w->w_file == NULL) { - if (w->w_class->lc_flags & LC_SLEEPLOCK) - STAILQ_REMOVE(&w_sleep, w, witness, - w_typelist); - else - STAILQ_REMOVE(&w_spin, w, witness, - w_typelist); - STAILQ_REMOVE(&w_all, w, witness, w_list); - witness_free(w); - } else if (w->w_dead_squawked == 0) { - w->w_dead_squawked = 1; - print = 1; - } - } - mtx_unlock_spin(&w_mtx); - if (print) +#if 1 + if (w->w_refcount == 0) + name = w->w_name; +#endif + /* + * Lock is already released if we have an allocation failure + * and depart() fails. + */ + if (w->w_refcount != 0 || depart(w)) + mtx_unlock_spin(&w_mtx); +#if 1 + if (name != NULL) printf("dead witness: %s\n", w->w_name); +#endif } mtx_lock(&all_mtx); @@ -1119,23 +1115,66 @@ return (w); } +/* Don't let the door bang you on the way out... */ +static int +depart(struct witness *w) +{ + struct witness_child_list_entry *wcl, *nwcl; + struct witness_list *list; + struct witness *parent; + + MPASS(w->w_refcount == 0); + if (w->w_class->lc_flags & LC_SLEEPLOCK) + list = &w_sleep; + else + list = &w_spin; + /* + * First, we run through the entire tree looking for any + * witnesses that the outgoing witness is a child of. For + * each parent that we find, we reparent all the direct + * children of the outgoing witness to its parent. + */ + STAILQ_FOREACH(parent, list, w_typelist) { + if (!isitmychild(parent, w)) + continue; + removechild(parent, w); + if (!reparentchildren(parent, w)) + return (0); + } + + /* + * Now we go through and free up the child list of the + * outgoing witness. + */ + for (wcl = w->w_children; wcl != NULL; wcl = nwcl) { + nwcl = wcl->wcl_next; + witness_child_free(wcl); + } + + /* + * Detach from various lists and free. + */ + STAILQ_REMOVE(list, w, witness, w_typelist); + STAILQ_REMOVE(&w_all, w, witness, w_list); + witness_free(w); + + /* Finally, fixup the tree. */ + return (rebalancetree(list)); +} + + /* - * Prune the whole tree. We look for cases where a lock is now - * both a descendant and a direct child of a given lock. In that - * case, we want to remove the direct child link from the tree. + * Prune an entire lock order tree. We look for cases where a lock + * is now both a descendant and a direct child of a given lock. In + * that case, we want to remove the direct child link from the tree. * * Returns false if insertchild() fails. */ static int -rebalancetree(void) +rebalancetree(struct witness_list *list) { struct witness *child, *parent; - struct witness_list *list; - if (parent->w_class->lc_flags & LC_SLEEPLOCK) - list = &w_sleep; - else - list = &w_spin; STAILQ_FOREACH(child, list, w_typelist) { STAILQ_FOREACH(parent, list, w_typelist) { if (!isitmychild(parent, child)) @@ -1178,9 +1217,30 @@ return (1); } +/* + * Make all the direct descendants of oldparent be direct descendants + * of newparent. + */ static int +reparentchildren(struct witness *newparent, struct witness *oldparent) +{ + struct witness_child_list_entry *wcl; + int i; + + /* Avoid making a witness a child of itself. */ + MPASS(!itismychild(oldparent, newparent)); + + for (wcl = oldparent->w_children; wcl != NULL; wcl = wcl->wcl_next) + for (i = 0; i < wcl->wcl_count; i++) + if (!insertchild(newparent, wcl->wcl_children[i])) + return (0); + return (1); +} + +static int itismychild(struct witness *parent, struct witness *child) { + struct witness_list *list; MPASS(child != NULL && parent != NULL); if ((parent->w_class->lc_flags & (LC_SLEEPLOCK | LC_SPINLOCK)) != @@ -1193,7 +1253,11 @@ if (!insertchild(parent, child)) return (0); - return (rebalancetree()); + if (parent->w_class->lc_flags & LC_SLEEPLOCK) + list = &w_sleep; + else + list = &w_spin; + return (rebalancetree(list)); } static void To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe p4-projects" in the body of the message