The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/drm2/ttm/ttm_lock.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /**************************************************************************
    2  *
    3  * Copyright (c) 2007-2009 VMware, Inc., Palo Alto, CA., USA
    4  * All Rights Reserved.
    5  *
    6  * Permission is hereby granted, free of charge, to any person obtaining a
    7  * copy of this software and associated documentation files (the
    8  * "Software"), to deal in the Software without restriction, including
    9  * without limitation the rights to use, copy, modify, merge, publish,
   10  * distribute, sub license, and/or sell copies of the Software, and to
   11  * permit persons to whom the Software is furnished to do so, subject to
   12  * the following conditions:
   13  *
   14  * The above copyright notice and this permission notice (including the
   15  * next paragraph) shall be included in all copies or substantial portions
   16  * of the Software.
   17  *
   18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   20  * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
   21  * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
   22  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
   23  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
   24  * USE OR OTHER DEALINGS IN THE SOFTWARE.
   25  *
   26  **************************************************************************/
   27 /*
   28  * Authors: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
   29  */
   30 /*
   31  * Copyright (c) 2013 The FreeBSD Foundation
   32  * All rights reserved.
   33  *
   34  * Portions of this software were developed by Konstantin Belousov
   35  * <kib@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __FBSDID("$FreeBSD$");
   40 
   41 #include <dev/drm2/ttm/ttm_lock.h>
   42 #include <dev/drm2/ttm/ttm_module.h>
   43 
   44 #define TTM_WRITE_LOCK_PENDING    (1 << 0)
   45 #define TTM_VT_LOCK_PENDING       (1 << 1)
   46 #define TTM_SUSPEND_LOCK_PENDING  (1 << 2)
   47 #define TTM_VT_LOCK               (1 << 3)
   48 #define TTM_SUSPEND_LOCK          (1 << 4)
   49 
   50 void ttm_lock_init(struct ttm_lock *lock)
   51 {
   52         mtx_init(&lock->lock, "ttmlk", NULL, MTX_DEF);
   53         lock->rw = 0;
   54         lock->flags = 0;
   55         lock->kill_takers = false;
   56         lock->signal = SIGKILL;
   57 }
   58 
   59 static void
   60 ttm_lock_send_sig(int signo)
   61 {
   62         struct proc *p;
   63 
   64         p = curproc;    /* XXXKIB curthread ? */
   65         PROC_LOCK(p);
   66         kern_psignal(p, signo);
   67         PROC_UNLOCK(p);
   68 }
   69 
   70 void ttm_read_unlock(struct ttm_lock *lock)
   71 {
   72         mtx_lock(&lock->lock);
   73         if (--lock->rw == 0)
   74                 wakeup(lock);
   75         mtx_unlock(&lock->lock);
   76 }
   77 
   78 static bool __ttm_read_lock(struct ttm_lock *lock)
   79 {
   80         bool locked = false;
   81 
   82         if (unlikely(lock->kill_takers)) {
   83                 ttm_lock_send_sig(lock->signal);
   84                 return false;
   85         }
   86         if (lock->rw >= 0 && lock->flags == 0) {
   87                 ++lock->rw;
   88                 locked = true;
   89         }
   90         return locked;
   91 }
   92 
   93 int
   94 ttm_read_lock(struct ttm_lock *lock, bool interruptible)
   95 {
   96         const char *wmsg;
   97         int flags, ret;
   98 
   99         ret = 0;
  100         if (interruptible) {
  101                 flags = PCATCH;
  102                 wmsg = "ttmri";
  103         } else {
  104                 flags = 0;
  105                 wmsg = "ttmr";
  106         }
  107         mtx_lock(&lock->lock);
  108         while (!__ttm_read_lock(lock)) {
  109                 ret = -msleep(lock, &lock->lock, flags, wmsg, 0);
  110                 if (ret == -EINTR || ret == -ERESTART)
  111                         ret = -ERESTARTSYS;
  112                 if (ret != 0)
  113                         break;
  114         }
  115         return (ret);
  116 }
  117 
  118 static bool __ttm_read_trylock(struct ttm_lock *lock, bool *locked)
  119 {
  120         bool block = true;
  121 
  122         *locked = false;
  123 
  124         if (unlikely(lock->kill_takers)) {
  125                 ttm_lock_send_sig(lock->signal);
  126                 return false;
  127         }
  128         if (lock->rw >= 0 && lock->flags == 0) {
  129                 ++lock->rw;
  130                 block = false;
  131                 *locked = true;
  132         } else if (lock->flags == 0) {
  133                 block = false;
  134         }
  135 
  136         return !block;
  137 }
  138 
  139 int ttm_read_trylock(struct ttm_lock *lock, bool interruptible)
  140 {
  141         const char *wmsg;
  142         int flags, ret;
  143         bool locked;
  144 
  145         ret = 0;
  146         if (interruptible) {
  147                 flags = PCATCH;
  148                 wmsg = "ttmrti";
  149         } else {
  150                 flags = 0;
  151                 wmsg = "ttmrt";
  152         }
  153         mtx_lock(&lock->lock);
  154         while (!__ttm_read_trylock(lock, &locked)) {
  155                 ret = -msleep(lock, &lock->lock, flags, wmsg, 0);
  156                 if (ret == -EINTR || ret == -ERESTART)
  157                         ret = -ERESTARTSYS;
  158                 if (ret != 0)
  159                         break;
  160         }
  161         MPASS(!locked || ret == 0);
  162         mtx_unlock(&lock->lock);
  163 
  164         return (locked) ? 0 : -EBUSY;
  165 }
  166 
  167 void ttm_write_unlock(struct ttm_lock *lock)
  168 {
  169         mtx_lock(&lock->lock);
  170         lock->rw = 0;
  171         wakeup(lock);
  172         mtx_unlock(&lock->lock);
  173 }
  174 
  175 static bool __ttm_write_lock(struct ttm_lock *lock)
  176 {
  177         bool locked = false;
  178 
  179         if (unlikely(lock->kill_takers)) {
  180                 ttm_lock_send_sig(lock->signal);
  181                 return false;
  182         }
  183         if (lock->rw == 0 && ((lock->flags & ~TTM_WRITE_LOCK_PENDING) == 0)) {
  184                 lock->rw = -1;
  185                 lock->flags &= ~TTM_WRITE_LOCK_PENDING;
  186                 locked = true;
  187         } else {
  188                 lock->flags |= TTM_WRITE_LOCK_PENDING;
  189         }
  190         return locked;
  191 }
  192 
  193 int
  194 ttm_write_lock(struct ttm_lock *lock, bool interruptible)
  195 {
  196         const char *wmsg;
  197         int flags, ret;
  198 
  199         ret = 0;
  200         if (interruptible) {
  201                 flags = PCATCH;
  202                 wmsg = "ttmwi";
  203         } else {
  204                 flags = 0;
  205                 wmsg = "ttmw";
  206         }
  207         mtx_lock(&lock->lock);
  208         /* XXXKIB: linux uses __ttm_read_lock for uninterruptible sleeps */
  209         while (!__ttm_write_lock(lock)) {
  210                 ret = -msleep(lock, &lock->lock, flags, wmsg, 0);
  211                 if (ret == -EINTR || ret == -ERESTART)
  212                         ret = -ERESTARTSYS;
  213                 if (interruptible && ret != 0) {
  214                         lock->flags &= ~TTM_WRITE_LOCK_PENDING;
  215                         wakeup(lock);
  216                         break;
  217                 }
  218         }
  219         mtx_unlock(&lock->lock);
  220 
  221         return (ret);
  222 }
  223 
  224 void ttm_write_lock_downgrade(struct ttm_lock *lock)
  225 {
  226         mtx_lock(&lock->lock);
  227         lock->rw = 1;
  228         wakeup(lock);
  229         mtx_unlock(&lock->lock);
  230 }
  231 
  232 static int __ttm_vt_unlock(struct ttm_lock *lock)
  233 {
  234         int ret = 0;
  235 
  236         mtx_lock(&lock->lock);
  237         if (unlikely(!(lock->flags & TTM_VT_LOCK)))
  238                 ret = -EINVAL;
  239         lock->flags &= ~TTM_VT_LOCK;
  240         wakeup(lock);
  241         mtx_unlock(&lock->lock);
  242 
  243         return ret;
  244 }
  245 
  246 static void ttm_vt_lock_remove(struct ttm_base_object **p_base)
  247 {
  248         struct ttm_base_object *base = *p_base;
  249         struct ttm_lock *lock = container_of(base, struct ttm_lock, base);
  250         int ret;
  251 
  252         *p_base = NULL;
  253         ret = __ttm_vt_unlock(lock);
  254         MPASS(ret == 0);
  255 }
  256 
  257 static bool __ttm_vt_lock(struct ttm_lock *lock)
  258 {
  259         bool locked = false;
  260 
  261         if (lock->rw == 0) {
  262                 lock->flags &= ~TTM_VT_LOCK_PENDING;
  263                 lock->flags |= TTM_VT_LOCK;
  264                 locked = true;
  265         } else {
  266                 lock->flags |= TTM_VT_LOCK_PENDING;
  267         }
  268         return locked;
  269 }
  270 
  271 int ttm_vt_lock(struct ttm_lock *lock,
  272                 bool interruptible,
  273                 struct ttm_object_file *tfile)
  274 {
  275         const char *wmsg;
  276         int flags, ret;
  277 
  278         ret = 0;
  279         if (interruptible) {
  280                 flags = PCATCH;
  281                 wmsg = "ttmwi";
  282         } else {
  283                 flags = 0;
  284                 wmsg = "ttmw";
  285         }
  286         mtx_lock(&lock->lock);
  287         while (!__ttm_vt_lock(lock)) {
  288                 ret = -msleep(lock, &lock->lock, flags, wmsg, 0);
  289                 if (ret == -EINTR || ret == -ERESTART)
  290                         ret = -ERESTARTSYS;
  291                 if (interruptible && ret != 0) {
  292                         lock->flags &= ~TTM_VT_LOCK_PENDING;
  293                         wakeup(lock);
  294                         break;
  295                 }
  296         }
  297 
  298         /*
  299          * Add a base-object, the destructor of which will
  300          * make sure the lock is released if the client dies
  301          * while holding it.
  302          */
  303 
  304         ret = ttm_base_object_init(tfile, &lock->base, false,
  305                                    ttm_lock_type, &ttm_vt_lock_remove, NULL);
  306         if (ret)
  307                 (void)__ttm_vt_unlock(lock);
  308         else
  309                 lock->vt_holder = tfile;
  310 
  311         return (ret);
  312 }
  313 
  314 int ttm_vt_unlock(struct ttm_lock *lock)
  315 {
  316         return ttm_ref_object_base_unref(lock->vt_holder,
  317                                          lock->base.hash.key, TTM_REF_USAGE);
  318 }
  319 
  320 void ttm_suspend_unlock(struct ttm_lock *lock)
  321 {
  322         mtx_lock(&lock->lock);
  323         lock->flags &= ~TTM_SUSPEND_LOCK;
  324         wakeup(lock);
  325         mtx_unlock(&lock->lock);
  326 }
  327 
  328 static bool __ttm_suspend_lock(struct ttm_lock *lock)
  329 {
  330         bool locked = false;
  331 
  332         if (lock->rw == 0) {
  333                 lock->flags &= ~TTM_SUSPEND_LOCK_PENDING;
  334                 lock->flags |= TTM_SUSPEND_LOCK;
  335                 locked = true;
  336         } else {
  337                 lock->flags |= TTM_SUSPEND_LOCK_PENDING;
  338         }
  339         return locked;
  340 }
  341 
  342 void ttm_suspend_lock(struct ttm_lock *lock)
  343 {
  344         mtx_lock(&lock->lock);
  345         while (!__ttm_suspend_lock(lock))
  346                 msleep(lock, &lock->lock, 0, "ttms", 0);
  347         mtx_unlock(&lock->lock);
  348 }

Cache object: a6e9a20ffd0041b2c0c6726331eae9c5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.