]> git.proxmox.com Git - mirror_spl-debian.git/blobdiff - include/sys/condvar.h
Reimplement mutexs for Linux lock profiling/analysis
[mirror_spl-debian.git] / include / sys / condvar.h
index 6a2060fd243fff0308e2f1de1de83a189f9f8470..9a2e8b5a0df46034090cfda5358f5c2764e22254 100644 (file)
@@ -1,3 +1,29 @@
+/*
+ *  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>
+ *  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 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.
+ */
+
 #ifndef _SPL_CONDVAR_H
 #define _SPL_CONDVAR_H
 
@@ -7,6 +33,8 @@ extern "C" {
 
 #include <linux/module.h>
 #include <linux/wait.h>
+#include <sys/kmem.h>
+#include <sys/mutex.h>
 
 /* The kcondvar_t struct is protected by mutex taken externally before
  * calling any of the wait/signal funs, and passed into the wait funs.
@@ -17,186 +45,34 @@ extern "C" {
 typedef struct {
        int cv_magic;
        char *cv_name;
+       int cv_name_size;
        wait_queue_head_t cv_event;
        atomic_t cv_waiters;
-       kmutex_t *cv_mutex; /* only for verification purposes */
+       kmutex_t *cv_mutex;
+       spinlock_t cv_lock;
 } kcondvar_t;
 
 typedef enum { CV_DEFAULT=0, CV_DRIVER } kcv_type_t;
 
