]> git.proxmox.com Git - mirror_spl-debian.git/blobdiff - module/spl/spl-mutex.c
Imported Upstream version 0.6.4.1
[mirror_spl-debian.git] / module / spl / spl-mutex.c
index e7ec41cf48a400ee3fb55fc0181bb38567378c93..a29d488d13b77fbb98e042acd34644b2b3f967a4 100644 (file)
@@ -1,28 +1,28 @@
-/*
- *  This file is part of the SPL: Solaris Porting Layer.
- *
- *  Copyright (c) 2008 Lawrence Livermore National Security, LLC.
- *  Produced at Lawrence Livermore National Laboratory
- *  Written by:
- *          Brian Behlendorf <behlendorf1@llnl.gov>,
- *          Herb Wartens <wartens2@llnl.gov>,
- *          Jim Garlick <garlick@llnl.gov>
+/*****************************************************************************\
+ *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
+ *  Copyright (C) 2007 The Regents of the University of California.
+ *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
+ *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
  *  UCRL-CODE-235197
  *
- *  This is free software; you can redistribute it and/or modify it
- *  under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
+ *  This file is part of the SPL, Solaris Porting Layer.
+ *  For details, see <http://zfsonlinux.org/>.
+ *
+ *  The SPL is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2 of the License, or (at your
+ *  option) any later version.
  *
- *  This is distributed in the hope that it will be useful, but WITHOUT
+ *  The SPL is distributed in the hope that it will be useful, but WITHOUT
  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  *  for more details.
  *
  *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
- */
+ *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
+ *****************************************************************************
+ *  Solaris Porting Layer (SPL) Mutex Implementation.
+\*****************************************************************************/
 
 #include <sys/mutex.h>
 
 
 #define DEBUG_SUBSYSTEM S_MUTEX
 
