xref: /csrg-svn/sys/netiso/tp_timer.c (revision 51006)
149268Sbostic /*-
249268Sbostic  * Copyright (c) 1991 The Regents of the University of California.
349268Sbostic  * All rights reserved.
449268Sbostic  *
549268Sbostic  * %sccs.include.redist.c%
649268Sbostic  *
7*51006Ssklower  *	@(#)tp_timer.c	7.7 (Berkeley) 09/05/91
849268Sbostic  */
949268Sbostic 
1036415Ssklower /***********************************************************
1136415Ssklower 		Copyright IBM Corporation 1987
1236415Ssklower 
1336415Ssklower                       All Rights Reserved
1436415Ssklower 
1536415Ssklower Permission to use, copy, modify, and distribute this software and its
1636415Ssklower documentation for any purpose and without fee is hereby granted,
1736415Ssklower provided that the above copyright notice appear in all copies and that
1836415Ssklower both that copyright notice and this permission notice appear in
1936415Ssklower supporting documentation, and that the name of IBM not be
2036415Ssklower used in advertising or publicity pertaining to distribution of the
2136415Ssklower software without specific, written prior permission.
2236415Ssklower 
2336415Ssklower IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
2436415Ssklower ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
2536415Ssklower IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
2636415Ssklower ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
2736415Ssklower WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2836415Ssklower ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2936415Ssklower SOFTWARE.
3036415Ssklower 
3136415Ssklower ******************************************************************/
3236415Ssklower 
3336415Ssklower /*
3436415Ssklower  * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
3536415Ssklower  */
3636415Ssklower /*
3736415Ssklower  * ARGO TP
3836415Ssklower  *
3936415Ssklower  * $Header: tp_timer.c,v 5.2 88/11/18 17:29:07 nhall Exp $
4036415Ssklower  * $Source: /usr/argo/sys/netiso/RCS/tp_timer.c,v $
4136415Ssklower  *
4236415Ssklower  * Contains all the timer code.
4336415Ssklower  * There are two sources of calls to these routines:
4436415Ssklower  * the clock, and tp.trans. (ok, and tp_pcb.c calls it at init time)
4536415Ssklower  *
4636415Ssklower  * Timers come in two flavors - those that generally get
4736415Ssklower  * cancelled (tp_ctimeout, tp_cuntimeout)
4836415Ssklower  * and those that either usually expire (tp_etimeout,
4936415Ssklower  * tp_euntimeout, tp_slowtimo) or may require more than one instance
5036415Ssklower  * of the timer active at a time.
5136415Ssklower  *
5236415Ssklower  * The C timers are stored in the tp_ref structure. Their "going off"
5336415Ssklower  * is manifested by a driver event of the TM_xxx form.
5436415Ssklower  *
5536415Ssklower  * The E timers are handled like the generic kernel callouts.
5636415Ssklower  * Their "going off" is manifested by a function call w/ 3 arguments.
5736415Ssklower  */
5836415Ssklower 
5936415Ssklower #include "param.h"
6036415Ssklower #include "types.h"
6136415Ssklower #include "time.h"
6237469Ssklower #include "malloc.h"
6348752Ssklower #include "socket.h"
6436415Ssklower 
6537469Ssklower #include "tp_param.h"
6637469Ssklower #include "tp_timer.h"
6737469Ssklower #include "tp_stat.h"
6837469Ssklower #include "tp_pcb.h"
6937469Ssklower #include "tp_tpdu.h"
7037469Ssklower #include "argo_debug.h"
7137469Ssklower #include "tp_trace.h"
7237469Ssklower #include "tp_seq.h"
7336415Ssklower 
7448752Ssklower struct	Ecallout *TP_callfree;
7548752Ssklower struct	Ecallout *TP_callout;
7648752Ssklower struct	tp_ref *tp_ref;
7748752Ssklower int		N_TPREF = 100;
78*51006Ssklower struct	tp_refinfo tp_refinfo;
7936415Ssklower 
8036415Ssklower extern int tp_maxrefopen;  /* highest ref # of an open tp connection */
8136415Ssklower 
8236415Ssklower /*
8336415Ssklower  * CALLED FROM:
8436415Ssklower  *  at autoconfig time from tp_init()
8536415Ssklower  * 	a combo of event, state, predicate
8636415Ssklower  * FUNCTION and ARGUMENTS:
8736415Ssklower  *  initialize data structures for the timers
8836415Ssklower  */
8936415Ssklower void
9036415Ssklower tp_timerinit()
9136415Ssklower {
9248752Ssklower 	register struct Ecallout *e;
9348752Ssklower 	register int s;
9448752Ssklower #define GETME(x, t, n) {s = (n)*sizeof(*x); x = (t) malloc(s, M_PCB, M_NOWAIT);\
9548752Ssklower if (x == 0) panic("tp_timerinit"); bzero((caddr_t)x, s);}
9636415Ssklower 	/*
9748752Ssklower 	 * Initialize storage
9836415Ssklower 	 */
9948752Ssklower 	GETME(TP_callout, struct Ecallout *, 2 * N_TPREF);
10048752Ssklower 	GETME(tp_ref, struct tp_ref *, 1 +  N_TPREF);
101*51006Ssklower 	tp_refinfo.tpr_base = tp_ref;
102*51006Ssklower 	tp_refinfo.tpr_size = N_TPREF;  /* XXX: There will be a better way */
10336415Ssklower 
10448752Ssklower 	TP_callfree = TP_callout + ((2 * N_TPREF) - 1);
10548752Ssklower 	for (e = TP_callfree; e > TP_callout; e--)
10648752Ssklower 		e->c_next = e - 1;
10736415Ssklower 
10836415Ssklower 	/* hate to do this but we really don't want zero to be a legit ref */
10936415Ssklower 	tp_maxrefopen = 1;
11036415Ssklower 	tp_ref[0].tpr_state = REF_FROZEN;  /* white lie -- no ref timer, don't
11136415Ssklower 		* want this one to be allocated- ever
11236415Ssklower 		* unless, of course, you make refs and address instead of an
11336415Ssklower 		* index - then 0 can be allocated
11436415Ssklower 		*/
11548752Ssklower #undef GETME
11636415Ssklower }
11736415Ssklower 
11836415Ssklower /**********************  e timers *************************/
11936415Ssklower 
12036415Ssklower /*
12136415Ssklower  * CALLED FROM:
12236415Ssklower  *  tp_slowtimo() every 1/2 second, for each open reference
12336415Ssklower  * FUNCTION and ARGUMENTS:
12436415Ssklower  *  (refp) indicates a reference structure that is in use.
12536415Ssklower  *  This ref structure may contain active E-type timers.
12636415Ssklower  *  Update the timers and if any expire, create an event and
12736415Ssklower  *  call the driver.
12836415Ssklower  */
12936415Ssklower static void
13036415Ssklower tp_Eclock(refp)
13136415Ssklower 	struct tp_ref	*refp; /* the reference structure */
13236415Ssklower {
13336415Ssklower 	register struct Ecallout *p1; /* to drift through the list of callouts */
13436415Ssklower 	struct tp_event			 E; /* event to pass to tp_driver() */
13536415Ssklower 	int						 tp_driver(); /* drives the FSM */
13636415Ssklower 
13736415Ssklower 	/*
13836415Ssklower 	 * Update real-time timeout queue.
13936415Ssklower 	 * At front of queue are some number of events which are ``due''.
14036415Ssklower 	 * The time to these is <= 0 and if negative represents the
14136415Ssklower 	 * number of ticks which have passed since it was supposed to happen.
14236415Ssklower 	 * The rest of the q elements (times > 0) are events yet to happen,
14336415Ssklower 	 * where the time for each is given as a delta from the previous.
14436415Ssklower 	 * Decrementing just the first of these serves to decrement the time
14536415Ssklower 	 * to all events.
14636415Ssklower 	 *
14736415Ssklower 	 * This version, which calls the driver directly, doesn't pass
14836415Ssklower 	 * along the ticks - may want to add the ticks if there's any use
14936415Ssklower 	 * for them.
15036415Ssklower 	 */
15136415Ssklower 	IncStat(ts_Eticks);
15236415Ssklower 	p1 = refp->tpr_calltodo.c_next;
15336415Ssklower 	while (p1) {
15436415Ssklower 		if (--p1->c_time > 0)
15536415Ssklower 			break;
15636415Ssklower 		if (p1->c_time == 0)
15736415Ssklower 			break;
15836415Ssklower 		p1 = p1->c_next;
15936415Ssklower 	}
16036415Ssklower 
16136415Ssklower 	for (;;) {
16237469Ssklower 		struct tp_pcb *tpcb;
16336415Ssklower 		if ((p1 = refp->tpr_calltodo.c_next) == 0 || p1->c_time > 0) {
16436415Ssklower 			break;
16536415Ssklower 		}
16636415Ssklower 		refp->tpr_calltodo.c_next = p1->c_next;
16736415Ssklower 		p1->c_next = TP_callfree;
16836415Ssklower 
16936415Ssklower #ifndef lint
17036415Ssklower 		E.ev_number = p1->c_func;
17136415Ssklower 		E.ATTR(TM_data_retrans).e_low = (SeqNum) p1->c_arg1;
17236415Ssklower 		E.ATTR(TM_data_retrans).e_high = (SeqNum) p1->c_arg2;
17336415Ssklower 		E.ATTR(TM_data_retrans).e_retrans =  p1->c_arg3;
17436415Ssklower #endif lint
17536415Ssklower 		IFDEBUG(D_TIMER)
17636415Ssklower 			printf("E expired! event 0x%x (0x%x,0x%x), pcb 0x%x ref %d\n",
17736415Ssklower 				p1->c_func, p1->c_arg1, p1->c_arg2, refp->tpr_pcb,
17836415Ssklower 				refp-tp_ref);
17936415Ssklower 		ENDDEBUG
18036415Ssklower 
18136415Ssklower 		TP_callfree = p1;
18236415Ssklower 		IncStat(ts_Eexpired);
18337469Ssklower 		(void) tp_driver( tpcb = refp->tpr_pcb, &E);
18450940Ssklower 		if (p1->c_func == TM_reference && tpcb->tp_state == TP_CLOSED) {
18550940Ssklower 			if (tpcb->tp_notdetached) {
18650940Ssklower 				IFDEBUG(D_CONN)
18750940Ssklower 					printf("PRU_DETACH: not detached\n");
18850940Ssklower 				ENDDEBUG
18950940Ssklower 				tp_detach(tpcb);
19050940Ssklower 			}
19137469Ssklower 			free((caddr_t)tpcb, M_PCB); /* XXX wart; where else to do it? */
19250940Ssklower 		}
19336415Ssklower 	}
19436415Ssklower }
19536415Ssklower 
19636415Ssklower /*
19736415Ssklower  * CALLED FROM:
19836415Ssklower  *  tp.trans all over
19936415Ssklower  * FUNCTION and ARGUMENTS:
20036415Ssklower  * Set an E type timer.  (refp) is the ref structure.
20136415Ssklower  * Causes  fun(arg1,arg2,arg3) to be called after time t.
20236415Ssklower  */
20336415Ssklower void
20436415Ssklower tp_etimeout(refp, fun, arg1, arg2, arg3, ticks)
20536415Ssklower 	struct tp_ref	*refp;
20636415Ssklower 	int 			fun; 	/* function to be called */
20736415Ssklower 	u_int			arg1, arg2;
20836415Ssklower 	int				arg3;
20936415Ssklower 	register int	ticks;
21036415Ssklower {
21136415Ssklower 	register struct Ecallout *p1, *p2, *pnew;
21236415Ssklower 		/* p1 and p2 drift through the list of timeout callout structures,
21336415Ssklower 		 * pnew points to the newly created callout structure
21436415Ssklower 		 */
21536415Ssklower 
21636415Ssklower 	IFDEBUG(D_TIMER)
21736415Ssklower 		printf("etimeout pcb 0x%x state 0x%x\n", refp->tpr_pcb,
21836415Ssklower 		refp->tpr_pcb->tp_state);
21936415Ssklower 	ENDDEBUG
22036415Ssklower 	IFTRACE(D_TIMER)
22136415Ssklower 		tptrace(TPPTmisc, "tp_etimeout ref refstate tks Etick", refp-tp_ref,
22236415Ssklower 		refp->tpr_state, ticks, tp_stat.ts_Eticks);
22336415Ssklower 	ENDTRACE
22436415Ssklower 
22536415Ssklower 	IncStat(ts_Eset);
22636415Ssklower 	if (ticks == 0)
22736415Ssklower 		ticks = 1;
22836415Ssklower 	pnew = TP_callfree;
22936415Ssklower 	if (pnew == (struct Ecallout *)0)
23036415Ssklower 		panic("tp timeout table overflow");
23136415Ssklower 	TP_callfree = pnew->c_next;
23236415Ssklower 	pnew->c_arg1 = arg1;
23336415Ssklower 	pnew->c_arg2 = arg2;
23436415Ssklower 	pnew->c_arg3 = arg3;
23536415Ssklower 	pnew->c_func = fun;
23636415Ssklower 	for (p1 = &(refp->tpr_calltodo);
23736415Ssklower 							(p2 = p1->c_next) && p2->c_time < ticks; p1 = p2)
23836415Ssklower 		if (p2->c_time > 0)
23936415Ssklower 			ticks -= p2->c_time;
24036415Ssklower 	p1->c_next = pnew;
24136415Ssklower 	pnew->c_next = p2;
24236415Ssklower 	pnew->c_time = ticks;
24336415Ssklower 	if (p2)
24436415Ssklower 		p2->c_time -= ticks;
24536415Ssklower }
24636415Ssklower 
24736415Ssklower /*
24836415Ssklower  * CALLED FROM:
24936415Ssklower  *  tp.trans all over
25036415Ssklower  * FUNCTION and ARGUMENTS:
25136415Ssklower  *  Cancel all occurrences of E-timer function (fun) for reference (refp)
25236415Ssklower  */
25336415Ssklower void
25436415Ssklower tp_euntimeout(refp, fun)
25536415Ssklower 	struct tp_ref *refp;
25636415Ssklower 	int			  fun;
25736415Ssklower {
25836415Ssklower 	register struct Ecallout *p1, *p2; /* ptrs to drift through the list */
25936415Ssklower 
26036415Ssklower 	IFTRACE(D_TIMER)
26136415Ssklower 		tptrace(TPPTmisc, "tp_euntimeout ref", refp-tp_ref, 0, 0, 0);
26236415Ssklower 	ENDTRACE
26336415Ssklower 
26436415Ssklower 	p1 = &refp->tpr_calltodo;
26536415Ssklower 	while ( (p2 = p1->c_next) != 0) {
26636415Ssklower 		if (p2->c_func == fun)  {
26736415Ssklower 			if (p2->c_next && p2->c_time > 0)
26836415Ssklower 				p2->c_next->c_time += p2->c_time;
26936415Ssklower 			p1->c_next = p2->c_next;
27036415Ssklower 			p2->c_next = TP_callfree;
27136415Ssklower 			TP_callfree = p2;
27236415Ssklower 			IncStat(ts_Ecan_act);
27336415Ssklower 			continue;
27436415Ssklower 		}
27536415Ssklower 		p1 = p2;
27636415Ssklower 	}
27736415Ssklower }
27836415Ssklower 
27936415Ssklower /*
28036415Ssklower  * CALLED FROM:
28136415Ssklower  *  tp.trans, when an incoming ACK causes things to be dropped
28236415Ssklower  *  from the retransmission queue, and we want their associated
28336415Ssklower  *  timers to be cancelled.
28436415Ssklower  * FUNCTION and ARGUMENTS:
28536415Ssklower  *  cancel all occurrences of function (fun) where (arg2) < (seq)
28636415Ssklower  */
28736415Ssklower void
28836415Ssklower tp_euntimeout_lss(refp, fun, seq)
28936415Ssklower 	struct tp_ref *refp;
29036415Ssklower 	int			  fun;
29136415Ssklower 	SeqNum		  seq;
29236415Ssklower {
29336415Ssklower 	register struct Ecallout *p1, *p2;
29436415Ssklower 
29536415Ssklower 	IFTRACE(D_TIMER)
29636415Ssklower 		tptrace(TPPTmisc, "tp_euntimeoutLSS ref", refp-tp_ref, seq, 0, 0);
29736415Ssklower 	ENDTRACE
29836415Ssklower 
29936415Ssklower 	p1 = &refp->tpr_calltodo;
30036415Ssklower 	while ( (p2 = p1->c_next) != 0) {
30136415Ssklower 		if ((p2->c_func == fun) && SEQ_LT(refp->tpr_pcb, p2->c_arg2, seq))  {
30236415Ssklower 			if (p2->c_next && p2->c_time > 0)
30336415Ssklower 				p2->c_next->c_time += p2->c_time;
30436415Ssklower 			p1->c_next = p2->c_next;
30536415Ssklower 			p2->c_next = TP_callfree;
30636415Ssklower 			TP_callfree = p2;
30736415Ssklower 			IncStat(ts_Ecan_act);
30836415Ssklower 			continue;
30936415Ssklower 		}
31036415Ssklower 		p1 = p2;
31136415Ssklower 	}
31236415Ssklower }
31336415Ssklower 
31436415Ssklower /****************  c timers **********************
31536415Ssklower  *
31636415Ssklower  * These are not chained together; they sit
31736415Ssklower  * in the tp_ref structure. they are the kind that
31836415Ssklower  * are typically cancelled so it's faster not to
31936415Ssklower  * mess with the chains
32036415Ssklower  */
32136415Ssklower 
32236415Ssklower /*
32336415Ssklower  * CALLED FROM:
32436415Ssklower  *  the clock, every 500 ms
32536415Ssklower  * FUNCTION and ARGUMENTS:
32636415Ssklower  *  Look for open references with active timers.
32736415Ssklower  *  If they exist, call the appropriate timer routines to update
32836415Ssklower  *  the timers and possibly generate events.
32936415Ssklower  *  (The E timers are done in other procedures; the C timers are
33036415Ssklower  *  updated here, and events for them are generated here.)
33136415Ssklower  */
33236415Ssklower ProtoHook
33336415Ssklower tp_slowtimo()
33436415Ssklower {
33536415Ssklower 	register int 		r,t;
33636415Ssklower 	struct Ccallout 	*cp;
33736415Ssklower 	struct tp_ref		*rp = tp_ref;
33836415Ssklower 	struct tp_event		E;
33936415Ssklower 	int 				s = splnet();
34036415Ssklower 
34136415Ssklower 	/* check only open reference structures */
34236415Ssklower 	IncStat(ts_Cticks);
34336415Ssklower 	rp++;	/* tp_ref[0] is never used */
34436415Ssklower 	for(  r=1 ; (r <= tp_maxrefopen) ; r++,rp++ ) {
34536415Ssklower 		if (rp->tpr_state < REF_OPEN)
34636415Ssklower 			continue;
34736415Ssklower 
34836415Ssklower 		/* check the C-type timers */
34936415Ssklower 		cp = rp->tpr_callout;
35036415Ssklower 		for (t=0 ; t < N_CTIMERS; t++,cp++) {
35136415Ssklower 			if( cp->c_active ) {
35236415Ssklower 				if( --cp->c_time <= 0 ) {
35336415Ssklower 					cp->c_active = FALSE;
35436415Ssklower 					E.ev_number = t;
35536415Ssklower 					IFDEBUG(D_TIMER)
35636415Ssklower 						printf("C expired! type 0x%x\n", t);
35736415Ssklower 					ENDDEBUG
35836415Ssklower 					IncStat(ts_Cexpired);
35936415Ssklower 					tp_driver( rp->tpr_pcb, &E);
36036415Ssklower 				}
36136415Ssklower 			}
36236415Ssklower 		}
36336415Ssklower 		/* now update the list */
36436415Ssklower 		tp_Eclock(rp);
36536415Ssklower 	}
36636415Ssklower 	splx(s);
36736415Ssklower 	return 0;
36836415Ssklower }
36936415Ssklower 
37036415Ssklower /*
37136415Ssklower  * CALLED FROM:
37236415Ssklower  *  tp.trans, tp_emit()
37336415Ssklower  * FUNCTION and ARGUMENTS:
37436415Ssklower  * 	Set a C type timer of type (which) to go off after (ticks) time.
37536415Ssklower  */
37636415Ssklower void
37736415Ssklower tp_ctimeout(refp, which, ticks)
37836415Ssklower 	register struct tp_ref	*refp;
37936415Ssklower 	int 					which, ticks;
38036415Ssklower {
38136415Ssklower 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
38236415Ssklower 
38336415Ssklower 	IFTRACE(D_TIMER)
38436415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout ref which tpcb active",
38536415Ssklower 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active);
38636415Ssklower 	ENDTRACE
38736415Ssklower 	if(cp->c_active)
38836415Ssklower 		IncStat(ts_Ccan_act);
38936415Ssklower 	IncStat(ts_Cset);
39036415Ssklower 	cp->c_time = ticks;
39136415Ssklower 	cp->c_active = TRUE;
39236415Ssklower }
39336415Ssklower 
39436415Ssklower /*
39536415Ssklower  * CALLED FROM:
39636415Ssklower  *  tp.trans
39736415Ssklower  * FUNCTION and ARGUMENTS:
39836415Ssklower  * 	Version of tp_ctimeout that resets the C-type time if the
39936415Ssklower  * 	parameter (ticks) is > the current value of the timer.
40036415Ssklower  */
40136415Ssklower void
40236415Ssklower tp_ctimeout_MIN(refp, which, ticks)
40336415Ssklower 	register struct tp_ref	*refp;
40436415Ssklower 	int						which, ticks;
40536415Ssklower {
40636415Ssklower 	register struct Ccallout *cp = &(refp->tpr_callout[which]);
40736415Ssklower 
40836415Ssklower 	IFTRACE(D_TIMER)
40936415Ssklower 		tptrace(TPPTmisc, "tp_ctimeout_MIN ref which tpcb active",
41036415Ssklower 			(int)(refp - tp_ref), which, refp->tpr_pcb, cp->c_active);
41136415Ssklower 	ENDTRACE
41236415Ssklower 	if(cp->c_active)
41336415Ssklower 		IncStat(ts_Ccan_act);
41436415Ssklower 	IncStat(ts_Cset);
41536415Ssklower 	if( cp->c_active )
41636415Ssklower 		cp->c_time = MIN(ticks, cp->c_time);
41736415Ssklower 	else  {
41836415Ssklower 		cp->c_time = ticks;
41936415Ssklower 		cp->c_active = TRUE;
42036415Ssklower 	}
42136415Ssklower }
42236415Ssklower 
42336415Ssklower /*
42436415Ssklower  * CALLED FROM:
42536415Ssklower  *  tp.trans
42636415Ssklower  * FUNCTION and ARGUMENTS:
42736415Ssklower  *  Cancel the (which) timer in the ref structure indicated by (refp).
42836415Ssklower  */
42936415Ssklower void
43036415Ssklower tp_cuntimeout(refp, which)
43136415Ssklower 	int						which;
43236415Ssklower 	register struct tp_ref	*refp;
43336415Ssklower {
43436415Ssklower 	register struct Ccallout *cp;
43536415Ssklower 
43636415Ssklower 	cp = &(refp->tpr_callout[which]);
43736415Ssklower 
43836415Ssklower 	IFDEBUG(D_TIMER)
43937469Ssklower 		printf("tp_cuntimeout(0x%x, %d) active %d\n", refp, which, cp->c_active);
44036415Ssklower 	ENDDEBUG
44136415Ssklower 
44236415Ssklower 	IFTRACE(D_TIMER)
44336415Ssklower 		tptrace(TPPTmisc, "tp_cuntimeout ref which, active", refp-tp_ref,
44436415Ssklower 			which, cp->c_active, 0);
44536415Ssklower 	ENDTRACE
44636415Ssklower 
44736415Ssklower 	if(cp->c_active)
44836415Ssklower 		IncStat(ts_Ccan_act);
44936415Ssklower 	else
45036415Ssklower 		IncStat(ts_Ccan_inact);
45136415Ssklower 	cp->c_active = FALSE;
45236415Ssklower }
453