Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 Nov 2002 11:30:41 -0800 (PST)
From:      John Baldwin <jhb@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 20970 for review
Message-ID:  <200211111930.gABJUfUF085587@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=20970

Change 20970 by jhb@jhb_laptop on 2002/11/11 11:30:27

	Rename witness_sleep() to witness_warn() and make it a bit more
	extensible so it can handle more arbitrary messages, etc.  Also,
	add a function to display a single lock instance and share this
	code between witness_warn() and witness_list_locks().

Affected files ...

.. //depot/projects/smpng/sys/kern/subr_witness.c#62 edit
.. //depot/projects/smpng/sys/sys/lock.h#18 edit

Differences ...

==== //depot/projects/smpng/sys/kern/subr_witness.c#62 (text+ko) ====

@@ -145,6 +145,7 @@
 static void	witness_lock_list_free(struct lock_list_entry *lle);
 static struct	lock_instance *find_instance(struct lock_list_entry *lock_list,
 					     struct lock_object *lock);
+static int	witness_list_lock(struct lock_instance *instance);
 #if defined(DDB)
 static void	witness_display_list(void(*prnt)(const char *fmt, ...),
 				     struct witness_list *list);
@@ -912,60 +913,71 @@
 }
 
 /*
- * Warn if any held locks are not sleepable.  Note that Giant and the lock
- * passed in are both special cases since they are both released during the
- * sleep process and aren't actually held while the thread is asleep.
+ * Warn if any locks other than 'lock' are held.  Flags can be passed in to
+ * exempt Giant and sleepable locks from the checks as well.  If any
+ * non-exempt locks are held, then a supplied message is printed to the
+ * console along with a list of the offending locks.  If indicated in the
+ * flags then a failure results in a panic as well.
  */
 int
