Author: thompsa
Date: Wed Jan 21 04:19:18 2009
New Revision: 187511
URL: http://svn.freebsd.org/changeset/base/187511

Log:
  Add functions WITNESS so it can be asserted that the lock is not released for 
a
  section of code, this uses WITNESS_NORELEASE() and WITNESS_RELEASEOK() to mark
  the boundaries. Both functions require the lock to be held when calling.
  
  This is intended for scenarios like a bus asserting that the bus lock is not
  dropped during a driver call. There doesn't appear to be a man page to
  document this in.
  
  Reviewed by:  jhb

Modified:
  head/sys/kern/subr_witness.c
  head/sys/sys/lock.h

Modified: head/sys/kern/subr_witness.c
==============================================================================
--- head/sys/kern/subr_witness.c        Wed Jan 21 02:53:00 2009        
(r187510)
+++ head/sys/kern/subr_witness.c        Wed Jan 21 04:19:18 2009        
(r187511)
@@ -127,6 +127,7 @@ __FBSDID("$FreeBSD$");
 
 #define        LI_RECURSEMASK  0x0000ffff      /* Recursion depth of lock 
instance. */
 #define        LI_EXCLUSIVE    0x00010000      /* Exclusive lock instance. */
+#define        LI_NORELEASE    0x00020000      /* Lock not allowed to be 
released. */
 
 /* Define this to check for blessed mutexes */
 #undef BLESSING
@@ -367,6 +368,7 @@ static struct witness_lock_order_data       *w
                                            struct witness *parent,
                                            struct witness *child);
 static void    witness_list_lock(struct lock_instance *instance);
+static void    witness_setflag(struct lock_object *lock, int flag, int set);
 
 #ifdef KDB
 #define        witness_debugger(c)     _witness_debugger(c, __func__)
@@ -1509,6 +1511,11 @@ found:
                    instance->li_line);
                panic("share->uexcl");
        }
+       if ((instance->li_flags & LI_NORELEASE) != 0 && witness_watch > 0) {
+               printf("forbidden unlock of (%s) %s @ %s:%d\n", class->lc_name,
+                   lock->lo_name, file, line);
+               panic("lock marked norelease");
+       }
 
        /* If we are recursed, unrecurse. */
        if ((instance->li_flags & LI_RECURSEMASK) > 0) {
@@ -2224,6 +2231,48 @@ witness_assert(struct lock_object *lock,
 #endif /* INVARIANT_SUPPORT */
 }
 
+static void
+witness_setflag(struct lock_object *lock, int flag, int set)
+{
+       struct lock_list_entry *lock_list;
+       struct lock_instance *instance;
+       struct lock_class *class;
+
+       if (lock->lo_witness == NULL || witness_watch == -1 || panicstr != NULL)
+               return;
+       class = LOCK_CLASS(lock);
+       if (class->lc_flags & LC_SLEEPLOCK)
+               lock_list = curthread->td_sleeplocks;
+       else {
+               if (witness_skipspin)
+                       return;
+               lock_list = PCPU_GET(spinlocks);
+       }
+       instance = find_instance(lock_list, lock);
+       if (instance == NULL)
+               panic("%s: lock (%s) %s not locked", __func__,
+                   class->lc_name, lock->lo_name);
+
+       if (set)
+               instance->li_flags |= flag;
+       else
+               instance->li_flags &= ~flag;
+}
+
+void
+witness_norelease(struct lock_object *lock)
+{
+
+       witness_setflag(lock, LI_NORELEASE, 1);
+}
+
+void
+witness_releaseok(struct lock_object *lock)
+{
+
+       witness_setflag(lock, LI_NORELEASE, 0);
+}
+
 #ifdef DDB
 static void
 witness_ddb_list(struct thread *td)

Modified: head/sys/sys/lock.h
==============================================================================
--- head/sys/sys/lock.h Wed Jan 21 02:53:00 2009        (r187510)
+++ head/sys/sys/lock.h Wed Jan 21 04:19:18 2009        (r187511)
@@ -216,6 +216,8 @@ int witness_warn(int, struct lock_object
 void   witness_assert(struct lock_object *, int, const char *, int);
 void   witness_display_spinlock(struct lock_object *, struct thread *);
 int    witness_line(struct lock_object *);
+void   witness_norelease(struct lock_object *);
+void   witness_releaseok(struct lock_object *);
 const char *witness_file(struct lock_object *);
 void   witness_thread_exit(struct thread *);
 
@@ -267,6 +269,12 @@ void       witness_thread_exit(struct thread *
 #define        WITNESS_RESTORE(lock, n)                                        
\
        witness_restore((lock), __CONCAT(n, __wf), __CONCAT(n, __wl))
 
+#define        WITNESS_NORELEASE(lock)                                         
\
+       witness_norelease(&(lock)->lock_object)
+
+#define        WITNESS_RELEASEOK(lock)                                         
\
+       witness_releaseok(&(lock)->lock_object)
+
 #define        WITNESS_FILE(lock)                                              
\
        witness_file(lock)
 
@@ -287,6 +295,8 @@ void        witness_thread_exit(struct thread *
 #define        WITNESS_SAVE_DECL(n)
 #define        WITNESS_SAVE(lock, n)
 #define        WITNESS_RESTORE(lock, n)
+#define        WITNESS_NORELEASE(lock)
+#define        WITNESS_RELEASEOK(lock)
 #define        WITNESS_FILE(lock) ("?")
 #define        WITNESS_LINE(lock) (0)
 #endif /* WITNESS */
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to