kern_synch.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 339 行

C
339
字号
/* * Copyright (c) 1997-1998 University of Utah and the Flux Group. * All rights reserved. *  * This file is part of the Flux OSKit.  The OSKit is free software, also known * as "open source;" you can redistribute it and/or modify it under the terms * of the GNU General Public License (GPL), version 2, as published by the Free * Software Foundation (FSF).  To explore alternate licensing terms, contact * the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271. *  * The OSKit 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 GPL for more details.  You should have * received a copy of the GPL along with the OSKit; see the file COPYING.  If * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA. *//*- * Copyright (c) 1982, 1986, 1990, 1991, 1993 *	The Regents of the University of California.  All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software *    must display the following acknowledgement: *	This product includes software developed by the University of *	California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors *    may be used to endorse or promote products derived from this software *    without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * *	@(#)kern_synch.c	8.6 (Berkeley) 1/21/94 * $\Id: kern_synch.c,v 1.11.4.1 1996/01/31 13:12:29 davidg Exp $ */#include <sys/param.h>#include <sys/systm.h>#include <sys/proc.h>#include <sys/kernel.h>#include <sys/buf.h>#include <sys/signalvar.h>#include <sys/resourcevar.h>#include <sys/signalvar.h>#include <vm/vm.h>#include "glue.h"#include <machine/cpu.h>int	lbolt;			/* once a second sleep address */void	endtsleep __P((void *));#ifdef OSKITvoid#elsestatic void#endifschedcpu(arg)	void *arg;{	wakeup((caddr_t)&lbolt);	timeout(schedcpu, (void *)0, hz);}/* * We're only looking at 7 bits of the address; everything is * aligned to 4, lots of things are aligned to greater powers * of 2.  Shift right by 8, i.e. drop the bottom 256 worth. */#define TABLESIZE	128static TAILQ_HEAD(slpquehead, proc) slpque[TABLESIZE];#define LOOKUP(x)	(((intptr_t)(x) >> 8) & (TABLESIZE - 1))/* * During autoconfiguration or after a panic, a sleep will simply * lower the priority briefly to allow interrupts, then return. * The priority to be used (safepri) is machine-dependent, thus this * value is initialized and maintained in the machine-dependent layers. * This priority will typically be 0, or the lowest priority * that is safe for use on the interrupt stack; it can be made * higher to block network software interrupts after panics. */int safepri;/* * General sleep call.  Suspends the current process until a wakeup is * performed on the specified identifier.  The process will then be made * runnable with the specified priority.  Sleeps at most timo/hz seconds * (0 means no timeout).  If pri includes PCATCH flag, signals are checked * before and after sleeping, else signals are not checked.  Returns 0 if * awakened, EWOULDBLOCK if the timeout expires.  If PCATCH is set and a * signal needs to be delivered, ERESTART is returned if the current system * call should be restarted if possible, and EINTR is returned if the system * call should be interrupted by the signal (return EINTR). */inttsleep(ident, priority, wmesg, timo)	void *ident;	int priority, timo;	const char *wmesg;{	struct proc *p = curproc;	int s, catch = priority & PCATCH;	struct callout_handle thandle;	int interrupted;	s = splhigh();	KASSERT(p != NULL, ("tsleep1"));        KASSERT(ident != NULL && p->p_stat == SRUN, ("tsleep"));        /*         * 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;	/* We don't have these fields. */#ifndef OSKIT        p->p_slptime = 0;        p->p_priority = priority & PRIMASK;#endif        TAILQ_INSERT_TAIL(&slpque[LOOKUP(ident)], p, p_procq);        if (timo)                thandle = timeout(endtsleep, (void *)p, timo);	p->p_stat = SSLEEP;	p->p_stats->p_ru.ru_nvcsw++;	interrupted = OSKIT_FREEBSD_SLEEP(p);	if (interrupted)		unsleep(p);	splx(s);#if 0	p->p_flag &= ~P_SINTR;#endif	if (p->p_flag & P_TIMEOUT) {		p->p_flag &= ~P_TIMEOUT;		return (EWOULDBLOCK);	} else if (timo)		untimeout(endtsleep, (void *)p, thandle);	if (catch && interrupted)		return (EINTR);	return (0);}/* * Implement timeout for tsleep. * 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. */voidendtsleep(arg)	void *arg;{	register struct proc *p;	int s;	p = (struct proc *)arg;	s = splhigh();	if (p->p_wchan) {		if (p->p_stat == SSLEEP) {			unsleep(p);			p->p_stat = SRUN;			osenv_wakeup(&p->p_sr, OSENV_SLEEP_WAKEUP);		}		else			unsleep(p);		p->p_flag |= P_TIMEOUT;	}	splx(s);}#if 0/* * Short-term, non-interruptable sleep. */voidsleep(ident, priority)	void *ident;	int priority;{	register struct proc *p = curproc;	register struct slpque *qp;	register s;#ifdef DIAGNOSTIC	if (priority > PZERO) {		printf("sleep called with priority %d > PZERO, wchan: %p\n",		    priority, ident);		panic("old sleep");	}#endif	s = splhigh();	if (cold || panicstr) {		/*		 * After a panic, or during autoconfiguration,		 * just give interrupts a chance, then just return;		 * don't run any other procs or panic below,		 * in case this is the idle process and already asleep.		 */		splx(safepri);		splx(s);		return;	}#ifdef DIAGNOSTIC	if (ident == NULL || p->p_stat != SRUN || p->p_back)		panic("sleep");#endif	p->p_wchan = ident;	p->p_wmesg = NULL;	qp = &slpque[LOOKUP(ident)];	if (qp->sq_head == 0)		qp->sq_head = p;	else		*qp->sq_tailp = p;	*(qp->sq_tailp = &p->p_forw) = 0;	p->p_stat = SSLEEP;	p->p_stats->p_ru.ru_nvcsw++;	osenv_sleep(&p->p_sr);	splx(s);}#endif/* * Remove a process from its wait queue */voidunsleep(p)	register struct proc *p;{	int s;	s = splhigh();	if (p->p_wchan) {		TAILQ_REMOVE(&slpque[LOOKUP(p->p_wchan)], p, p_procq);		p->p_wchan = 0;	}	splx(s);}/* * Make all processes sleeping on the specified identifier runnable. */voidwakeup(ident)	register void *ident;{        register struct slpquehead *qp;        register struct proc *p;	int s;	s = splhigh();	qp = &slpque[LOOKUP(ident)];restart:        for (p = qp->tqh_first; p != NULL; p = p->p_procq.tqe_next) {                if (p->p_wchan == ident) {                        TAILQ_REMOVE(qp, p, p_procq);                        p->p_wchan = 0;                        if (p->p_stat == SSLEEP) {                                p->p_stat = SRUN;				osenv_wakeup(&p->p_sr, OSENV_SLEEP_WAKEUP);                                goto restart;                        }                }        }        splx(s);}/* * Make a process sleeping on the specified identifier runnable. * May wake more than one process if a target prcoess is currently * swapped out. */voidwakeup_one(ident)        register void *ident;{        register struct slpquehead *qp;        register struct proc *p;        int s;        s = splhigh();        qp = &slpque[LOOKUP(ident)];        for (p = qp->tqh_first; p != NULL; p = p->p_procq.tqe_next) {                if (p->p_wchan == ident) {                        TAILQ_REMOVE(qp, p, p_procq);                        p->p_wchan = 0;                        if (p->p_stat == SSLEEP) {                                p->p_stat = SRUN;				osenv_wakeup(&p->p_sr, OSENV_SLEEP_WAKEUP);                        }                }        }        splx(s);}voidsleepinit(){        int i;        for (i = 0; i < TABLESIZE; i++)                TAILQ_INIT(&slpque[i]);}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?