-static __inline__ void
-cv_init(kcondvar_t *cvp, char *name, kcv_type_t type, void *arg)
-{
-       BUG_ON(cvp == NULL);
-       BUG_ON(type != CV_DEFAULT);
-       BUG_ON(arg != NULL);
-
-       cvp->cv_magic = CV_MAGIC;
-       init_waitqueue_head(&cvp->cv_event);
-       atomic_set(&cvp->cv_waiters, 0);
-       cvp->cv_mutex = NULL;
-       cvp->cv_name = NULL;
-
-       if (name) {
-               cvp->cv_name = kmalloc(strlen(name) + 1, GFP_KERNEL);
-               if (cvp->cv_name)
-                       strcpy(cvp->cv_name, name);
-       }
-}
-
-static __inline__ void
-cv_destroy(kcondvar_t *cvp)
-{
-       BUG_ON(cvp == NULL);
-       BUG_ON(cvp->cv_magic != CV_MAGIC);
-       BUG_ON(atomic_read(&cvp->cv_waiters) != 0);
-       BUG_ON(waitqueue_active(&cvp->cv_event));
-
-       if (cvp->cv_name)
-               kfree(cvp->cv_name);
-
-       memset(cvp, CV_POISON, sizeof(*cvp));
-}
-
-static __inline__ void
-cv_wait(kcondvar_t *cvp, kmutex_t *mtx)
-{
-       DEFINE_WAIT(wait);
-       int flag = 1;
-
-       BUG_ON(cvp == NULL || mtx == NULL);
-       BUG_ON(cvp->cv_magic != CV_MAGIC);
-       BUG_ON(!mutex_owned(mtx));
-
-       if (cvp->cv_mutex == NULL)
-               cvp->cv_mutex = mtx;
-
-       /* Ensure the same mutex is used by all callers */
-       BUG_ON(cvp->cv_mutex != mtx);
-
-       for (;;) {
-               prepare_to_wait_exclusive(&cvp->cv_event, &wait,
-                                         TASK_INTERRUPTIBLE);
-               /* Must occur after we are added to the list but only once */
-               if (flag) {
-                       atomic_inc(&cvp->cv_waiters);
-                       flag = 0;
-               }
-
-               /* XXX - The correct thing to do here may be to wake up and 
-                * force the caller to handle the signal.  Spurious wakeups 
-                * should already be safely handled by the caller. */
-               if (signal_pending(current))
-                       flush_signals(current);
-
-               /* Mutex should be dropped after prepare_to_wait() this
-                * ensures we're linked in to the waiters list and avoids the
-                * race where 'cvp->cv_waiters > 0' but the list is empty. */
-               mutex_exit(mtx);
-               schedule();
-               mutex_enter(mtx);
-
-               /* XXX - The correct thing to do here may be to wake up and 
-                * force the caller to handle the signal.  Spurious wakeups 
-                * should already be safely handled by the caller. */
-               if (signal_pending(current))
-                       continue;
-
-               break;
-       }
-
-       atomic_dec(&cvp->cv_waiters);
-       finish_wait(&cvp->cv_event, &wait);
-}
-
-/* 'expire_time' argument is an absolute wall clock time in jiffies.
- * Return value is time left (expire_time - now) or -1 if timeout occurred.
- */
-static __inline__ clock_t
-cv_timedwait(kcondvar_t *cvp, kmutex_t *mtx, clock_t expire_time)
-{
-       DEFINE_WAIT(wait);
-       clock_t time_left;
-       int flag = 1;
-
-       BUG_ON(cvp == NULL || mtx == NULL);
-       BUG_ON(cvp->cv_magic != CV_MAGIC);
-       BUG_ON(!mutex_owned(mtx));
-
-       if (cvp->cv_mutex == NULL)
-               cvp->cv_mutex = mtx;
-
-       /* XXX - Does not handle jiffie wrap properly */
-       time_left = expire_time - jiffies;
-       if (time_left <= 0)
-               return -1;
-
-       /* Ensure the same mutex is used by all callers */
-       BUG_ON(cvp->cv_mutex != mtx);
-
-       for (;;) {
-               prepare_to_wait_exclusive(&cvp->cv_event, &wait,
-                                         TASK_INTERRUPTIBLE);
-               if (flag) {
-                       atomic_inc(&cvp->cv_waiters);
-                       flag = 0;
-               }
-
-               /* XXX - The correct thing to do here may be to wake up and 
-                * force the caller to handle the signal.  Spurious wakeups 
-                * should already be safely handled by the caller. */
-               if (signal_pending(current))
-                       flush_signals(current);
-
-               /* Mutex should be dropped after prepare_to_wait() this
-                * ensures we're linked in to the waiters list and avoids the
-                * race where 'cvp->cv_waiters > 0' but the list is empty. */
-               mutex_exit(mtx);
-               time_left = schedule_timeout(time_left);
-               mutex_enter(mtx);
-
-               /* XXX - The correct thing to do here may be to wake up and 
-                * force the caller to handle the signal.  Spurious wakeups 
-                * should already be safely handled by the caller. */
-               if (signal_pending(current)) {
-                       if (time_left > 0)
-                               continue;
-
-                       flush_signals(current);
-               }
-
-               break;
-       }
-
-       atomic_dec(&cvp->cv_waiters);
-       finish_wait(&cvp->cv_event, &wait);
-
-       return (time_left > 0 ? time_left : -1);
-}
-
-static __inline__ void
-cv_signal(kcondvar_t *cvp)
-{
-       BUG_ON(cvp == NULL);
-       BUG_ON(cvp->cv_magic != CV_MAGIC);
-
-       /* All waiters are added with WQ_FLAG_EXCLUSIVE so only one
-        * waiter will be set runable with each call to wake_up().
-        * Additionally wake_up() holds a spin_lock assoicated with
-        * the wait queue to ensure we don't race waking up processes. */
-       if (atomic_read(&cvp->cv_waiters) > 0)
-               wake_up(&cvp->cv_event);
-}
-
-static __inline__ void
-cv_broadcast(kcondvar_t *cvp)
-{
-       BUG_ON(cvp == NULL);
-       BUG_ON(cvp->cv_magic != CV_MAGIC);
+extern void __cv_init(kcondvar_t *cvp, char *name, kcv_type_t type, void *arg);
+extern void __cv_destroy(kcondvar_t *cvp);
+extern void __cv_wait(kcondvar_t *cvp, kmutex_t *mp);
+extern clock_t __cv_timedwait(kcondvar_t *cvp, kmutex_t *mp,
+                             clock_t expire_time);
+extern void __cv_signal(kcondvar_t *cvp);
+extern void __cv_broadcast(kcondvar_t *cvp);
+
+#define cv_init(cvp, name, type, arg)                                 \
+({                                                                    \
+       if ((name) == NULL)                                           \
+               __cv_init(cvp, #cvp, type, arg);                      \
+       else                                                          \
+               __cv_init(cvp, name, type, arg);                      \
+})
+#define cv_destroy(cvp)                        __cv_destroy(cvp)
+#define cv_wait(cvp, mp)               __cv_wait(cvp, mp)
+#define cv_timedwait(cvp, mp, t)       __cv_timedwait(cvp, mp, t)
+#define cv_signal(cvp)                 __cv_signal(cvp)
+#define cv_broadcast(cvp)              __cv_broadcast(cvp)
 
-       /* Wake_up_all() will wake up all waiters even those which
-        * have the WQ_FLAG_EXCLUSIVE flag set. */
-       if (atomic_read(&cvp->cv_waiters) > 0)
-               wake_up_all(&cvp->cv_event);
-}
 #endif /* _SPL_CONDVAR_H */