]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/i386/locks_i386.c
xnu-3789.51.2.tar.gz
[apple/xnu.git] / osfmk / i386 / locks_i386.c
index 130ba126a4028aeb0516ae451af389bf87b50bb4..9b4639c24da971cdb307344ed94604be70f4dba9 100644 (file)
@@ -126,6 +126,15 @@ decl_simple_lock_data(extern , panic_lock)
 #endif /* USLOCK_DEBUG */
 
 extern unsigned int not_in_kdp;
+extern void kdp_lck_mtx_find_owner(
+       struct waitq *          waitq,
+       event64_t               event,
+       thread_waitinfo_t *     waitinfo);
+
+extern void kdp_rwlck_find_owner(
+       struct waitq *          waitq,
+       event64_t               event,
+       thread_waitinfo_t *     waitinfo);
 
 /*
  *     We often want to know the addresses of the callers
@@ -287,7 +296,47 @@ boolean_t
 lck_spin_try_lock(
        lck_spin_t      *lck)
 {
-       return((boolean_t)usimple_lock_try((usimple_lock_t) lck));
+       boolean_t lrval = (boolean_t)usimple_lock_try((usimple_lock_t) lck);
+#if    DEVELOPMENT || DEBUG
+       if (lrval) {
+               pltrace(FALSE);
+       }
+#endif
+       return(lrval);
+}
+
+/*
+ *     Routine:        lck_spin_assert
+ */
+void
+lck_spin_assert(lck_spin_t *lock, unsigned int type)
+{
+       thread_t thread, holder;
+       uintptr_t state;
+
+       if (__improbable(type != LCK_ASSERT_OWNED && type != LCK_ASSERT_NOTOWNED)) {
+               panic("lck_spin_assert(): invalid arg (%u)", type);
+       }
+
+       state = lock->interlock;
+       holder = (thread_t)state;
+       thread = current_thread();
+       if (type == LCK_ASSERT_OWNED) {
+               if (__improbable(holder == THREAD_NULL)) {
+                       panic("Lock not owned %p = %lx", lock, state);
+               }
+               if (__improbable(holder != thread)) {
+                       panic("Lock not owned by current thread %p = %lx", lock, state);
+               }
+       } else if (type == LCK_ASSERT_NOTOWNED) {
+               if (__improbable(holder != THREAD_NULL)) {
+                       if (holder == thread) {
+                               panic("Lock owned by current thread %p = %lx", lock, state);
+                       } else {
+                               panic("Lock %p owned by thread %p", lock, holder);
+                       }
+               }
+       }
 }
 
 /*
@@ -378,6 +427,10 @@ usimple_lock(
                        panic("Spinlock acquisition timed out: lock=%p, lock owner thread=0x%lx, current_thread: %p, lock owner active on CPU 0x%x, current owner: 0x%lx", l, lowner,  current_thread(), lock_cpu, (uintptr_t)l->interlock.lock_data);
                }
        }
+#if DEVELOPMENT || DEBUG
+               pltrace(FALSE);
+#endif
+
        USLDBG(usld_lock_post(l, pc));
 #else
        simple_lock((simple_lock_t)l);
@@ -401,6 +454,9 @@ usimple_unlock(
 
        OBTAIN_PC(pc);
        USLDBG(usld_unlock(l, pc));
+#if DEVELOPMENT || DEBUG
+               pltrace(TRUE);
+#endif
        hw_lock_unlock(&l->interlock);
 #else
        simple_unlock_rwmb((simple_lock_t)l);
@@ -431,7 +487,10 @@ usimple_lock_try(
        OBTAIN_PC(pc);
        USLDBG(usld_lock_try_pre(l, pc));
        if ((success = hw_lock_try(&l->interlock))) {
-               USLDBG(usld_lock_try_post(l, pc));
+#if DEVELOPMENT || DEBUG
+               pltrace(FALSE);
+#endif
+       USLDBG(usld_lock_try_post(l, pc));
        }
        return success;
 #else
@@ -439,6 +498,22 @@ usimple_lock_try(
 #endif
 }
 
+/*
+ * Acquire a usimple_lock while polling for pending TLB flushes
+ * and spinning on a lock.
+ *
+ */
+void
+usimple_lock_try_lock_loop(usimple_lock_t l)
+{
+       boolean_t istate = ml_get_interrupts_enabled();
+       while (!simple_lock_try((l))) {
+               if (!istate)
+                       handle_pending_TLB_flushes();
+               cpu_pause();
+       }
+}
+
 #if    USLOCK_DEBUG
 /*
  *     States of a usimple_lock.  The default when initializing
@@ -548,7 +623,7 @@ usld_lock_post(
        usimple_lock_t  l,
        pc_t            pc)
 {
-       register int    mycpu;
+       int     mycpu;
        char    caller[] = "successful usimple_lock";
 
 
@@ -585,7 +660,7 @@ usld_unlock(
        usimple_lock_t  l,
        pc_t            pc)
 {
-       register int    mycpu;
+       int     mycpu;
        char    caller[] = "usimple_unlock";
 
 
@@ -650,7 +725,7 @@ usld_lock_try_post(
        usimple_lock_t  l,
        pc_t            pc)
 {
-       register int    mycpu;
+       int     mycpu;
        char    caller[] = "successful usimple_lock_try";
 
        if (!usld_lock_common_checks(l, caller))
@@ -782,12 +857,6 @@ lck_rw_destroy(
 
 #define DECREMENTER_TIMEOUT 1000000
 
-#define RW_LOCK_READER_EVENT(x)                \
-               ((event_t) (((unsigned char*) (x)) + (offsetof(lck_rw_t, lck_rw_tag))))
-
-#define RW_LOCK_WRITER_EVENT(x)                \
-               ((event_t) (((unsigned char*) (x)) + (offsetof(lck_rw_t, lck_rw_pad8))))
-
 /*
  * We disable interrupts while holding the RW interlock to prevent an
  * interrupt from exacerbating hold time.
@@ -925,6 +994,7 @@ lck_rw_lock_exclusive_gen(
 
                                lck->lck_w_waiting = TRUE;
 
+                               thread_set_pending_block_hint(current_thread(), kThreadWaitKernelRWLockWrite);
                                res = assert_wait(RW_LOCK_WRITER_EVENT(lck), THREAD_UNINT);
                                lck_interlock_unlock(lck, istate);
 
@@ -1003,6 +1073,7 @@ lck_rw_lock_exclusive_gen(
 
                                lck->lck_w_waiting = TRUE;
 
+                               thread_set_pending_block_hint(current_thread(), kThreadWaitKernelRWLockWrite);
                                res = assert_wait(RW_LOCK_WRITER_EVENT(lck), THREAD_UNINT);
                                lck_interlock_unlock(lck, istate);
 
@@ -1151,7 +1222,7 @@ lck_rw_unlock_shared(
        ret = lck_rw_done(lck);
 
        if (ret != LCK_RW_TYPE_SHARED)
-               panic("lck_rw_unlock(): lock held in mode: %d\n", ret);
+               panic("lck_rw_unlock_shared(): lock %p held in mode: %d\n", lck, ret);
 }
 
 
@@ -1264,6 +1335,7 @@ lck_rw_lock_shared_gen(
 
                                lck->lck_r_waiting = TRUE;
 
+                               thread_set_pending_block_hint(current_thread(), kThreadWaitKernelRWLockRead);
                                res = assert_wait(RW_LOCK_READER_EVENT(lck), THREAD_UNINT);
                                lck_interlock_unlock(lck, istate);
 
@@ -1423,6 +1495,7 @@ lck_rw_lock_shared_to_exclusive_success(
 
                                lck->lck_w_waiting = TRUE;
 
+                               thread_set_pending_block_hint(current_thread(), kThreadWaitKernelRWLockUpgrade);
                                res = assert_wait(RW_LOCK_WRITER_EVENT(lck), THREAD_UNINT);
                                lck_interlock_unlock(lck, istate);
 
@@ -1649,7 +1722,7 @@ lck_mtx_ext_init(
                lck->lck_mtx_attr |= LCK_MTX_ATTR_STAT;
 
        lck->lck_mtx.lck_mtx_is_ext = 1;
-       lck->lck_mtx.lck_mtx_sw.lck_mtxd.lck_mtxd_pad32 = 0xFFFFFFFF;
+       lck->lck_mtx.lck_mtx_pad32 = 0xFFFFFFFF;
 }
 
 /*
@@ -1679,7 +1752,7 @@ lck_mtx_init(
                lck->lck_mtx_owner = 0;
                lck->lck_mtx_state = 0;
        }
-       lck->lck_mtx_sw.lck_mtxd.lck_mtxd_pad32 = 0xFFFFFFFF;
+       lck->lck_mtx_pad32 = 0xFFFFFFFF;
        lck_grp_reference(grp);
        lck_grp_lckcnt_incr(grp, LCK_TYPE_MTX);
 }
@@ -1709,7 +1782,7 @@ lck_mtx_init_ext(
                lck->lck_mtx_owner = 0;
                lck->lck_mtx_state = 0;
        }
-       lck->lck_mtx_sw.lck_mtxd.lck_mtxd_pad32 = 0xFFFFFFFF;
+       lck->lck_mtx_pad32 = 0xFFFFFFFF;
 
        lck_grp_reference(grp);
        lck_grp_lckcnt_incr(grp, LCK_TYPE_MTX);
@@ -2083,6 +2156,7 @@ lck_mtx_lock_wait_x86 (
                thread_unlock(holder);
                splx(s);
        }
+       thread_set_pending_block_hint(self, kThreadWaitKernelMutex);
        assert_wait(LCK_MTX_EVENT(mutex), THREAD_UNINT);
 
        lck_mtx_ilk_unlock(mutex);
@@ -2121,10 +2195,38 @@ kdp_lck_mtx_lock_spin_is_acquired(lck_mtx_t     *lck)
                panic("panic: kdp_lck_mtx_lock_spin_is_acquired called outside of kernel debugger");
        }
 
-       if (lck->lck_mtx_sw.lck_mtxd.lck_mtxd_ilocked || lck->lck_mtx_sw.lck_mtxd.lck_mtxd_mlocked) {
+       if (lck->lck_mtx_ilocked || lck->lck_mtx_mlocked) {
                return TRUE;
        }
 
        return FALSE;
 }
 
+void
+kdp_lck_mtx_find_owner(__unused struct waitq * waitq, event64_t event, thread_waitinfo_t * waitinfo)
+{
+       lck_mtx_t * mutex = LCK_EVENT_TO_MUTEX(event);
+       waitinfo->context = VM_KERNEL_UNSLIDE_OR_PERM(mutex);
+       thread_t holder   = (thread_t)mutex->lck_mtx_owner;
+       waitinfo->owner   = thread_tid(holder);
+}
+
+void
+kdp_rwlck_find_owner(__unused struct waitq * waitq, event64_t event, thread_waitinfo_t * waitinfo)
+{
+       lck_rw_t *rwlck = NULL;
+       switch(waitinfo->wait_type) {
+               case kThreadWaitKernelRWLockRead:
+                       rwlck = READ_EVENT_TO_RWLOCK(event);
+                       break;
+               case kThreadWaitKernelRWLockWrite:
+               case kThreadWaitKernelRWLockUpgrade:
+                       rwlck = WRITE_EVENT_TO_RWLOCK(event);
+                       break;
+               default:
+                       panic("%s was called with an invalid blocking type", __FUNCTION__);
+                       break;
+       }
+       waitinfo->context = VM_KERNEL_UNSLIDE_OR_PERM(rwlck);
+       waitinfo->owner = 0;
+}