-witness_sleep(int check_only, struct lock_object *lock, const char *file,
-	      int line)
+witness_warn(int flags, struct lock_object *lock, const char *file, int line,
+    const char *fmt, ...)
 {
-	struct lock_list_entry **lock_list, *lle;
+	struct lock_list_entry *lle;
 	struct lock_instance *lock1;
 	struct thread *td;
+	va_list ap;
 	int i, n;
 
 	if (witness_cold || witness_dead || panicstr != NULL)
 		return (0);
 	n = 0;
 	td = curthread;
-	lock_list = &td->td_sleeplocks;
-again:
-	for (lle = *lock_list; lle != NULL; lle = lle->ll_next)
+	for (lle = td->td_sleeplocks; lle != NULL; lle = lle->ll_next)
 		for (i = lle->ll_count - 1; i >= 0; i--) {
 			lock1 = &lle->ll_children[i];
-			if (lock1->li_lock == lock ||
+			if (lock1->li_lock == lock)
+				continue;
+			if (flags & WARN_GIANTOK &&
 			    lock1->li_lock == &Giant.mtx_object)
 				continue;
-			if ((lock1->li_lock->lo_flags & LO_SLEEPABLE) != 0) {
-				if (check_only == 0) {
-					CTR3(KTR_WITNESS,
-				    "pid %d: sleeping with lock (%s) %s held",
-					    td->td_proc->p_pid,
-					    lock1->li_lock->lo_class->lc_name,
-					    lock1->li_lock->lo_name);
-					lock1->li_flags |= LI_SLEPT;
-				}
+			if (flags & WARN_SLEEPOK &&
+			    (lock1->li_lock->lo_flags & LO_SLEEPABLE) != 0)
 				continue;
+			if (n == 0) {
+				va_start(ap, fmt);
+				vprintf(fmt, ap);
+				va_end(ap);
+				printf(" with the following");
+				if (flags & WARN_SLEEPOK)
+					printf(" non-sleepable");
+				printf("locks held at %s:%d:\n", file, line);
 			}
 			n++;
-			printf("%s:%d: %s with \"%s\" locked from %s:%d\n",
-			    file, line, check_only ? "could sleep" : "sleeping",
-			    lock1->li_lock->lo_name, lock1->li_file,
-			    lock1->li_line);
+			witness_list_lock(lock1);
 		}
-	if (lock_list == &td->td_sleeplocks && PCPU_GET(spinlocks) != NULL) {
+	if (PCPU_GET(spinlocks) != NULL) {
 		/*
 		 * Since we already hold a spinlock preemption is
 		 * already blocked.
 		 */
-		lock_list = PCPU_PTR(spinlocks);
-		goto again;
+		if (n == 0) {
+			va_start(ap, fmt);
+			vprintf(fmt, ap);
+			va_end(ap);
+			printf(" with the following");
+			if (flags & WARN_SLEEPOK)
+				printf(" non-sleepable");
+			printf("locks held at %s:%d:\n", file, line);
+		}
+		n += witness_list_locks(PCPU_PTR(spinlocks));
 	}
+	if (flags & WARN_PANIC && n)
+		panic("witness_warn");
 #ifdef DDB
-	if (witness_ddb && n)
+	else if (witness_ddb && n)
 		Debugger(__func__);
-#endif /* DDB */
+#endif
 	return (n);
 }
 
@@ -1354,28 +1366,31 @@
 	return (NULL);
 }
 
+static int
+witness_list_lock(struct lock_instance *instance)
+{
+	struct lock_object *lock;
+
+	lock = instance->li_lock;
+	printf("%s %s %s", (instance->li_flags & LI_EXCLUSIVE) != 0 ?
+	    "exclusive" : "shared", lock->lo_class->lc_name, lock->lo_name);
+	if (lock->lo_type != lock->lo_name)
+		printf(" (%s)", lock->lo_type);
+	printf(" r = %d (%p) locked @ %s:%d\n",
+	    instance->li_flags & LI_RECURSEMASK, lock, instance->li_file,
+	    instance->li_line);
+}
+
 int
 witness_list_locks(struct lock_list_entry **lock_list)
 {
 	struct lock_list_entry *lle;
-	struct lock_instance *instance;
-	struct lock_object *lock;
 	int i, nheld;
 
 	nheld = 0;
 	for (lle = *lock_list; lle != NULL; lle = lle->ll_next)
 		for (i = lle->ll_count - 1; i >= 0; i--) {
-			instance = &lle->ll_children[i];
-			lock = instance->li_lock;
-			printf("%s %s %s",
-			    (instance->li_flags & LI_EXCLUSIVE) != 0 ?
-			    "exclusive" : "shared",
-			    lock->lo_class->lc_name, lock->lo_name);
-			if (lock->lo_type != lock->lo_name)
-				printf(" (%s)", lock->lo_type);
-			printf(" r = %d (%p) locked @ %s:%d\n",
-			    instance->li_flags & LI_RECURSEMASK, lock,
-			    instance->li_file, instance->li_line);
+			witness_list_lock(&lle->ll_children[i]);
 			nheld++;
 		}
 	return (nheld);

==== //depot/projects/smpng/sys/sys/lock.h#18 (text+ko) ====

@@ -212,6 +212,12 @@
 const char *witness_file(struct lock_object *);
 
 #ifdef	WITNESS
+
+/* Flags for witness_warn(). */
+#define	WARN_GIANTOK	0x01	/* Giant is exempt from this check. */
+#define	WARN_PANIC	0x02	/* Panic if check fails. */
+#define	WARN_SLEEPOK	0x04	/* Sleepable locks are exempt from check. */
+
 #define	WITNESS_INIT(lock)						\
 	witness_init((lock))
 
@@ -230,8 +236,8 @@
 #define	WITNESS_UNLOCK(lock, flags, file, line)				\
 	witness_unlock((lock), (flags), (file), (line))
 
-#define	WITNESS_SLEEP(check, lock) 					\
-	witness_sleep((check), (lock), __FILE__, __LINE__)
+#define	WITNESS_WARN(flags, lock, fmt, ...)				\
+	witness_warn((flags), (lock), __FILE__, __LINE__, (fmt), __VA_ARGS__)
 
 #define	WITNESS_SAVE_DECL(n)						\
 	const char * __CONCAT(n, __wf);					\
@@ -256,7 +262,7 @@
 #define	WITNESS_UPGRADE(lock, flags, file, line)
 #define	WITNESS_DOWNGRADE(lock, flags, file, line)
 #define	WITNESS_UNLOCK(lock, flags, file, line)
-#define	WITNESS_SLEEP(check, lock)
+#define	WITNESS_WARN(flags, lock, fmt, ...)
 #define	WITNESS_SAVE_DECL(n)
 #define	WITNESS_SAVE(lock, n)
 #define	WITNESS_RESTORE(lock, n)
@@ -264,5 +270,15 @@
 #define	WITNESS_LINE(lock) (0)
 #endif	/* WITNESS */
 
+/* XXX */
+#define	WITNESS_SLEEP(check, lock) do {					\
+	if ((check))							\
+		WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,		\
+		    "Could Sleep");					\
+	else								\
+		WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, lock,		\
+		    "Sleeping");					\
+} while (0)
+
 #endif	/* _KERNEL */
 #endif	/* _SYS_LOCK_H_ */

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe p4-projects" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200211111930.gABJUfUF085587>