LCOV - code coverage report
Current view: top level - dev/pci/drm - linux_ww_mutex.h (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 74 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 13 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Michael Neumann <mneumann@ntecs.de>
       3             :  * All rights reserved.
       4             :  *
       5             :  * Redistribution and use in source and binary forms, with or without
       6             :  * modification, are permitted provided that the following conditions
       7             :  * are met:
       8             :  * 1. Redistributions of source code must retain the above copyright
       9             :  *    notice unmodified, this list of conditions, and the following
      10             :  *    disclaimer.
      11             :  * 2. Redistributions in binary form must reproduce the above copyright
      12             :  *    notice, this list of conditions and the following disclaimer in the
      13             :  *    documentation and/or other materials provided with the distribution.
      14             :  *
      15             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      16             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      17             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      18             :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      19             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      20             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      21             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      22             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      23             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      24             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      25             :  */
      26             : 
      27             : #ifndef _LINUX_WW_MUTEX_H_
      28             : #define _LINUX_WW_MUTEX_H_
      29             : 
      30             : /*
      31             :  * A basic, unoptimized implementation of wound/wait mutexes for DragonFly
      32             :  * modelled after the Linux API [1].
      33             :  *
      34             :  * [1]: http://lxr.free-electrons.com/source/include/linux/ww_mutex.h
      35             :  */
      36             : 
      37             : #include <sys/types.h>
      38             : #include <sys/systm.h>
      39             : #include <sys/mutex.h>
      40             : 
      41             : struct ww_class {
      42             :         volatile u_long                 stamp;
      43             :         const char                      *name;
      44             : };
      45             : 
      46             : struct ww_acquire_ctx {
      47             :         u_long                          stamp;
      48             :         struct ww_class                 *ww_class;
      49             : };
      50             : 
      51             : struct ww_mutex {
      52             :         struct mutex                    lock;
      53             :         volatile int                    acquired;
      54             :         volatile struct ww_acquire_ctx  *ctx;
      55             :         volatile struct proc            *owner;
      56             : };
      57             : 
      58             : #define DEFINE_WW_CLASS(classname)      \
      59             :         struct ww_class classname = {   \
      60             :                 .stamp = 0,             \
      61             :                 .name = #classname      \
      62             :         }
      63             : 
      64             : static inline void
      65           0 : ww_acquire_init(struct ww_acquire_ctx *ctx, struct ww_class *ww_class) {
      66           0 :         ctx->stamp = __sync_fetch_and_add(&ww_class->stamp, 1);
      67           0 :         ctx->ww_class = ww_class;
      68           0 : }
      69             : 
      70             : static inline void
      71           0 : ww_acquire_done(__unused struct ww_acquire_ctx *ctx) {
      72           0 : }
      73             : 
      74             : static inline void
      75           0 : ww_acquire_fini(__unused struct ww_acquire_ctx *ctx) {
      76           0 : }
      77             : 
      78             : static inline void
      79           0 : ww_mutex_init(struct ww_mutex *lock, struct ww_class *ww_class) {
      80           0 :         mtx_init(&lock->lock, IPL_NONE);
      81           0 :         lock->acquired = 0;
      82           0 :         lock->ctx = NULL;
      83           0 :         lock->owner = NULL;
      84           0 : }
      85             : 
      86             : static inline bool
      87           0 : ww_mutex_is_locked(struct ww_mutex *lock) {
      88             :         bool res = false;
      89           0 :         mtx_enter(&lock->lock);
      90           0 :         if (lock->acquired > 0) res = true;
      91           0 :         mtx_leave(&lock->lock);
      92           0 :         return res;
      93             : }
      94             : 
      95             : /*
      96             :  * Return 1 if lock could be acquired, else 0 (contended).
      97             :  */
      98             : static inline int
      99           0 : ww_mutex_trylock(struct ww_mutex *lock) {
     100             :         int res = 0;
     101             : 
     102           0 :         mtx_enter(&lock->lock);
     103             :         /*
     104             :          * In case no one holds the ww_mutex yet, we acquire it.
     105             :          */
     106           0 :         if (lock->acquired == 0) {
     107           0 :                 KASSERT(lock->ctx == NULL);
     108           0 :                 lock->acquired = 1;
     109           0 :                 lock->owner = curproc;
     110             :                 res = 1;
     111           0 :         }
     112           0 :         mtx_leave(&lock->lock);
     113           0 :         return res;
     114             : }
     115             : 
     116             : /*
     117             :  * When `slow` is `true`, it will always block if the ww_mutex is contended.
     118             :  * It is assumed that the called will not hold any (ww_mutex) resources when
     119             :  * calling the slow path as this could lead to deadlocks.
     120             :  *
     121             :  * When `intr` is `true`, the ssleep will be interruptable.
     122             :  */
     123             : static inline int
     124           0 : __ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx, bool slow, bool intr) {
     125             :         int err;
     126             : 
     127           0 :         mtx_enter(&lock->lock);
     128           0 :         for (;;) {
     129             :                 /*
     130             :                  * In case no one holds the ww_mutex yet, we acquire it.
     131             :                  */
     132           0 :                 if (lock->acquired == 0) {
     133           0 :                         KASSERT(lock->ctx == NULL);
     134           0 :                         lock->acquired = 1;
     135           0 :                         lock->ctx = ctx;
     136           0 :                         lock->owner = curproc;
     137             :                         err = 0;
     138           0 :                         break;
     139             :                 }
     140             :                 /*
     141             :                  * In case we already hold the return -EALREADY.
     142             :                  */
     143           0 :                 else if (lock->owner == curproc) {
     144             :                         err = -EALREADY;
     145           0 :                         break;
     146             :                 }
     147             :                 /*
     148             :                  * This is the contention case where the ww_mutex is
     149             :                  * already held by another context.
     150             :                  */
     151             :                 else {
     152             :                         /*
     153             :                          * Three cases:
     154             :                          *
     155             :                          * - We are in the slow-path (first lock to obtain).
     156             :                          *
     157             :                          * - No context was specified. We assume a single
     158             :                          *   resouce, so there is no danger of a deadlock.
     159             :                          *
     160             :                          * - An `older` process (`ctx`) tries to acquire a
     161             :                          *   lock already held by a `younger` process.
     162             :                          *   We put the `older` process to sleep until
     163             :                          *   the `younger` process gives up all it's
     164             :                          *   resources.
     165             :                          */
     166           0 :                         if (slow || ctx == NULL ||
     167           0 :                             (lock->ctx && ctx->stamp < lock->ctx->stamp)) {
     168           0 :                                 int s = msleep(lock, &lock->lock,
     169           0 :                                                intr ? PCATCH : 0,
     170           0 :                                                ctx ? ctx->ww_class->name : "ww_mutex_lock", 0);
     171           0 :                                 if (intr && (s == EINTR || s == ERESTART)) {
     172             :                                         // XXX: Should we handle ERESTART?
     173             :                                         err = -EINTR;
     174           0 :                                         break;
     175             :                                 }
     176           0 :                         }
     177             :                         /*
     178             :                          * If a `younger` process tries to acquire a lock
     179             :                          * already held by an `older` process, we `wound` it,
     180             :                          * i.e. we return -EDEADLK because there is a potential
     181             :                          * risk for a deadlock. The `younger` process then
     182             :                          * should give up all it's resources and try again to
     183             :                          * acquire the lock in question, this time in a
     184             :                          * blocking manner.
     185             :                          */
     186             :                         else {
     187             :                                 err = -EDEADLK;
     188           0 :                                 break;
     189             :                         }
     190             :                 }
     191             : 
     192             :         } /* for */
     193           0 :         mtx_leave(&lock->lock);
     194           0 :         return err;
     195             : }
     196             : 
     197             : static inline int
     198           0 : ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) {
     199           0 :         return __ww_mutex_lock(lock, ctx, false, false);
     200             : }
     201             :         
     202             : static inline void
     203           0 : ww_mutex_lock_slow(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) {
     204           0 :         (void)__ww_mutex_lock(lock, ctx, true, false);
     205           0 : }
     206             : 
     207             : static inline int
     208           0 : ww_mutex_lock_interruptible(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) {
     209           0 :         return __ww_mutex_lock(lock, ctx, false, true);
     210             : }
     211             :         
     212             : static inline int __must_check
     213           0 : ww_mutex_lock_slow_interruptible(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) {
     214           0 :         return __ww_mutex_lock(lock, ctx, true, true);
     215             : }
     216             : 
     217             : static inline void
     218           0 : ww_mutex_unlock(struct ww_mutex *lock) {
     219           0 :         mtx_enter(&lock->lock);
     220           0 :         KASSERT(lock->owner == curproc);
     221           0 :         KASSERT(lock->acquired == 1);
     222             : 
     223           0 :         lock->acquired = 0;
     224           0 :         lock->ctx = NULL;
     225           0 :         lock->owner = NULL;
     226           0 :         mtx_leave(&lock->lock);
     227           0 :         wakeup(lock);
     228           0 : }
     229             : 
     230             : static inline void
     231           0 : ww_mutex_destroy(struct ww_mutex *lock) {
     232           0 :         KASSERT(lock->acquired == 0);
     233           0 :         KASSERT(lock->ctx == NULL);
     234           0 :         KASSERT(lock->owner == NULL);
     235           0 : }
     236             : 
     237             : #endif  /* _LINUX_WW_MUTEX_H_ */

Generated by: LCOV version 1.13