-/* Mutex implementation based on those found in Solaris.  This means
- * they the MUTEX_DEFAULT type is an adaptive mutex.  When calling
- * mutex_enter() your process will spin waiting for the lock if it's
- * likely the lock will be free'd shortly.  If it looks like the
- * lock will be held for a longer time we schedule and sleep waiting
- * for it.  This determination is made by checking if the holder of
- * the lock is currently running on cpu or sleeping waiting to be
- * scheduled.  If the holder is currently running it's likely the
- * lock will be shortly dropped.
- *
- * XXX: This is basically a rough implementation to see if this
- * helps our performance.  If it does a more careful implementation
- * should be done, perhaps in assembly.
- */
-
-/*  0:         Never spin when trying to aquire lock
- * -1:         Spin until aquired or holder yeilds without dropping lock
- *  1-MAX_INT: Spin for N attempts before sleeping for lock
- */
-int mutex_spin_max = 0;
-
-#ifdef DEBUG_MUTEX
-int mutex_stats[MUTEX_STATS_SIZE] = { 0 };
-spinlock_t mutex_stats_lock;
-struct list_head mutex_stats_list;
-#endif
-
-int
-__spl_mutex_init(kmutex_t *mp, char *name, int type, void *ibc)
-{
-       int flags = KM_SLEEP;
-
-       ASSERT(mp);
-       ASSERT(name);
-       ASSERT(ibc == NULL);
-       ASSERT(mp->km_magic != KM_MAGIC); /* Never double init */
-
-       mp->km_name = NULL;
-       mp->km_name_size = strlen(name) + 1;
-
-       switch (type) {
-               case MUTEX_DEFAULT:
-                       mp->km_type = MUTEX_ADAPTIVE;
-                       break;
-               case MUTEX_SPIN:
-               case MUTEX_ADAPTIVE:
-                       mp->km_type = type;
-                       break;
-               default:
-                       SBUG();
-       }
-
-       /* We may be called when there is a non-zero preempt_count or
-        * interrupts are disabled is which case we must not sleep.
-        */
-        if (current_thread_info()->preempt_count || irqs_disabled())
-               flags = KM_NOSLEEP;
-
-       /* Semaphore kmem_alloc'ed to keep struct size down (<64b) */
-       mp->km_sem = kmem_alloc(sizeof(struct semaphore), flags);
-       if (mp->km_sem == NULL)
-               return -ENOMEM;
-
-       mp->km_name = kmem_alloc(mp->km_name_size, flags);
-       if (mp->km_name == NULL) {
-               kmem_free(mp->km_sem, sizeof(struct semaphore));
-               return -ENOMEM;
-       }
-
-       sema_init(mp->km_sem, 1);
-       strncpy(mp->km_name, name, mp->km_name_size);
-
-#ifdef DEBUG_MUTEX
-       mp->km_stats = kmem_zalloc(sizeof(int) * MUTEX_STATS_SIZE, flags);
-        if (mp->km_stats == NULL) {
-               kmem_free(mp->km_name, mp->km_name_size);
-               kmem_free(mp->km_sem, sizeof(struct semaphore));
-               return -ENOMEM;
-       }
-
-       /* XXX - This appears to be a much more contended lock than I
-        * would have expected.  To run with this debugging enabled and
-        * get reasonable performance we may need to be more clever and
-        * do something like hash the mutex ptr on to one of several
-        * lists to ease this single point of contention.
-        */
-       spin_lock(&mutex_stats_lock);
-       list_add_tail(&mp->km_list, &mutex_stats_list);
-       spin_unlock(&mutex_stats_lock);
-#endif
-       mp->km_magic = KM_MAGIC;
-       mp->km_owner = NULL;
-
-       return 0;
-}
-EXPORT_SYMBOL(__spl_mutex_init);
-
-void
-__spl_mutex_destroy(kmutex_t *mp)
-{
-       ASSERT(mp);
-       ASSERT(mp->km_magic == KM_MAGIC);
-
-#ifdef DEBUG_MUTEX
-       spin_lock(&mutex_stats_lock);
-       list_del_init(&mp->km_list);
-       spin_unlock(&mutex_stats_lock);
-
-       kmem_free(mp->km_stats, sizeof(int) * MUTEX_STATS_SIZE);
-#endif
-       kmem_free(mp->km_name, mp->km_name_size);
-       kmem_free(mp->km_sem, sizeof(struct semaphore));
-
-       memset(mp, KM_POISON, sizeof(*mp));
-}
-EXPORT_SYMBOL(__spl_mutex_destroy);
-
-/* Return 1 if we acquired the mutex, else zero.  */
-int
-__mutex_tryenter(kmutex_t *mp)
-{
-       int rc;
-       ENTRY;
-
-       ASSERT(mp);
-       ASSERT(mp->km_magic == KM_MAGIC);
-       MUTEX_STAT_INC(mutex_stats, MUTEX_TRYENTER_TOTAL);
-       MUTEX_STAT_INC(mp->km_stats, MUTEX_TRYENTER_TOTAL);
-
-       rc = down_trylock(mp->km_sem);
-       if (rc == 0) {
-               ASSERT(mp->km_owner == NULL);
-               mp->km_owner = current;
-               MUTEX_STAT_INC(mutex_stats, MUTEX_TRYENTER_NOT_HELD);
-               MUTEX_STAT_INC(mp->km_stats, MUTEX_TRYENTER_NOT_HELD);
-       }
-
-       RETURN(!rc);
-}
-EXPORT_SYMBOL(__mutex_tryenter);
-
-#ifndef HAVE_TASK_CURR
-#define task_curr(owner)                0
-#endif
-
-
-static void
-mutex_enter_adaptive(kmutex_t *mp)
-{
-       struct task_struct *owner;
-       int count = 0;
-
-       /* Lock is not held so we expect to aquire the lock */
-       if ((owner = mp->km_owner) == NULL) {
-               down(mp->km_sem);
-               MUTEX_STAT_INC(mutex_stats, MUTEX_ENTER_NOT_HELD);
-               MUTEX_STAT_INC(mp->km_stats, MUTEX_ENTER_NOT_HELD);
-       } else {
-               /* The lock is held by a currently running task which
-                * we expect will drop the lock before leaving the
-                * head of the runqueue.  So the ideal thing to do
-                * is spin until we aquire the lock and avoid a
-                * context switch.  However it is also possible the
-                * task holding the lock yields the processor with
-                * out dropping lock.  In which case, we know it's
-                * going to be a while so we stop spinning and go
-                * to sleep waiting for the lock to be available.
-                * This should strike the optimum balance between
-                * spinning and sleeping waiting for a lock.
-                */
-               while (task_curr(owner) && (count <= mutex_spin_max)) {
-                       if (down_trylock(mp->km_sem) == 0) {
-                               MUTEX_STAT_INC(mutex_stats, MUTEX_ENTER_SPIN);
-                               MUTEX_STAT_INC(mp->km_stats, MUTEX_ENTER_SPIN);
-                               GOTO(out, count);
-                       }
-                       count++;
-               }
-
-               /* The lock is held by a sleeping task so it's going to
-                * cost us minimally one context switch.  We might as
-                * well sleep and yield the processor to other tasks.
-                */
-               down(mp->km_sem);
-               MUTEX_STAT_INC(mutex_stats, MUTEX_ENTER_SLEEP);
-               MUTEX_STAT_INC(mp->km_stats, MUTEX_ENTER_SLEEP);
-       }
-out:
-       MUTEX_STAT_INC(mutex_stats, MUTEX_ENTER_TOTAL);
-       MUTEX_STAT_INC(mp->km_stats, MUTEX_ENTER_TOTAL);
-}
-
-void
-__mutex_enter(kmutex_t *mp)
-{
-       ENTRY;
-       ASSERT(mp);
-       ASSERT(mp->km_magic == KM_MAGIC);
-
-       switch (mp->km_type) {
-               case MUTEX_SPIN:
-                       while (down_trylock(mp->km_sem));
-                       MUTEX_STAT_INC(mutex_stats, MUTEX_ENTER_SPIN);
-                       MUTEX_STAT_INC(mp->km_stats, MUTEX_ENTER_SPIN);
-                       break;
-               case MUTEX_ADAPTIVE:
-                       mutex_enter_adaptive(mp);
-                       break;
-       }
-
-       ASSERT(mp->km_owner == NULL);
-       mp->km_owner = current;
-
-       EXIT;
-}
-EXPORT_SYMBOL(__mutex_enter);
-
-void
-__mutex_exit(kmutex_t *mp)
-{
-       ENTRY;
-       ASSERT(mp);
-       ASSERT(mp->km_magic == KM_MAGIC);
-       ASSERT(mp->km_owner == current);
-       mp->km_owner = NULL;
-       up(mp->km_sem);
-       EXIT;
-}
-EXPORT_SYMBOL(__mutex_exit);
-
-/* Return 1 if mutex is held by current process, else zero.  */
-int
-__mutex_owned(kmutex_t *mp)
-{
-       ENTRY;
-       ASSERT(mp);
-       ASSERT(mp->km_magic == KM_MAGIC);
-       RETURN(mp->km_owner == current);
-}
-EXPORT_SYMBOL(__mutex_owned);
-
-/* Return owner if mutex is owned, else NULL.  */
-kthread_t *
-__spl_mutex_owner(kmutex_t *mp)
-{
-       ENTRY;
-       ASSERT(mp);
-       ASSERT(mp->km_magic == KM_MAGIC);
-       RETURN(mp->km_owner);
-}
-EXPORT_SYMBOL(__spl_mutex_owner);
-
-int
-spl_mutex_init(void)
-{
-       ENTRY;
-#ifdef DEBUG_MUTEX
-       spin_lock_init(&mutex_stats_lock);
-        INIT_LIST_HEAD(&mutex_stats_list);
-#endif
-       RETURN(0);
-}
-
-void
-spl_mutex_fini(void)
-{
-        ENTRY;
-#ifdef DEBUG_MUTEX
-       ASSERT(list_empty(&mutex_stats_list));
-#endif
-        EXIT;
-}
-
-module_param(mutex_spin_max, int, 0644);
-MODULE_PARM_DESC(mutex_spin_max, "Spin a maximum of N times to aquire lock");
+int spl_mutex_init(void) { return 0; }
+void spl_mutex_fini(void) { }