LCOV - code coverage report
Current view: top level - kern - kern_lock.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 17 108 15.7 %
Date: 2018-10-19 03:25:38 Functions: 0 16 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: kern_lock.c,v 1.66 2018/06/15 13:59:53 visa Exp $     */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2017 Visa Hankala
       5             :  * Copyright (c) 2014 David Gwynne <dlg@openbsd.org>
       6             :  * Copyright (c) 2004 Artur Grabowski <art@openbsd.org>
       7             :  *
       8             :  * Permission to use, copy, modify, and distribute this software for any
       9             :  * purpose with or without fee is hereby granted, provided that the above
      10             :  * copyright notice and this permission notice appear in all copies.
      11             :  *
      12             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      13             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      14             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      15             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      16             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      17             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      18             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      19             :  */
      20             : 
      21             : #include <sys/param.h>
      22             : #include <sys/systm.h>
      23             : #include <sys/sched.h>
      24             : #include <sys/atomic.h>
      25             : #include <sys/witness.h>
      26             : #include <sys/mutex.h>
      27             : 
      28             : #include <ddb/db_output.h>
      29             : 
      30             : #ifdef MP_LOCKDEBUG
      31             : #ifndef DDB
      32             : #error "MP_LOCKDEBUG requires DDB"
      33             : #endif
      34             : 
      35             : /* CPU-dependent timing, this needs to be settable from ddb. */
      36             : int __mp_lock_spinout = 200000000;
      37             : #endif /* MP_LOCKDEBUG */
      38             : 
      39             : #ifdef MULTIPROCESSOR
      40             : 
      41             : #include <sys/mplock.h>
      42             : struct __mp_lock kernel_lock;
      43             : 
      44             : /*
      45             :  * Functions for manipulating the kernel_lock.  We put them here
      46             :  * so that they show up in profiles.
      47             :  */
      48             : 
      49             : void
      50           0 : _kernel_lock_init(void)
      51             : {
      52           0 :         __mp_lock_init(&kernel_lock);
      53           0 : }
      54             : 
      55             : /*
      56             :  * Acquire/release the kernel lock.  Intended for use in the scheduler
      57             :  * and the lower half of the kernel.
      58             :  */
      59             : 
      60             : void
      61           0 : _kernel_lock(const char *file, int line)
      62             : {
      63         199 :         SCHED_ASSERT_UNLOCKED();
      64             : #ifdef WITNESS
      65             :         ___mp_lock(&kernel_lock, file, line);
      66             : #else
      67           0 :         __mp_lock(&kernel_lock);
      68             : #endif
      69           0 : }
      70             : 
      71             : void
      72           0 : _kernel_unlock(void)
      73             : {
      74           0 :         __mp_unlock(&kernel_lock);
      75           0 : }
      76             : 
      77             : int
      78           0 : _kernel_lock_held(void)
      79             : {
      80           0 :         if (panicstr || db_active)
      81           0 :                 return 1;
      82           0 :         return (__mp_lock_held(&kernel_lock, curcpu()));
      83           0 : }
      84             : 
      85             : #ifdef __USE_MI_MPLOCK
      86             : 
      87             : /* Ticket lock implementation */
      88             : 
      89             : #include <machine/cpu.h>
      90             : 
      91             : void
      92           0 : ___mp_lock_init(struct __mp_lock *mpl, const struct lock_type *type)
      93             : {
      94           0 :         memset(mpl->mpl_cpus, 0, sizeof(mpl->mpl_cpus));
      95           0 :         mpl->mpl_users = 0;
      96           0 :         mpl->mpl_ticket = 1;
      97             : 
      98             : #ifdef WITNESS
      99             :         mpl->mpl_lock_obj.lo_name = type->lt_name;
     100             :         mpl->mpl_lock_obj.lo_type = type;
     101             :         if (mpl == &kernel_lock)
     102             :                 mpl->mpl_lock_obj.lo_flags = LO_WITNESS | LO_INITIALIZED |
     103             :                     LO_SLEEPABLE | (LO_CLASS_KERNEL_LOCK << LO_CLASSSHIFT);
     104             :         else if (mpl == &sched_lock)
     105             :                 mpl->mpl_lock_obj.lo_flags = LO_WITNESS | LO_INITIALIZED |
     106             :                     LO_RECURSABLE | (LO_CLASS_SCHED_LOCK << LO_CLASSSHIFT);
     107             :         WITNESS_INIT(&mpl->mpl_lock_obj, type);
     108             : #endif
     109           0 : }
     110             : 
     111             : static __inline void
     112           0 : __mp_lock_spin(struct __mp_lock *mpl, u_int me)
     113             : {
     114           0 :         struct schedstate_percpu *spc = &curcpu()->ci_schedstate;
     115             : #ifdef MP_LOCKDEBUG
     116             :         int nticks = __mp_lock_spinout;
     117             : #endif
     118             : 
     119           0 :         spc->spc_spinning++;
     120         197 :         while (mpl->mpl_ticket != me) {
     121           0 :                 CPU_BUSY_CYCLE();
     122             : 
     123             : #ifdef MP_LOCKDEBUG
     124             :                 if (--nticks <= 0) {
     125             :                         db_printf("%s: %p lock spun out", __func__, mpl);
     126             :                         db_enter();
     127             :                         nticks = __mp_lock_spinout;
     128             :                 }
     129             : #endif
     130             :         }
     131           0 :         spc->spc_spinning--;
     132           0 : }
     133             : 
     134             : void
     135           0 : ___mp_lock(struct __mp_lock *mpl LOCK_FL_VARS)
     136             : {
     137         197 :         struct __mp_lock_cpu *cpu = &mpl->mpl_cpus[cpu_number()];
     138             :         unsigned long s;
     139             : 
     140             : #ifdef WITNESS
     141             :         if (!__mp_lock_held(mpl, curcpu()))
     142             :                 WITNESS_CHECKORDER(&mpl->mpl_lock_obj,
     143             :                     LOP_EXCLUSIVE | LOP_NEWORDER, file, line, NULL);
     144             : #endif
     145             : 
     146           0 :         s = intr_disable();
     147           0 :         if (cpu->mplc_depth++ == 0)
     148           0 :                 cpu->mplc_ticket = atomic_inc_int_nv(&mpl->mpl_users);
     149           0 :         intr_restore(s);
     150             : 
     151         118 :         __mp_lock_spin(mpl, cpu->mplc_ticket);
     152           0 :         membar_enter_after_atomic();
     153             : 
     154             :         WITNESS_LOCK(&mpl->mpl_lock_obj, LOP_EXCLUSIVE, file, line);
     155           0 : }
     156             : 
     157             : void
     158           0 : ___mp_unlock(struct __mp_lock *mpl LOCK_FL_VARS)
     159             : {
     160         180 :         struct __mp_lock_cpu *cpu = &mpl->mpl_cpus[cpu_number()];
     161             :         unsigned long s;
     162             : 
     163             : #ifdef MP_LOCKDEBUG
     164             :         if (!__mp_lock_held(mpl, curcpu())) {
     165             :                 db_printf("__mp_unlock(%p): not held lock\n", mpl);
     166             :                 db_enter();
     167             :         }
     168             : #endif
     169             : 
     170             :         WITNESS_UNLOCK(&mpl->mpl_lock_obj, LOP_EXCLUSIVE, file, line);
     171             : 
     172           0 :         s = intr_disable();
     173          90 :         if (--cpu->mplc_depth == 0) {
     174           0 :                 membar_exit();
     175          90 :                 mpl->mpl_ticket++;
     176           0 :         }
     177           0 :         intr_restore(s);
     178           0 : }
     179             : 
     180             : int
     181           0 : ___mp_release_all(struct __mp_lock *mpl LOCK_FL_VARS)
     182             : {
     183           0 :         struct __mp_lock_cpu *cpu = &mpl->mpl_cpus[cpu_number()];
     184             :         unsigned long s;
     185             :         int rv;
     186             : #ifdef WITNESS
     187             :         int i;
     188             : #endif
     189             : 
     190           0 :         s = intr_disable();
     191           0 :         rv = cpu->mplc_depth;
     192             : #ifdef WITNESS
     193             :         for (i = 0; i < rv; i++)
     194             :                 WITNESS_UNLOCK(&mpl->mpl_lock_obj, LOP_EXCLUSIVE, file, line);
     195             : #endif
     196           0 :         cpu->mplc_depth = 0;
     197           0 :         membar_exit();
     198           0 :         mpl->mpl_ticket++;
     199           0 :         intr_restore(s);
     200             : 
     201           0 :         return (rv);
     202             : }
     203             : 
     204             : int
     205           0 : ___mp_release_all_but_one(struct __mp_lock *mpl LOCK_FL_VARS)
     206             : {
     207           0 :         struct __mp_lock_cpu *cpu = &mpl->mpl_cpus[cpu_number()];
     208           0 :         int rv = cpu->mplc_depth - 1;
     209             : #ifdef WITNESS
     210             :         int i;
     211             : 
     212             :         for (i = 0; i < rv; i++)
     213             :                 WITNESS_UNLOCK(&mpl->mpl_lock_obj, LOP_EXCLUSIVE, file, line);
     214             : #endif
     215             : 
     216             : #ifdef MP_LOCKDEBUG
     217             :         if (!__mp_lock_held(mpl, curcpu())) {
     218             :                 db_printf("__mp_release_all_but_one(%p): not held lock\n", mpl);
     219             :                 db_enter();
     220             :         }
     221             : #endif
     222             : 
     223           0 :         cpu->mplc_depth = 1;
     224             : 
     225           0 :         return (rv);
     226             : }
     227             : 
     228             : void
     229           0 : ___mp_acquire_count(struct __mp_lock *mpl, int count LOCK_FL_VARS)
     230             : {
     231           0 :         while (count--)
     232           0 :                 ___mp_lock(mpl LOCK_FL_ARGS);
     233           0 : }
     234             : 
     235             : int
     236           0 : __mp_lock_held(struct __mp_lock *mpl, struct cpu_info *ci)
     237             : {
     238         198 :         struct __mp_lock_cpu *cpu = &mpl->mpl_cpus[CPU_INFO_UNIT(ci)];
     239             : 
     240           0 :         return (cpu->mplc_ticket == mpl->mpl_ticket && cpu->mplc_depth > 0);
     241             : }
     242             : 
     243             : #endif /* __USE_MI_MPLOCK */
     244             : 
     245             : #endif /* MULTIPROCESSOR */
     246             : 
     247             : 
     248             : #ifdef __USE_MI_MUTEX
     249             : void
     250           0 : __mtx_init(struct mutex *mtx, int wantipl)
     251             : {
     252           0 :         mtx->mtx_owner = NULL;
     253           0 :         mtx->mtx_wantipl = wantipl;
     254           0 :         mtx->mtx_oldipl = IPL_NONE;
     255           0 : }
     256             : 
     257             : #ifdef MULTIPROCESSOR
     258             : void
     259           0 : __mtx_enter(struct mutex *mtx)
     260             : {
     261         770 :         struct schedstate_percpu *spc = &curcpu()->ci_schedstate;
     262             : #ifdef MP_LOCKDEBUG
     263             :         int nticks = __mp_lock_spinout;
     264             : #endif
     265             : 
     266           0 :         spc->spc_spinning++;
     267         765 :         while (__mtx_enter_try(mtx) == 0) {
     268           0 :                 CPU_BUSY_CYCLE();
     269             : 
     270             : #ifdef MP_LOCKDEBUG
     271             :                 if (--nticks == 0) {
     272             :                         db_printf("%s: %p lock spun out", __func__, mtx);
     273             :                         db_enter();
     274             :                         nticks = __mp_lock_spinout;
     275             :                 }
     276             : #endif
     277             :         }
     278           0 :         spc->spc_spinning--;
     279           0 : }
     280             : 
     281             : int
     282           0 : __mtx_enter_try(struct mutex *mtx)
     283             : {
     284         767 :         struct cpu_info *owner, *ci = curcpu();
     285             :         int s;
     286             : 
     287             :         /* Avoid deadlocks after panic or in DDB */
     288           0 :         if (panicstr || db_active)
     289           0 :                 return (1);
     290             : 
     291           0 :         if (mtx->mtx_wantipl != IPL_NONE)
     292         706 :                 s = splraise(mtx->mtx_wantipl);
     293             : 
     294           0 :         owner = atomic_cas_ptr(&mtx->mtx_owner, NULL, ci);
     295             : #ifdef DIAGNOSTIC
     296           0 :         if (__predict_false(owner == ci))
     297           0 :                 panic("mtx %p: locking against myself", mtx);
     298             : #endif
     299           0 :         if (owner == NULL) {
     300           0 :                 membar_enter_after_atomic();
     301           0 :                 if (mtx->mtx_wantipl != IPL_NONE)
     302         705 :                         mtx->mtx_oldipl = s;
     303             : #ifdef DIAGNOSTIC
     304          60 :                 ci->ci_mutex_level++;
     305             : #endif
     306           0 :                 return (1);
     307             :         }
     308             : 
     309           0 :         if (mtx->mtx_wantipl != IPL_NONE)
     310           0 :                 splx(s);
     311             : 
     312           0 :         return (0);
     313           0 : }
     314             : #else
     315             : void
     316             : __mtx_enter(struct mutex *mtx)
     317             : {
     318             :         struct cpu_info *ci = curcpu();
     319             : 
     320             :         /* Avoid deadlocks after panic or in DDB */
     321             :         if (panicstr || db_active)
     322             :                 return;
     323             : 
     324             : #ifdef DIAGNOSTIC
     325             :         if (__predict_false(mtx->mtx_owner == ci))
     326             :                 panic("mtx %p: locking against myself", mtx);
     327             : #endif
     328             : 
     329             :         if (mtx->mtx_wantipl != IPL_NONE)
     330             :                 mtx->mtx_oldipl = splraise(mtx->mtx_wantipl);
     331             : 
     332             :         mtx->mtx_owner = ci;
     333             : 
     334             : #ifdef DIAGNOSTIC
     335             :         ci->ci_mutex_level++;
     336             : #endif
     337             : }
     338             : 
     339             : int
     340             : __mtx_enter_try(struct mutex *mtx)
     341             : {
     342             :         __mtx_enter(mtx);
     343             :         return (1);
     344             : }
     345             : #endif
     346             : 
     347             : void
     348           0 : __mtx_leave(struct mutex *mtx)
     349             : {
     350             :         int s;
     351             : 
     352             :         /* Avoid deadlocks after panic or in DDB */
     353         753 :         if (panicstr || db_active)
     354           0 :                 return;
     355             : 
     356           0 :         MUTEX_ASSERT_LOCKED(mtx);
     357             : 
     358             : #ifdef DIAGNOSTIC
     359           0 :         curcpu()->ci_mutex_level--;
     360             : #endif
     361             : 
     362           0 :         s = mtx->mtx_oldipl;
     363             : #ifdef MULTIPROCESSOR
     364           0 :         membar_exit_before_atomic();
     365             : #endif
     366           0 :         mtx->mtx_owner = NULL;
     367           0 :         if (mtx->mtx_wantipl != IPL_NONE)
     368         693 :                 splx(s);
     369          60 : }
     370             : #endif /* __USE_MI_MUTEX */
     371             : 
     372             : #ifdef WITNESS
     373             : void
     374             : _mtx_init_flags(struct mutex *m, int ipl, const char *name, int flags,
     375             :     const struct lock_type *type)
     376             : {
     377             :         struct lock_object *lo = MUTEX_LOCK_OBJECT(m);
     378             : 
     379             :         lo->lo_flags = MTX_LO_FLAGS(flags);
     380             :         if (name != NULL)
     381             :                 lo->lo_name = name;
     382             :         else
     383             :                 lo->lo_name = type->lt_name;
     384             :         WITNESS_INIT(lo, type);
     385             : 
     386             :         _mtx_init(m, ipl);
     387             : }
     388             : 
     389             : void
     390             : _mtx_enter(struct mutex *m, const char *file, int line)
     391             : {
     392             :         struct lock_object *lo = MUTEX_LOCK_OBJECT(m);
     393             : 
     394             :         WITNESS_CHECKORDER(lo, LOP_EXCLUSIVE | LOP_NEWORDER, file, line, NULL);
     395             :         __mtx_enter(m);
     396             :         WITNESS_LOCK(lo, LOP_EXCLUSIVE, file, line);
     397             : }
     398             : 
     399             : int
     400             : _mtx_enter_try(struct mutex *m, const char *file, int line)
     401             : {
     402             :         struct lock_object *lo = MUTEX_LOCK_OBJECT(m);
     403             : 
     404             :         if (__mtx_enter_try(m)) {
     405             :                 WITNESS_LOCK(lo, LOP_EXCLUSIVE, file, line);
     406             :                 return 1;
     407             :         }
     408             :         return 0;
     409             : }
     410             : 
     411             : void
     412             : _mtx_leave(struct mutex *m, const char *file, int line)
     413             : {
     414             :         struct lock_object *lo = MUTEX_LOCK_OBJECT(m);
     415             : 
     416             :         WITNESS_UNLOCK(lo, LOP_EXCLUSIVE, file, line);
     417             :         __mtx_leave(m);
     418             : }
     419             : #endif /* WITNESS */

Generated by: LCOV version 1.13