freebsd-dev/usr.bin/gprof/dfn.c
Warner Losh fbbd9655e5 Renumber copyright clause 4
Renumber cluase 4 to 3, per what everybody else did when BSD granted
them permission to remove clause 3. My insistance on keeping the same
numbering for legal reasons is too pedantic, so give up on that point.

Submitted by:	Jan Schaumann <jschauma@stevens.edu>
Pull Request:	https://github.com/freebsd/freebsd/pull/96
2017-02-28 23:42:47 +00:00

322 lines
7.9 KiB
C

/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* 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. 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.
*/
#if 0
#ifndef lint
static char sccsid[] = "@(#)dfn.c 8.1 (Berkeley) 6/6/93";
#endif /* not lint */
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <err.h>
#include "gprof.h"
#define DFN_DEPTH 100
struct dfnstruct {
nltype *nlentryp;
int cycletop;
};
typedef struct dfnstruct dfntype;
dfntype dfn_stack[ DFN_DEPTH ];
int dfn_depth;
int dfn_counter;
void
dfn_init(void)
{
dfn_depth = 0;
dfn_counter = DFN_NAN;
}
/*
* given this parent, depth first number its children.
*/
void
dfn(nltype *parentp)
{
arctype *arcp;
# ifdef DEBUG
if ( debug & DFNDEBUG ) {
printf( "[dfn] dfn(" );
printname( parentp );
printf( ")\n" );
}
# endif /* DEBUG */
/*
* if we're already numbered, no need to look any further.
*/
if ( dfn_numbered( parentp ) ) {
return;
}
/*
* if we're already busy, must be a cycle
*/
if ( dfn_busy( parentp ) ) {
dfn_findcycle( parentp );
return;
}
/*
* visit yourself before your children
*/
dfn_pre_visit( parentp );
/*
* visit children
*/
for ( arcp = parentp -> children ; arcp ; arcp = arcp -> arc_childlist ) {
if ( arcp -> arc_flags & DEADARC )
continue;
dfn( arcp -> arc_childp );
}
/*
* visit yourself after your children
*/
dfn_post_visit( parentp );
}
/*
* push a parent onto the stack and mark it busy
*/
void
dfn_pre_visit(nltype *parentp)
{
dfn_depth += 1;
if ( dfn_depth >= DFN_DEPTH )
errx( 1 , "[dfn] out of my depth (dfn_stack overflow)" );
dfn_stack[ dfn_depth ].nlentryp = parentp;
dfn_stack[ dfn_depth ].cycletop = dfn_depth;
parentp -> toporder = DFN_BUSY;
# ifdef DEBUG
if ( debug & DFNDEBUG ) {
printf( "[dfn_pre_visit]\t\t%d:" , dfn_depth );
printname( parentp );
printf( "\n" );
}
# endif /* DEBUG */
}
/*
* are we already numbered?
*/
bool
dfn_numbered(nltype *childp)
{
return ( childp -> toporder != DFN_NAN && childp -> toporder != DFN_BUSY );
}
/*
* are we already busy?
*/
bool
dfn_busy(nltype *childp)
{
if ( childp -> toporder == DFN_NAN ) {
return FALSE;
}
return TRUE;
}
/*
* MISSING: an explanation
*/
void
dfn_findcycle(nltype *childp)
{
int cycletop;
nltype *cycleheadp;
nltype *tailp;
int index;
for ( cycletop = dfn_depth ; cycletop > 0 ; cycletop -= 1 ) {
cycleheadp = dfn_stack[ cycletop ].nlentryp;
if ( childp == cycleheadp ) {
break;
}
if ( childp -> cyclehead != childp &&
childp -> cyclehead == cycleheadp ) {
break;
}
}
if ( cycletop <= 0 )
errx( 1 , "[dfn_findcycle] couldn't find head of cycle" );
# ifdef DEBUG
if ( debug & DFNDEBUG ) {
printf( "[dfn_findcycle] dfn_depth %d cycletop %d " ,
dfn_depth , cycletop );
printname( cycleheadp );
printf( "\n" );
}
# endif /* DEBUG */
if ( cycletop == dfn_depth ) {
/*
* this is previous function, e.g. this calls itself
* sort of boring
*/
dfn_self_cycle( childp );
} else {
/*
* glom intervening functions that aren't already
* glommed into this cycle.
* things have been glommed when their cyclehead field
* points to the head of the cycle they are glommed into.
*/
for ( tailp = cycleheadp ; tailp -> cnext ; tailp = tailp -> cnext ) {
/* void: chase down to tail of things already glommed */
# ifdef DEBUG
if ( debug & DFNDEBUG ) {
printf( "[dfn_findcycle] tail " );
printname( tailp );
printf( "\n" );
}
# endif /* DEBUG */
}
/*
* if what we think is the top of the cycle
* has a cyclehead field, then it's not really the
* head of the cycle, which is really what we want
*/
if ( cycleheadp -> cyclehead != cycleheadp ) {
cycleheadp = cycleheadp -> cyclehead;
# ifdef DEBUG
if ( debug & DFNDEBUG ) {
printf( "[dfn_findcycle] new cyclehead " );
printname( cycleheadp );
printf( "\n" );
}
# endif /* DEBUG */
}
for ( index = cycletop + 1 ; index <= dfn_depth ; index += 1 ) {
childp = dfn_stack[ index ].nlentryp;
if ( childp -> cyclehead == childp ) {
/*
* not yet glommed anywhere, glom it
* and fix any children it has glommed
*/
tailp -> cnext = childp;
childp -> cyclehead = cycleheadp;
# ifdef DEBUG
if ( debug & DFNDEBUG ) {
printf( "[dfn_findcycle] glomming " );
printname( childp );
printf( " onto " );
printname( cycleheadp );
printf( "\n" );
}
# endif /* DEBUG */
for ( tailp = childp ; tailp->cnext ; tailp = tailp->cnext ) {
tailp -> cnext -> cyclehead = cycleheadp;
# ifdef DEBUG
if ( debug & DFNDEBUG ) {
printf( "[dfn_findcycle] and its tail " );
printname( tailp -> cnext );
printf( " onto " );
printname( cycleheadp );
printf( "\n" );
}
# endif /* DEBUG */
}
} else if ( childp -> cyclehead != cycleheadp /* firewall */ ) {
fprintf( stderr ,
"[dfn_busy] glommed, but not to cyclehead\n" );
}
}
}
}
/*
* deal with self-cycles
* for lint: ARGSUSED
*/
void
dfn_self_cycle(nltype *parentp)
{
/*
* since we are taking out self-cycles elsewhere
* no need for the special case, here.
*/
# ifdef DEBUG
if ( debug & DFNDEBUG ) {
printf( "[dfn_self_cycle] " );
printname( parentp );
printf( "\n" );
}
# endif /* DEBUG */
}
/*
* visit a node after all its children
* [MISSING: an explanation]
* and pop it off the stack
*/
void
dfn_post_visit(nltype *parentp)
{
nltype *memberp;
# ifdef DEBUG
if ( debug & DFNDEBUG ) {
printf( "[dfn_post_visit]\t%d: " , dfn_depth );
printname( parentp );
printf( "\n" );
}
# endif /* DEBUG */
/*
* number functions and things in their cycles
* unless the function is itself part of a cycle
*/
if ( parentp -> cyclehead == parentp ) {
dfn_counter += 1;
for ( memberp = parentp ; memberp ; memberp = memberp -> cnext ) {
memberp -> toporder = dfn_counter;
# ifdef DEBUG
if ( debug & DFNDEBUG ) {
printf( "[dfn_post_visit]\t\tmember " );
printname( memberp );
printf( " -> toporder = %d\n" , dfn_counter );
}
# endif /* DEBUG */
}
} else {
# ifdef DEBUG
if ( debug & DFNDEBUG ) {
printf( "[dfn_post_visit]\t\tis part of a cycle\n" );
}
# endif /* DEBUG */
}
dfn_depth -= 1;
}