summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordillon <dillon@FreeBSD.org>1998-12-21 07:41:51 +0000
committerdillon <dillon@FreeBSD.org>1998-12-21 07:41:51 +0000
commit953800406c481161521b5c25cb80dfda0ab5ad5f (patch)
tree5f1787f08c2d27d5ba81c84ce1f1e01855473a4c
parent131312c0d64ef051c53888e1373ee73402f389b9 (diff)
downloadFreeBSD-src-953800406c481161521b5c25cb80dfda0ab5ad5f.zip
FreeBSD-src-953800406c481161521b5c25cb80dfda0ab5ad5f.tar.gz
Add asleep() and await() support. Currently highly experimental. A
small support structure had to be added to the proc structure, and a few minor conditional panics no longer apply.
-rw-r--r--sys/kern/kern_synch.c191
-rw-r--r--sys/sys/proc.h15
-rw-r--r--sys/sys/systm.h4
3 files changed, 206 insertions, 4 deletions
diff --git a/sys/kern/kern_synch.c b/sys/kern/kern_synch.c
index a659f70..17b2a94 100644
--- a/sys/kern/kern_synch.c
+++ b/sys/kern/kern_synch.c
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)kern_synch.c 8.9 (Berkeley) 5/19/95
- * $Id: kern_synch.c,v 1.68 1998/11/26 16:49:55 bde Exp $
+ * $Id: kern_synch.c,v 1.69 1998/11/27 11:44:22 dg Exp $
*/
#include "opt_ktrace.h"
@@ -407,9 +407,21 @@ tsleep(ident, priority, wmesg, timo)
if (ident == NULL || p->p_stat != SRUN)
panic("tsleep");
/* XXX This is not exhaustive, just the most common case */
+#ifdef NOTDEF
+ /*
+ * This can happen legitimately now with asleep()/await()
+ */
if ((p->p_procq.tqe_prev != NULL) && (*p->p_procq.tqe_prev == p))
panic("sleeping process already on another queue");
#endif
+#endif
+ /*
+ * Process may be sitting on a slpque if asleep() was called, remove
+ * it before re-adding.
+ */
+ if (p->p_wchan != NULL)
+ unsleep(p);
+
p->p_wchan = ident;
p->p_wmesg = wmesg;
p->p_slptime = 0;
@@ -475,7 +487,170 @@ resume:
}
/*
- * Implement timeout for tsleep.
+ * asleep() - async sleep call. Place process on wait queue and return
+ * immediately without blocking. The process stays runnable until await()
+ * is called. If ident is NULL, remove process from wait queue if it is still
+ * on one.
+ *
+ * Only the most recent sleep condition is effective when making successive
+ * calls to asleep() or when calling tsleep().
+ *
+ * The timeout, if any, is not initiated until await() is called. The sleep
+ * priority, signal, and timeout is specified in the asleep() call but may be
+ * overriden in the await() call.
+ *
+ * <<<<<<<< EXPERIMENTAL, UNTESTED >>>>>>>>>>
+ */
+
+int
+asleep(void *ident, int priority, const char *wmesg, int timo)
+{
+ struct proc *p = curproc;
+ int s;
+
+ /*
+ * splhigh() while manipulating sleep structures and slpque.
+ *
+ * Remove preexisting wait condition (if any) and place process
+ * on appropriate slpque, but do not put process to sleep.
+ */
+
+ s = splhigh();
+
+ if (p->p_wchan != NULL)
+ unsleep(p);
+
+ if (ident) {
+ p->p_wchan = ident;
+ p->p_wmesg = wmesg;
+ p->p_slptime = 0;
+ p->p_asleep.as_priority = priority;
+ p->p_asleep.as_timo = timo;
+ TAILQ_INSERT_TAIL(&slpque[LOOKUP(ident)], p, p_procq);
+ }
+
+ splx(s);
+
+ return(0);
+}
+
+/*
+ * await() - wait for async condition to occur. The process blocks until
+ * wakeup() is called on the most recent asleep() address. If wakeup is called
+ * priority to await(), await() winds up being a NOP.
+ *
+ * If await() is called more then once (without an intervening asleep() call),
+ * await() is still effectively a NOP but it calls mi_switch() to give other
+ * processes some cpu before returning. The process is left runnable.
+ *
+ * <<<<<<<< EXPERIMENTAL, UNTESTED >>>>>>>>>>
+ */
+
+int
+await(int priority, int timo)
+{
+ struct proc *p = curproc;
+ int s;
+
+ s = splhigh();
+
+ if (p->p_wchan != NULL) {
+ struct callout_handle thandle;
+ int sig;
+ int catch;
+
+ /*
+ * The call to await() can override defaults specified in
+ * the original asleep().
+ */
+ if (priority < 0)
+ priority = p->p_asleep.as_priority;
+ if (timo < 0)
+ timo = p->p_asleep.as_timo;
+
+ /*
+ * Install timeout
+ */
+
+ if (timo)
+ thandle = timeout(endtsleep, (void *)p, timo);
+
+ sig = 0;
+ catch = priority & PCATCH;
+
+ if (catch) {
+ p->p_flag |= P_SINTR;
+ if ((sig = CURSIG(p))) {
+ if (p->p_wchan)
+ unsleep(p);
+ p->p_stat = SRUN;
+ goto resume;
+ }
+ if (p->p_wchan == NULL) {
+ catch = 0;
+ goto resume;
+ }
+ }
+ p->p_stat = SSLEEP;
+ p->p_stats->p_ru.ru_nvcsw++;
+ mi_switch();
+resume:
+ curpriority = p->p_usrpri;
+
+ splx(s);
+ p->p_flag &= ~P_SINTR;
+ if (p->p_flag & P_TIMEOUT) {
+ p->p_flag &= ~P_TIMEOUT;
+ if (sig == 0) {
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_CSW))
+ ktrcsw(p->p_tracep, 0, 0);
+#endif
+ return (EWOULDBLOCK);
+ }
+ } else if (timo)
+ untimeout(endtsleep, (void *)p, thandle);
+ if (catch && (sig != 0 || (sig = CURSIG(p)))) {
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_CSW))
+ ktrcsw(p->p_tracep, 0, 0);
+#endif
+ if (p->p_sigacts->ps_sigintr & sigmask(sig))
+ return (EINTR);
+ return (ERESTART);
+ }
+#ifdef KTRACE
+ if (KTRPOINT(p, KTR_CSW))
+ ktrcsw(p->p_tracep, 0, 0);
+#endif
+ } else {
+ /*
+ * If as_priority is 0, await() has been called without an
+ * intervening asleep(). We are still effectively a NOP,
+ * but we call mi_switch() for safety.
+ */
+
+ if (p->p_asleep.as_priority == 0) {
+ p->p_stats->p_ru.ru_nvcsw++;
+ mi_switch();
+ }
+ splx(s);
+ }
+
+ /*
+ * clear p_asleep.as_priority as an indication that await() has been
+ * called. If await() is called again without an intervening asleep(),
+ * await() is still effectively a NOP but the above mi_switch() code
+ * is triggered as a safety.
+ */
+ p->p_asleep.as_priority = 0;
+
+ return (0);
+}
+
+/*
+ * Implement timeout for tsleep or asleep()/await()
+ *
* If process hasn't been awakened (wchan non-zero),
* set timeout flag and undo the sleep. If proc
* is stopped, just unsleep so it will remain stopped.
@@ -532,9 +707,15 @@ wakeup(ident)
restart:
for (p = qp->tqh_first; p != NULL; p = p->p_procq.tqe_next) {
#ifdef DIAGNOSTIC
+#ifdef NOTDEF
+ /*
+ * The process can legitimately be running now with
+ * asleep()/await().
+ */
if (p->p_stat != SSLEEP && p->p_stat != SSTOP)
panic("wakeup");
#endif
+#endif
if (p->p_wchan == ident) {
TAILQ_REMOVE(qp, p, p_procq);
p->p_wchan = 0;
@@ -577,9 +758,15 @@ wakeup_one(ident)
for (p = qp->tqh_first; p != NULL; p = p->p_procq.tqe_next) {
#ifdef DIAGNOSTIC
+#ifdef NOTDEF
+ /*
+ * The process can legitimately be running now with
+ * asleep()/await().
+ */
if (p->p_stat != SSLEEP && p->p_stat != SSTOP)
panic("wakeup_one");
#endif
+#endif
if (p->p_wchan == ident) {
TAILQ_REMOVE(qp, p, p_procq);
p->p_wchan = 0;
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index d4fd1e2..71b59a8 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)proc.h 8.15 (Berkeley) 5/19/95
- * $Id: proc.h,v 1.62 1998/11/13 17:53:55 dg Exp $
+ * $Id: proc.h,v 1.63 1998/12/19 02:55:34 julian Exp $
*/
#ifndef _SYS_PROC_H_
@@ -94,6 +94,18 @@ struct procsig {
};
#endif /* COMPAT_LINUX_THREADS */
+
+
+/*
+ * pasleep structure, used by asleep() syscall to hold requested priority and
+ * timeout values for await().
+ */
+
+struct pasleep {
+ int as_priority; /* async priority */
+ int as_timo; /* async timeout */
+} pasleep;
+
/*
* Description of a process.
*
@@ -232,6 +244,7 @@ struct proc {
int p_wakeup; /* thread id */
struct proc *p_peers;
struct proc *p_leader;
+ struct pasleep p_asleep; /* used by asleep()/await() */
};
#define p_session p_pgrp->pg_session
diff --git a/sys/sys/systm.h b/sys/sys/systm.h
index 09b9ce5..222d14b 100644
--- a/sys/sys/systm.h
+++ b/sys/sys/systm.h
@@ -36,7 +36,7 @@
* SUCH DAMAGE.
*
* @(#)systm.h 8.7 (Berkeley) 3/29/95
- * $Id: systm.h,v 1.78 1998/10/30 05:41:15 msmith Exp $
+ * $Id: systm.h,v 1.79 1998/12/03 04:45:57 archie Exp $
*/
#ifndef _SYS_SYSTM_H_
@@ -295,6 +295,8 @@ extern watchdog_tickle_fn wdog_tickler;
* less often.
*/
int tsleep __P((void *chan, int pri, const char *wmesg, int timo));
+int asleep __P((void *chan, int pri, const char *wmesg, int timo));
+int await __P((int pri, int timo));
void wakeup __P((void *chan));
#endif /* !_SYS_SYSTM_H_ */
OpenPOWER on IntegriCloud