On Mon, Nov 13, 2017 at 01:25:42PM +0100, Martin Pieuchot wrote:
> I'd love is somebody could do the changes in the rwlock API to let us
> check if we're holding a lock.  Maybe this is already present in
> witness(4), visa?

witness(4) does maintain data about lock ownership. The patch below
might do the trick for rwlocks without adding extra state tracking.

The patch also fixes the witness-side initialization of statically
initialized locks, in functions witness_checkorder() and
witness_lock(). The fix belongs to a separate commit though.

Index: share/man/man9/rwlock.9
===================================================================
RCS file: src/share/man/man9/rwlock.9,v
retrieving revision 1.20
diff -u -p -r1.20 rwlock.9
--- share/man/man9/rwlock.9     30 Oct 2017 13:33:36 -0000      1.20
+++ share/man/man9/rwlock.9     13 Nov 2017 17:05:51 -0000
@@ -33,6 +33,7 @@
 .Nm rw_assert_anylock ,
 .Nm rw_assert_unlocked ,
 .Nm rw_status ,
+.Nm rw_status_curproc ,
 .Nm RWLOCK_INITIALIZER ,
 .Nm rrw_init ,
 .Nm rrw_init_flags ,
@@ -68,6 +69,8 @@
 .Fn rw_assert_unlocked "struct rwlock *rwl"
 .Ft int
 .Fn rw_status "struct rwlock *rwl"
+.Ft int
+.Fn rw_status_curproc "struct rwlock *rwl"
 .Fn RWLOCK_INITIALIZER "const char *name"
 .Ft void
 .Fn rrw_init "struct rrwlock *rrwl" "const char *name"
@@ -181,7 +184,7 @@ functions check the status
 .Fa rwl ,
 panicking if it is not write-, read-, any-, or unlocked, respectively.
 .Pp
-.Nm rw_status
+.Fn rw_status
 returns the current state of the lock:
 .Pp
 .Bl -tag -width "RW_WRITE_OTHER" -offset indent -compact
@@ -194,6 +197,22 @@ Lock is read locked.
 The current thread may be one of the threads that has it locked.
 .It 0
 Lock is not locked.
+.El
+.Pp
+.Fn rw_status_curproc
+returns the current state of the lock relative to the calling thread:
+.Pp
+.Bl -tag -width "RW_WRITE_OTHER" -offset indent -compact
+.It Dv RW_WRITE
+Lock is write locked by the calling thread.
+.It Dv RW_READ
+Lock is read locked.
+The current thread may be one of the threads that has it locked.
+If the kernel has been compiled with
+.Xr witness 4 ,
+the status is exact, and the lock is read locked by the current thread.
+.It 0
+Lock is not locked by the calling thread.
 .El
 .Pp
 A lock declaration may be initialised with the
Index: sys/kern/kern_rwlock.c
===================================================================
RCS file: src/sys/kern/kern_rwlock.c,v
retrieving revision 1.32
diff -u -p -r1.32 kern_rwlock.c
--- sys/kern/kern_rwlock.c      24 Oct 2017 08:53:15 -0000      1.32
+++ sys/kern/kern_rwlock.c      13 Nov 2017 17:05:51 -0000
@@ -325,6 +325,34 @@ rw_status(struct rwlock *rwl)
        return (0);
 }
 
+int
+rw_status_curproc(struct rwlock *rwl)
+{
+       unsigned long owner;
+#ifdef WITNESS
+       int status = witness_status(&rwl->rwl_lock_obj);
+
+       if (status != -1) {
+               if (status & LA_XLOCKED)
+                       return (RW_WRITE);
+               if (status & LA_SLOCKED)
+                       return (RW_READ);
+               return (0);
+       }
+#endif
+
+       owner = rwl->rwl_owner;
+       if (owner & RWLOCK_WRLOCK) {
+               if (RW_PROC(curproc) == RW_PROC(owner))
+                       return (RW_WRITE);
+               else
+                       return (0);
+       }
+       if (owner)
+               return RW_READ;
+       return (0);
+}
+
 #ifdef DIAGNOSTIC
 void
 rw_assert_wrlock(struct rwlock *rwl)
