From 953800406c481161521b5c25cb80dfda0ab5ad5f Mon Sep 17 00:00:00 2001 From: dillon Date: Mon, 21 Dec 1998 07:41:51 +0000 Subject: 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. --- sys/kern/kern_synch.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++- sys/sys/proc.h | 15 +++- sys/sys/systm.h | 4 +- 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_ */ -- cgit v1.1