condvar: add implementation
authorSimon Schubert <corecode@dragonflybsd.org>
Fri, 11 Dec 2009 22:25:09 +0000 (23:25 +0100)
committerRui Paulo <rpaulo@FreeBSD.org>
Thu, 25 Feb 2010 16:17:57 +0000 (16:17 +0000)
Add a small implementation of condition variables.  API design adopted
from FreeBSD.

sys/conf/files
sys/kern/kern_condvar.c [new file with mode: 0644]
sys/sys/condvar.h [new file with mode: 0644]

index 39793d0..a5bc7b8 100644 (file)
@@ -649,6 +649,7 @@ kern/link_elf.c             standard
 kern/kern_acct.c       standard
 kern/kern_acl.c                standard
 kern/kern_clock.c      standard
+kern/kern_condvar.c    standard
 kern/kern_conf.c       standard
 kern/kern_debug.c      standard
 kern/kern_device.c     standard
diff --git a/sys/kern/kern_condvar.c b/sys/kern/kern_condvar.c
new file mode 100644 (file)
index 0000000..06ec868
--- /dev/null
@@ -0,0 +1,56 @@
+#include <sys/condvar.h>
+#include <sys/spinlock2.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+
+void
+cv_init(struct cv *c, const char *desc)
+{
+       c->cv_desc = desc;
+       c->cv_waiters = 0;
+       spin_init(&c->cv_lock);
+}
+
+void
+cv_destroy(struct cv *c)
+{
+       spin_uninit(&c->cv_lock);
+}
+
+int
+_cv_timedwait(struct cv *c, struct lock *l, int timo, int wakesig)
+{
+       int flags = wakesig ? PCATCH : 0;
+       int error;
+
+       spin_lock_wr(&c->cv_lock);
+       tsleep_interlock(c, flags);
+       c->cv_waiters++;
+       spin_unlock_wr(&c->cv_lock);
+       if (l != NULL)
+               lockmgr(l, LK_RELEASE);
+       error = tsleep(c, flags, c->cv_desc, timo);
+       if (l != NULL)
+               lockmgr(l, LK_EXCLUSIVE);
+
+       return (error);
+}
+
+void
+_cv_signal(struct cv *c, int broadcast)
+{
+       spin_lock_wr(&c->cv_lock);
+       if (c->cv_waiters == 0)
+               goto out;
+
+       if (broadcast) {
+               c->cv_waiters = 0;
+               wakeup(c);
+       } else {
+               c->cv_waiters--;
+               wakeup_one(c);
+       }
+
+out:
+       spin_unlock_wr(&c->cv_lock);
+}
diff --git a/sys/sys/condvar.h b/sys/sys/condvar.h
new file mode 100644 (file)
index 0000000..3acd314
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef        _SYS_CONDVAR_H_
+#define        _SYS_CONDVAR_H_
+
+#include <sys/spinlock.h>
+
+struct lock;
+
+struct cv {
+       struct spinlock cv_lock;
+       int             cv_waiters;
+       const char      *cv_desc;
+};
+
+void   cv_init(struct cv *, const char *desc);
+void   cv_destroy(struct cv *);
+
+int    _cv_timedwait(struct cv *, struct lock *, int timo, int wakesig);
+void   _cv_signal(struct cv *, int broadcast);
+
+#define        cv_wait(cv, lock)                       \
+               _cv_timedwait((cv), (lock), 0, 0)
+#define        cv_wait_sig(cv, lock)                   \
+               _cv_timedwait((cv), (lock), 0, 1)
+#define        cv_timedwait(cv, lock, timeo)           \
+               _cv_timedwait((cv), (lock), (timeo), 0)
+#define        cv_timedwait_sig(cv, lock, timeo)       \
+               _cv_timedwait((cv), (lock), (timeo), 1)
+
+#define        cv_signal(cv)                           \
+               _cv_signal((cv), 0)
+#define        cv_broadcast(cv)                        \
+               _cv_signal((cv), 1)
+#define        cv_broadcastpri(cv)                     \
+               cv_broadcast((cv))
+
+#endif /* _SYS_CONDVAR_H_ */