⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 except.c

📁 操作系统SunOS 4.1.3版本的源码
💻 C
📖 第 1 页 / 共 2 页
字号:
caddr_t(*exc_bound(pattern, env))()	register int pattern;	/* pattern bound to handler */	caddr_t *env;		/* environment to be returned to caller */{	register __queue_t *q;	register caddr_t (*func)();	CLR_ERROR();	LOCK();	q = FIRSTQ(&__Curproc->lwp_exchandles);	while ((q != QNULL) && (((exccontext_t *)q)->exc_pattern != pattern)) {		q = q->q_next;	}	if (q == QNULL) {		UNLOCK();		return (CFUNCNULL);	} else {		*env = (((exccontext_t *)q)->exc_env);		func = ((exccontext_t *)q)->exc_func;		UNLOCK();		return (func);	}}/*  * exc_notify() -- PRIMITIVE. * Utility for using excbound: if there is a non-null function * bound to the handler bound to "pattern", invoke it with the * bound argument. Otherwise, raise an exception with the pattern. * Returns two kinds of results: int for exc_raise (the pattern) or * anything (whatever the handler function returns). * The (int) cast is therefore only to make lint happy, not what really is * returned. */intexc_notify(pattern)	int pattern;{	register caddr_t (*func)();	caddr_t env;	CLR_ERROR();	func = exc_bound(pattern, &env);	if (func != CFUNCNULL)		return ((int)func(env));	else		return (exc_raise(pattern));}/* Do the real work of exc_raise with room above on the stack to work with */STATIC intexcraise(pattern)	int pattern;	/* pattern to match the one set by exc_handle() */{	register int *proc;	register exccontext_t *cntxt;	register int *c;	register int i;	int popcount = 0;	int *sp;	caddr_t (*func)();	caddr_t env;	int patt;	extern int __excreturn();	CLR_ERROR();	LOCK();	/* look for a match, but don't skip backout handlers */	for (cntxt = (exccontext_t *)FIRSTQ(&__Curproc->lwp_exchandles);	  cntxt != EXCNULL; cntxt = cntxt->exc_next) {		if ((cntxt->exc_pattern != pattern) && 		  (cntxt->exc_pattern != CATCHALL)) {			popcount++;	/* don't zap now in case no match */		} else {			break;		}	}	ERROR((cntxt == EXCNULL), LE_NONEXIST);	/* 	 * if last handler in a procedure and not an	 * exit handler, remove __exccleanup	 */	if ((cntxt->exc_refcnt == 0) && (cntxt->exc_pattern != EXITPATTERN)) {		*cntxt->exc_retaddr = cntxt->exc_return;	}	/*	 * alter the actual context so CSWTCH() will work.	 */	sp = (int *)cntxt->exc_regs[SP];	c = cntxt->exc_regs;	proc = __Curproc->lwp_context;	for (i = 0; i < MC_GENERALREGS; i++)		proc[i] = c[i];	/* 	 * we will push 3 things for __excreturn (see low.s) to use	 * so subtract 3 items:	 * __excreturn, pattern, return address.	 * __excreturn is the address to go to upon CSWTCH;	 * excpattern will be popped by __excreturn into d0,	 * and __excreturn will rts to exc_pc.	 * Important that pattern be on stack	 * since it could be lost in a global if	 * an asynchrouous event caused an exception to occur.	 */	__Curproc->lwp_context[SP] = (int)sp - (3 * sizeof (int));	*(--sp) = cntxt->exc_pc;	*(--sp) = pattern;	*(--sp) = (int) __excreturn;	/* destroy intervening contexts incl. this one */	for (i = 0; i <= popcount; i++) {		REM_QUEUE((exccontext_t *), &__Curproc->lwp_exchandles, cntxt);		func = cntxt->exc_func;		env = cntxt->exc_env;		patt = cntxt->exc_pattern;		FREECHUNK(ExcType, cntxt);		if (patt == EXITPATTERN) {			/*			 * Do exit handling en route to a handler above.			 * Note that we're on the client stack.			 * If excraise were implemented as a system call,			 * (i.e., on a sep. stack here),			 * should context switch to this context and			 * have the cleanup code reraise the exception			 * (int lwp_needreraise to hold pattern added to cntxt.)			 * UNLOCK so can call nugget cleanly (e.g., mon_exit).			 */			UNLOCK();			(void) (*func)(env);			LOCK();		}	}	/* now a normal context switch will put us in the handler context */	CSWTCH();	/* NOTREACHED */}/* * exc_raise() -- PRIMITIVE. * Raise an exception by searching for a matching handler, installing * its context in the process's context, and doing a context switch. * exc_raise will munge the stack starting with the point where * the exc_handle call was made. This could overwrite the stack * where exc_raise is executing, so we make a dummy procedure * call to guarantee room on the stack for exc_raise to execute safely. */intexc_raise(pattern)	int pattern;{	int dummy[EXCSTKSZ];#ifdef lint	dummy[0] = dummy[0];#endif lint	if ((pattern == EXITPATTERN) || (pattern == -1)) {		SET_ERROR(__Curproc, LE_INVALIDARG);		return (-1);	}	return (excraise(pattern));}/* * __exccleanup is an assembly language entry point * that is called when a procedure that established * one or more exception handlers returns. (it is called only once, * regardless of how many handlers the procedure set up). * It's function is to call exchelpclean(). * It must provide a way so it (__exccleanup) can return * a different place (the original procedure return point). * Note that exchelpclean() is called as a byproduct of the * original procedure returning normally so the stack and * registers are all as they should be. Thus, from the * point of view of the original procedure, it looks like * it called __exccleanup immediately upon return. * Finally, note that it's important that contexts are * NOT allocated on the stack since we would be clobbering * them with the locals, etc. here. We could get around * this by writing the whole thing in assembler, not calling * any procedures (including this helper procedure), and carefully * avoid messing with the stack. * However, in environments (e.g., sys V) where interrupts can't * be saved on an alternate stack, we could have interrupts * clobbering the stack (and thus any cntxt info) on the sly. */void__exchelpclean(){	register exccontext_t *cntxt = EXCNULL;	register int retloc;	register qheader_t *q = &__Curproc->lwp_exchandles;	register int *retaddr;	int patt;	caddr_t env;	int refcnt;	caddr_t (*func)();	CLR_ERROR();	LOCK();	/*	 * Discard all unused handlers (including CATCHALL).	 * Must be at least one, since we're here cleaning up.	 */	while (!ISEMPTYQ(q)) {		REM_QUEUE((exccontext_t *), q, cntxt);		func = cntxt->exc_func;		env = cntxt->exc_env;		patt = cntxt->exc_pattern;		refcnt = cntxt->exc_refcnt;		retaddr = cntxt->exc_retaddr;		retloc = cntxt->exc_return;		FREECHUNK(ExcType, cntxt);		if (patt == 0) {			UNLOCK();			(void) (*func)(env);			LOCK();		}		if (refcnt == 0)			break;	}	/* 	 * return address must be on stack so we don't	 * lose it (a global can be overwritten if not locked)	 * in case of an interrupt. exchelpclean() left room where	 * the original return address was for it to be restored.	 * We restore the original return address there, return to	 * __exccleanup to restore any registers used by exchelpclean(),	 * and then execute the original return.	 * At this point, we have the initial context (refcnt == 0)	 * to get the right return adddress from.	 */	*retaddr = retloc;	UNLOCK();}/* clean up any exception handlers held by a dying process */void__exceptcleanup(corpse)	lwp_t *corpse;{	register exccontext_t *cntxt;	while (!ISEMPTYQ(&corpse->lwp_exchandles)) {		REM_QUEUE((exccontext_t *), &corpse->lwp_exchandles, cntxt);		LWPTRACE(tr_EXCEPT, 1, ("freeing exception %x\n", cntxt));		FREECHUNK(ExcType, cntxt);	}}/* allocate a cache of exception contexts */void__init_exc(){	ExcType =	  __allocinit(sizeof (exccontext_t), NUMHANDLERS, IFUNCNULL, FALSE);}/* * What to do when a trap occurs. Called from low.s * If any sort of handler was established, raise the exception. * Otherwise, destroy the offending thread. */int__exc_trap(trapid)	int trapid;	/* UNIX signal causing trap */{	register caddr_t (*func)();	caddr_t env;	int result;	func = exc_bound(trapid, &env);	if (func != CFUNCNULL)		return ((int)func(env));	result = exc_raise(trapid);	if (result != -1) {		return (result);	} else {		(void)lwp_destroy(SELF);		/* NOTREACHED */	}}

⌨️ 快捷键说明

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