Index: sys/kern/subr_witness.c
===================================================================
RCS file: src/sys/kern/subr_witness.c,v
retrieving revision 1.4
diff -u -p -r1.4 subr_witness.c
--- sys/kern/subr_witness.c     12 Aug 2017 03:13:23 -0000      1.4
+++ sys/kern/subr_witness.c     13 Nov 2017 17:05:51 -0000
@@ -744,8 +744,8 @@ witness_checkorder(struct lock_object *l
        struct witness *w, *w1;
        int i, j, s;
 
-       if (witness_cold || witness_watch < 1 || lock->lo_witness == NULL ||
-           panicstr != NULL)
+       if (witness_cold || witness_watch < 1 || panicstr != NULL ||
+           (lock->lo_flags & LO_WITNESS) == 0)
                return;
 
        w = lock->lo_witness;
@@ -1078,8 +1078,8 @@ witness_lock(struct lock_object *lock, i
        struct witness *w;
        int s;
 
-       if (witness_cold || witness_watch == -1 || lock->lo_witness == NULL ||
-           panicstr != NULL)
+       if (witness_cold || witness_watch == -1 || panicstr != NULL ||
+           (lock->lo_flags & LO_WITNESS) == 0)
                return;
 
        w = lock->lo_witness;
@@ -2004,6 +2004,42 @@ witness_assert(const struct lock_object 
 
        }
 #endif /* INVARIANT_SUPPORT */
+}
+
+int
+witness_status(struct lock_object *lock)
+{
+       struct lock_instance *instance;
+       struct lock_class *class;
+       int status = 0;
+
+       if (witness_cold || witness_watch < 1 || panicstr != NULL ||
+           (lock->lo_flags & LO_WITNESS) == 0)
+               return -1;
+
+       class = LOCK_CLASS(lock);
+       if ((class->lc_flags & LC_SLEEPLOCK) != 0)
+               instance = find_instance(curproc->p_sleeplocks, lock);
+       else if ((class->lc_flags & LC_SPINLOCK) != 0)
+               instance = find_instance(
+                   witness_cpu[cpu_number()].wc_spinlocks, lock);
+       else
+               panic("lock (%s) %s is not sleep or spin!",
+                   class->lc_name, lock->lo_name);
+
+       if (instance != NULL) {
+               status |= LA_LOCKED;
+               if (instance->li_flags & LI_EXCLUSIVE)
+                       status |= LA_XLOCKED;
+               else
+                       status |= LA_SLOCKED;
+               if (instance->li_flags & LI_RECURSEMASK)
+                       status |= LA_RECURSED;
+               else
+                       status |= LA_NOTRECURSED;
+       }
+
+       return (status);
 }
 
 static void
Index: sys/sys/rwlock.h
===================================================================
RCS file: src/sys/sys/rwlock.h,v
retrieving revision 1.22
diff -u -p -r1.22 rwlock.h
--- sys/sys/rwlock.h    12 Aug 2017 23:27:44 -0000      1.22
+++ sys/sys/rwlock.h    13 Nov 2017 17:05:51 -0000
@@ -170,6 +170,7 @@ void        rw_assert_unlocked(struct rwlock *)
 int    _rw_enter(struct rwlock *, int LOCK_FL_VARS);
 void   _rw_exit(struct rwlock * LOCK_FL_VARS);
 int    rw_status(struct rwlock *);
+int    rw_status_curproc(struct rwlock *);
 
 #define rw_enter(rwl, flags)   _rw_enter(rwl, flags LOCK_FILE_LINE)
 #define rw_exit(rwl)           _rw_exit(rwl LOCK_FILE_LINE)
Index: sys/sys/systm.h
===================================================================
RCS file: src/sys/sys/systm.h,v
retrieving revision 1.135
diff -u -p -r1.135 systm.h
--- sys/sys/systm.h     13 Nov 2017 14:41:46 -0000      1.135
+++ sys/sys/systm.h     13 Nov 2017 17:05:52 -0000
@@ -323,7 +323,7 @@ do {                                                        
                \
 
 #define        NET_ASSERT_LOCKED()                                             
\
 do {                                                                   \
-       int _s = rw_status(&netlock);                                   \
+       int _s = rw_status_curproc(&netlock);                           \
        if ((splassert_ctl > 0) && (_s != RW_WRITE && _s != RW_READ))   \
                splassert_fail(RW_READ, _s, __func__);                  \
 } while (0)
Index: sys/sys/witness.h
===================================================================
RCS file: src/sys/sys/witness.h,v
retrieving revision 1.1
diff -u -p -r1.1 witness.h
--- sys/sys/witness.h   20 Apr 2017 12:59:36 -0000      1.1
+++ sys/sys/witness.h   13 Nov 2017 17:05:52 -0000
@@ -88,6 +88,7 @@ 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 *);
+int    witness_status(struct lock_object *);
 void   witness_thread_exit(struct proc *);
 
 #ifdef WITNESS

Reply via email to