windows-nt/Source/XPSP1/NT/tools/postbuildscripts/pbuild.cmd
2020-09-26 16:20:57 +08:00

934 lines
27 KiB
Batchfile

@echo off
REM ------------------------------------------------------------------
REM
REM pbuild.cmd
REM Drives postbuild using information in pbuild.dat
REM
REM Copyright (c) Microsoft Corporation. All rights reserved.
REM
REM ------------------------------------------------------------------
perl -x "%~f0" %*
goto :EOF
#!perl
use strict;
use lib $ENV{RAZZLETOOLPATH} . "\\PostBuildScripts";
use lib $ENV{RAZZLETOOLPATH};
use PbuildEnv;
use ParseArgs;
use Logmsg;
sub Usage { print<<USAGE; exit(1) }
Pbuild [-d <datafile>] [-l <language>]
-d datafile Use <datafile> instead of pbuild.dat
This program processes a pbuild.dat file and issues the appropriate commands
in a multithreaded manner to run all or some of the postbuild process.
USAGE
my $PrivateDataFile;
parseargs('?' => \&Usage,
'd:'=> \$PrivateDataFile);
# Global variable section
my( $PBS ) = $ENV{ "RazzleToolPath" } . "\\PostBuildScripts";
my( $AmOfficial ) = $ENV{ "OFFICIAL_BUILD_MACHINE" };
my( $IsCoverageBuild ) = $ENV{ "_COVERAGE_BUILD" };
my( $MaxThreads ) = $ENV{ "NUMBER_OF_PROCESSORS" };
my( $Language ) = $ENV{ "lang" };
my( $HorsePower ) = $ENV{ "HORSE_POWER" };
my( $Comp ) = $ENV{ "COMP" };
my( $NumProcs ) = $ENV{ "NUMBER_OF_PROCESSORS" };
my( $MainBuildLab ) = $ENV{ "MAIN_BUILD_LAB_MACHINE" };
my( $IntelMachine ) = $ENV{ "x86" };
my( $Bit32 ) ;
my( $Bit64 );
if ( $ENV{ "_BuildArch" } =~ /x86/i ) { $Bit32 = "TRUE"; }
if ( $ENV{ "_BuildArch" } =~ /amd64|ia64/i ) { $Bit64 = "TRUE"; }
my( $NReqType ) = 0;
my( $NNeedToDo ) = 1;
my( $NInstance ) = 2;
my( $NCommand ) = 3;
my( $NOptions ) = 4;
# declare globals
my( $ExitCode, $Return, $AmIncremental );
my( @Requests, @EndList, $TimingFile, %HelpMessages );
# zeroth: init vars
&InitializeVariables();
# first: parse the data file
my( $DataFileName );
if ( defined( $PrivateDataFile ) ) {
$DataFileName = $PrivateDataFile;
} else {
$DataFileName = $PBS . "\\pbuild.dat";
}
$Return = &ParseDataFile( $DataFileName );
if ( $Return eq "FATAL" ) { goto QuitNow; }
# debug: show the request list
if ( $Logmsg::DEBUG ) { &DebugOnly(); }
# second: kick off all the stuff we need to do
$Return = &RunCommands();
if ( $Return eq "FATAL" ) { goto QuitNow; }
# last: display some interesting statistics
print( "\n" );
if ( -e $TimingFile ) { system( "type $TimingFile" ); }
# exit gracefully, if using a goto is your idea of graceful
QuitNow:
exit;
#
# DebugOnly
#
# Arguments: variable
#
# Purpose: a general routine for holding lots of debug code that can easily
# be turned off
#
sub DebugOnly
{
# get passed args
# my( $FooBar ) = @_;
# declare locals
my( $Request );
# dbgmsg( "In subroutine DebugOnly ..." );
# dbgmsg( "Request list is:" );
foreach $Request ( @Requests ) {
# dbgmsg( "$Request" );
}
# dbgmsg( "End of request list." );
}
#
# InitializeVariables
#
# Arguments: none
#
# Purpose: just set up the initial vars in the way we need them.
# nothing fancy.
#
# Returns: nothing
#
sub InitializeVariables
{
# declare locals
my( $HelpFile, @HelpLines, $Command, $HelpText, $Line );
my( $IncFile );
# dbgmsg( "In subroutine InitializeVariables ..." );
# check for incremental builds
undef( $AmIncremental );
$IncFile = $ENV{ "_NTPostBld" } . "\\congeal_scripts\\firstpass.txt";
if ( ! ( -e $IncFile ) ) {
$AmIncremental = "TRUE";
}
# init setup stuff
#$Logmsg::DEBUG = 1; # set to 1 to activate logging of dbgmsg's
$TimingFile = $ENV{logfile} . ".timing.log";
if ( -e $TimingFile ) { system( "del /f $TimingFile" ); }
$ExitCode = 0;
# Set maxthreads equal to numprocs * horse_power
if ( $HorsePower ) {
$MaxThreads = $NumProcs * $HorsePower;
} else {
$MaxThreads = $NumProcs * 4;
}
# read in the help message file
$HelpFile = $ENV{ "RazzleToolPath" } . "\\PostBuildScripts\\pbuild.hlp";
unless ( open( INFILE, $HelpFile ) ) {
wrnmsg( "Failed to open help file." );
goto PastHelpFile;
}
@HelpLines = <INFILE>;
close( INFILE );
foreach $Line ( @HelpLines ) {
chomp( $Line );
( $Command, $HelpText ) = split( /\s+\:\s+/, $Line );
if ( $Command =~ /.*\\([^\\]+?)$/ ) { $Command = $1; }
$Command = "\L$Command";
$HelpMessages{ $Command } = $HelpText;
# dbgmsg( "Help Message for '$Command' : $HelpMessages{ $Command }" );
}
PastHelpFile:
return;
}
#
# ParseDataFile
#
# Arguments: $DataFileName
#
# Purpose: read in the given data file, and figure out what requests we will
# need to run on this machine, storing the resultant requests in
# @Requests.
#
# Returns: nothing
#
sub ParseDataFile
{
# get passed args
my( $DataFileName ) = @_;
# declare locals
my( @DataLines, $Line );
my( $ThisReqType, $ThisCommand, $ThisOptions, $ShortName );
my( $NewRequest, $Request, $FoundBegin, $ThisShortName );
# dbgmsg( "In subroutine ParseDataFile ..." );
unless ( open( INFILE, $DataFileName ) ) {
errmsg( "ParseDataFile:" );
errmsg( "Failed to open $DataFileName for reading." );
$ExitCode++;
return( "FATAL" );
}
@DataLines = <INFILE>;
close( INFILE );
foreach $Line ( @DataLines ) {
chomp( $Line );
# see if this is a real line
if ( ( length( $Line ) == 0 ) || ( $Line =~ /^\;/ ) ) { next; }
# get the interesting info out of the file line
( $ThisReqType, $ThisCommand, $ThisOptions ) = split( /\s/, $Line, 3 );
# first things first, see if we need to do this one
if ( ( $ThisReqType =~ /OFFICIAL/i ) &&
( ! defined( $AmOfficial ) ) ) {
# dbgmsg( "Not official, skipping $Line ..." );
next;
}
if ( ( $ThisReqType =~ /INCREMENTAL/i ) &&
( $AmIncremental ne "TRUE" ) ) {
dbgmsg( "Not incremental pass, skipping $Line ..." );
next;
}
# check our full pass file and first pass file
my( $FullPassFile ) = $ENV{ "_NTPOSTBLD" } . "\\build_logs\\FullPass.txt";
my( $FirstPassFile ) = $ENV{ "_NTPOSTBLD" } . "\\congeal_scripts\\FirstPass.txt";
if ( ( $ThisReqType =~ /FULL/i ) &&
( ! -e $FullPassFile ) &&
( ! -e $FirstPassFile ) ) {
dbgmsg( "Not full pass, skipping $Line ..." );
next;
}
if ( ( $ThisReqType =~ /COVERAGE/i ) &&
( ! defined ( $IsCoverageBuild ) ) ) {
dbgmsg( "Not coverage build, skipping $Line ..." );
next;
}
if ( ( $ThisReqType =~ /MAIN/i ) &&
( ! defined( $MainBuildLab ) ) ) {
dbgmsg( "Not main build lab, skipping $Line ..." );
next;
}
if ( ( $ThisReqType =~ /COMP/i ) &&
( $Comp !~ /yes/i ) ) {
# dbgmsg( "COMP not set, skipping $Line ..." );
next;
}
if ( ( $ThisReqType =~ /INTEL/i ) &&
( ! defined( $IntelMachine ) ) ) {
dbgmsg( "Not intel machine, skipping $Line ..." );
next;
}
if ( ( $ThisReqType =~ /32/i ) &&
( ! defined( $Bit32 ) ) ) {
dbgmsg( "Not 32bit machine, skipping $Line ..." );
next;
}
if ( ( $ThisReqType =~ /64/i ) &&
( ! defined( $Bit64 ) ) ) {
dbgmsg( "Not 64bit machine, skipping $Line ..." );
next;
}
# now, if we passed all parameters, our req type will be begin
if ( ( $ThisReqType !~ /checkfatal/i ) &&
( $ThisReqType !~ /END/i ) ) {
$ThisReqType = "BEGIN";
}
# create the short name of the command for instance counting
if ( $ThisCommand =~ /.*\\([^\\]+?)$/ ) { $ShortName = $1; }
else { $ShortName = $ThisCommand; }
# begin populating the new request
# start with the request type and the NeedToDo
$NewRequest = "\U$ThisReqType\:t\:";
# tack on the unique identifier
$NewRequest .= &GetNextInstanceNumber( $ShortName, $ThisReqType ) .
":";
# tack on the command and the options
$NewRequest .= $ThisCommand . ":" . $ThisOptions;
# now, if this is an /END/ request, make sure the associated /BEGIN/
# is in our requests
if ( $ThisReqType =~ /END/i ) {
undef( $FoundBegin );
foreach $Request ( @Requests ) {
$ThisShortName = &GetField( $Request, $NCommand );
if ( $ThisShortName =~ /.*\\([^\\]+?)$/ ) {
$ThisShortName = $1;
}
if ( ( "\L$ShortName" eq "\L$ThisShortName" ) &&
( &GetField( $Request, $NReqType ) =~ /BEGIN/i ) ) {
$FoundBegin = "TRUE";
}
}
if ( ! defined( $FoundBegin ) ) {
next;
}
}
# finally, add the request to the list
push( @Requests, $NewRequest );
}
}
#
# GetNextInstanceNumber
#
# Arguments: $CommandName, $ReqType
#
# Purpose: this routine will return a unique number for this instance of the
# called command. e.g. if the data file calls crypto.cmd 4 times, and
# we're processing the third one, this should return 2, as the first
# returned 0 and the second returned 1.
#
sub GetNextInstanceNumber
{
# get passed args
my( $CommandName, $ReqType ) = @_;
# declare locals
my( $Request, $Count, $LongName, $ShortName );
# dbgmsg( "In subroutine GetNextInstanceNumber ..." );
# get the command name in the right syntax
if ( $CommandName =~ /.*\\([^\\]+?)$/ ) { $CommandName = $1; }
# make the actual count of commands with this name
$Count = 0;
foreach $Request ( @Requests ) {
if ( &GetField( $Request, $NReqType ) !~ /$ReqType/i ) { next; }
$LongName = &GetField( $Request, $NCommand );
if ( $LongName =~ /.*\\([^\\]+?)$/ ) { $ShortName = $1; }
else { $ShortName = $LongName; }
if ( "\L$ShortName" eq "\L$CommandName" ) {
$Count++;
}
}
# return the unique identifier
return( $Count );
}
#
# GetField
#
# Arguments: $Request, $FieldNumber
#
# Purpose: a simple sub to return the requested field from the given request.
# this is just to abstract the actual data structure from the data.
#
sub GetField
{
# get passed args
my( $Request, $FieldNumber ) = @_;
# declare locals
my( $ReqType, $NeedToDo, $Instance, $Command, $Options );
# take out the dbgmsg here, just too much spew
# dbgmsg( "In subroutine GetField ..." );
( $ReqType, $NeedToDo, $Instance, $Command, $Options ) =
split( /\:/, $Request, 5 );
if ( $FieldNumber == $NReqType ) { return $ReqType; }
if ( $FieldNumber == $NNeedToDo ) { return $NeedToDo; }
if ( $FieldNumber == $NInstance ) { return $Instance; }
if ( $FieldNumber == $NCommand ) { return $Command; }
if ( $FieldNumber == $NOptions ) { return $Options; }
# if none of the above apply, return undef
return( undef );
}
#
# MakeNewRequest
#
# Arguments: $Request, $FieldNumber, $Value
#
# Purpose: a simple sub to return a new request with the requested field for
# the given request set to the specified value. this is just to
# abstract the actual data structure from the data.
#
# Returns: the new request
#
sub MakeNewRequest
{
# get passed args
my( $Request, $FieldNumber, $Value ) = @_;
# declare locals
my( $ReqType, $NeedToDo, $Instance, $Command, $Options, $NewRequest );
# dbgmsg( "In subroutine MakeNewRequest ..." );
( $ReqType, $NeedToDo, $Instance, $Command, $Options ) =
split( /\:/, $Request, 5 );
if ( $FieldNumber == $NReqType ) { $ReqType = $Value; }
if ( $FieldNumber == $NNeedToDo ) { $NeedToDo = $Value; }
if ( $FieldNumber == $NInstance ) { $Instance = $Value; }
if ( $FieldNumber == $NCommand ) { $Command = $Value; }
if ( $FieldNumber == $NOptions ) { $Options = $Value; }
$NewRequest = "$ReqType:$NeedToDo:$Instance:$Command:$Options";
return( $NewRequest )
}
#
# RunCommands
#
# Arguments: none
#
# Purpose: this routine cycles over the requests from the data file and makes
# the judgement calls for when to kick things off or not. this logic
# is determined by the HORSE_POWER environment variable and the
# number of processors available.
#
# Returns: nothing
#
sub RunCommands
{
# declare locals
my( $Request, $ThreadCount, $NumThreads, $NumKill );
my( $LongName, $ShortName, $Options, $Req );
# dbgmsg( "In subroutine RunCommands ..." );
# init vars
$ThreadCount = 0;
undef( @EndList );
# debug only
# foreach $Request ( @Requests ) {
# $LongName = &GetField( $Request, $NCommand );
# if ( $LongName =~ /.*\\([^\\]+?)$/ ) { $ShortName = $1; }
# else { $ShortName = $LongName };
# dbgmsg( "Script $ShortName needs " .
# &GetNumThreads( &GetField( $Request, $NCommand ) ) .
# " threads ..." );
# }
# start the loop
foreach $Request ( @Requests ) {
# see if we need to do this one
if ( &GetField( $Request, $NNeedToDo ) =~ /f/i ) { next; }
# see if this is a checkfatal statement
if ( &GetField( $Request, $NReqType ) =~ /checkfatal/i ) {
if ( &CheckForStop() eq "TRUE" ) {
errmsg( "Errors encountered at this time, exiting." );
# clear up any unfinished processes
undef( @EndList );
foreach $Req ( @Requests ) {
if ( &IsRunning( $Req ) ) {
push( @EndList, $Req );
}
if ( @EndList ) { &WaitForEnds(); }
}
return( undef );
}
$Request = &MakeNewRequest( $Request, $NNeedToDo, "f" );
next;
}
# see if this is an end statement
if ( &GetField( $Request, $NReqType ) =~ /END/i ) {
push( @EndList, $Request );
next;
}
# this is not an end, so kill off any pending ends
if ( @EndList ) {
$ThreadCount -= &WaitForEnds();
}
# see how many threads we'll need
$NumThreads = &GetNumThreads( &GetField( $Request, $NCommand ) );
# make sure we have the horse power to kick off the given request
while ( ( $ThreadCount + $NumThreads > $MaxThreads ) &&
( $ThreadCount > 0 ) ) {
# now we want to kill off enough requests so that we can kick
# off the next script
$LongName = &GetField( $Request, $NCommand );
if ( $LongName =~ /.*\\([^\\]+?)$/ ) { $ShortName = $1; }
else { $ShortName = $LongName };
$NumKill = $ThreadCount - $MaxThreads + $NumThreads;
#dbgmsg( "Waiting prematurely:" );
#dbgmsg( "Script $ShortName needs $NumKill killed" );
#dbgmsg( "as there are $ThreadCount running, we need " .
#$NumThreads . ", and $MaxThreads is max ..." );
$ThreadCount -= &KillRunningRequest( $NumKill );
}
# we are now guaranteed we have the horse power to run the request
# kick it off and increment the thread count
$LongName = &GetField( $Request, $NCommand );
if ( $LongName =~ /.*\\([^\\]+?)$/ ) { $ShortName = $1; }
else { $ShortName = $LongName; }
$Options = &GetField( $Request, $NOptions );
system( "start \"PB\_$ShortName\" /min cmd /c " .
"\%RazzleToolPath\%\\PostBuildScripts\\Wrapper.cmd " .
&GetField( $Request, $NInstance ) . " $LongName $Options" . " -l:$Language" );
logmsg( "Beginning $ShortName with $NumThreads thread(s)" );
$ThreadCount += $NumThreads;
$Request = &MakeNewRequest( $Request, $NNeedToDo, "f" );
}
# cleanup - make sure @EndList is empty
if ( @EndList ) { $ThreadCount -= &WaitForEnds(); }
dbgmsg( "Current threads running: $ThreadCount" );
}
#
# GetNumThreads
#
# Arguments: $Command
#
# Purpose: this routine will return the number of threads kicked off by the
# passed command. DriverCab.cmd, for instance, kicks off twice the
# number of processors.
#
# Returns: the number of threads a given process kicks off
#
sub GetNumThreads
{
# get passed args
my( $Command ) = @_;
# declare locals
my( $ShortName );
# dbgmsg( "In subroutine GetNumThreads ..." );
# generate the short name (i.e. command name without the path)
if ( $Command =~ /.*\\([^\\]+?)$/ ) { $ShortName = $1; }
else { $ShortName = $Command };
if ( $ShortName =~ /drivercab\.cmd/i ) { return( $NumProcs * 2 ); }
if ( $ShortName =~ /startcompress\.cmd/i ) { return( $NumProcs ); }
if ( $ShortName =~ /ddkcabs\.bat/i ) { return( $NumProcs ); }
if ( $ShortName =~ /startcompress\_post\.cmd/i ) { return( $NumProcs ); }
# if we weren't in the list, assume only one thread
return( 1 );
}
#
# IsRunning
#
# Arguments: a $Request
#
# Purpose: this routine will determine if the passed request is still running.
# this means the /BEGIN/ half of the request must have $NeedToDo set
# to "f" and the /END/ must be set to "t"
#
# Returns: "t" if the command is still running, undef otherwise.
#
sub IsRunning
{
# get passed args
my( $Request ) = @_;
# declare locals
my( $Command, $Instance, $ReqType, $ShortName, $Req, $NeedToDo );
# remove dbgmsg because of profuse spewing
# dbgmsg( "In subroutine IsRunning ..." );
# check for a finished END request
if ( ( &GetField( $Request, $NReqType ) =~ /END/i ) &&
( &GetField( $Request, $NNeedToDo ) =~ /f/i ) ) {
return( undef );
}
# now if we haven't started this one, we're not running now
if ( ( &GetField( $Request, $NReqType ) =~ /BEGIN/i ) &&
( &GetField( $Request, $NNeedToDo ) =~ /t/i ) ) {
return( undef );
}
# get the short command name (i.e. no path)
$Command = &GetField( $Request, $NCommand );
if ( $Command =~ /.*\\([^\\]+?)$/ ) { $Command = $1; }
# get other interesting info
$ReqType = &GetField( $Request, $NReqType );
$Instance = &GetField( $Request, $NInstance );
# loop over other requests
foreach $Req ( @Requests ) {
if ( &GetField( $Req, $NReqType ) =~ /$ReqType/i ) { next; }
if ( &GetField( $Req, $NInstance ) !~ /$Instance/i ) { next; }
$ShortName = &GetField( $Req, $NCommand );
if ( $ShortName =~ /.*\\([^\\]+?)$/ ) { $ShortName = $1; }
if ( "\L$ShortName" ne "\L$Command" ) { next; }
# if we're here, we found our culprit
$NeedToDo = &GetField( $Req, $NNeedToDo );
if ( ( ( &GetField( $Req, $NReqType ) =~ /END/i ) &&
( $NeedToDo =~ /t/i ) ) ||
( ( &GetField( $Req, $NReqType ) =~ /BEGIN/i ) &&
( $NeedToDo =~ /f/i ) ) ) { return( "t" ); }
return( undef );
}
# default: say we're not running
return( undef );
}
#
# WaitForEnds
#
# Arguments: none
#
# Purpose: wait on the threads in the @EndList.
#
# Returns: the number of threads that died from this wait cycle
#
sub WaitForEnds
{
# declare locals
my( $EventName, $EventNames, $Req, $NumThreads, $Return, $Request );
my( $Instance, $Command );
# dbgmsg( "In subroutine WaitForEnds ..." );
# make sure we have events to wait on
unless ( @EndList ) {
errmsg( "Null EndList, not performing wait ..." );
$ExitCode++;
return( 0 );
}
&DisplayHelp( @EndList );
# loop over the end list and make our event names
$NumThreads = 0;
foreach $Req ( @EndList ) {
$EventName = &GetField( $Req, $NCommand );
if ( $EventName =~ /.*\\([^\\]+?)$/ ) { $EventName = $1; }
$Instance = &GetField( $Req, $NInstance );
# modify the request list to say this is done
foreach $Request ( @Requests ) {
$Command = &GetField( $Request, $NCommand );
if ( $Command =~ /.*\\([^\\]+?)$/ ) { $Command = $1; }
if ( ( "\L$Command" eq "\L$EventName" ) &&
( &GetField( $Request, $NInstance ) =~ /$Instance/i ) ) {
# dbgmsg( "CHANGING REQUEST $Request ..." );
$Request = &MakeNewRequest( $Request, $NNeedToDo, "f" );
}
}
$NumThreads += &GetNumThreads( &GetField( $Req, $NCommand ) );
$EventName .= "." . &GetField( $Req, $NInstance );
$EventNames .= " $EventName";
}
# now wait on all the events
$Return = system( "perl \%RazzleToolPath\%\\PostBuildScripts\\cmdevt.pl " .
"-ivw " . $EventNames );
if ( $Return != 0 ) {
errmsg( "Waitloop failed waiting on the following events:" );
errmsg( "$EventNames" );
$ExitCode++;
}
undef( @EndList );
# put in a blank line for aesthetic reasons
print( "\n" );
# return the thread count killed
return( $NumThreads );
}
#
# KillRunningRequest
#
# Arguments: number of threads to kill
#
# Purpose: this routine will check all requests. it will kill off the first n
# requests it finds in the requests array that are not finished
# running, such that we meet the number of threads to kill as passed.
# as a footnote, we don't have to worry if this event name
# is already in @EndList, because the point at which this routine is
# called, we are guaranteed that @EndList is empty.
#
# Returns: the number of threads that were killed in this manner
#
sub KillRunningRequest
{
# get passed args
my( $NumKill ) = @_;
# declare locals
my( $Req, $NThreads, $NEndedThreads );
my( $EventName, $LongName, $Return );
# dbgmsg( "In subroutine KillRunningRequest ..." );
# before we go into the loop of this that are running that we should wait
# on, let's see if anybody's done, and get rid of them first.
$NEndedThreads = 0;
$NThreads = 0;
foreach $Req ( @Requests ) {
if ( ( &IsRunning( $Req ) ) &&
( &GetField( $Req, $NNeedToDo ) !~ /f/i ) &&
( &GetField( $Req, $NReqType ) =~ /END/i ) ) {
# build up the event name for this request
$LongName = &GetField( $Req, $NCommand );
if ( $LongName =~ /.*\\([^\\]+?)$/ ) { $EventName = $1; }
else { $EventName = $LongName; }
$EventName .= "." . &GetField( $Req, $NInstance );
$Return = system( "perl \%RazzleToolPath\%\\PostBuildScripts\\" .
"cmdevt.pl -qi " . $EventName . " \>nul" );
if ( $Return == 0 ) {
# this means we have already finished this task and we can
# safely mark this one as finished
push( @EndList, $Req );
$Req = &MakeNewRequest( $Req, $NNeedToDo, "f" );
$NThreads += &GetNumThreads( $Req, $NCommand );
}
}
# if ( $NThreads >= $NumKill ) {
# $NEndedThreads += &WaitForEnds();
# last;
# }
}
if ( @EndList ) {
$NEndedThreads += &WaitForEnds();
}
if ( $NEndedThreads >= $NumKill ) {
return( $NEndedThreads );
}
foreach $Req ( @Requests ) {
if ( ( &IsRunning( $Req ) ) &&
( &GetField( $Req, $NNeedToDo ) !~ /f/i ) &&
( &GetField( $Req, $NReqType ) =~ /END/i ) ) {
# do the work here so when we modify $Req to say it's finished,
# we actually modify the one in @Requests
push( @EndList, $Req );
$Req = &MakeNewRequest( $Req, $NNeedToDo, "f" );
$NThreads += &GetNumThreads( &GetField( $Req, $NCommand ) );
}
if ( $NThreads >= $NumKill ) {
$NEndedThreads += &WaitForEnds();
last;
}
}
if ( @EndList ) {
$NEndedThreads += &WaitForEnds();
}
return( $NEndedThreads );
}
#
# DisplayHelp
#
# Arguments: @EndList
#
# Purpose: this routine goes through the given end list and prints out the
# help for each thing being waited on.
#
# Returns: nothing
#
sub DisplayHelp
{
# get passed args
my( @EndList ) = @_;
# declare locals
my( $Request, $BeginRequest, $Command );
# go through each request, find the associated begin (so we can get the
# options right) and print out the help
print( "\n" );
foreach $Request ( @EndList ) {
$BeginRequest = &GetBegin( $Request );
if ( $BeginRequest ) {
$Command = &GetField( $BeginRequest, $NCommand );
if ( $Command =~ /.*\\([^\\]+?)$/ ) { $Command = $1; }
if ( &GetField( $BeginRequest, $NOptions ) ) {
$Command .= " " . &GetField( $BeginRequest, $NOptions );
}
$Command = "\L$Command";
if ( $HelpMessages{ $Command } ) {
print( "INFO: $Command : $HelpMessages{ $Command }\n" );
}
}
}
#print( "\n" );
}
#
# GetBegin
#
# Arguments: $EndRequest
#
# Purpose: this routine finds the begin request associated with the given end
# request.
#
# Returns: the associated begin request
#
sub GetBegin
{
# get passed args
my( $EndRequest ) = @_;
# declare locals
my( $Request, $EndInstance, $EndCommand, $Command );
# if this isn't an /END/ request, return undef
if ( &GetField( $EndRequest, $NReqType ) !~ /END/i ) { return( undef ); }
$EndCommand = &GetField( $EndRequest, $NCommand );
if ( $EndCommand =~ /.*\\([^\\]+?)$/ ) { $EndCommand = $1; }
$EndCommand = "\L$EndCommand";
$EndInstance = &GetField( $EndRequest, $NInstance );
foreach $Request ( @Requests ) {
$Command = &GetField( $Request, $NCommand );
if ( $Command =~ /.*\\([^\\]+?)$/ ) { $Command = $1; }
$Command = "\L$Command";
if ( ( &GetField( $Request, $NInstance ) =~ /$EndInstance/i ) &&
( &GetField( $Request, $NReqType ) =~ /BEGIN/i ) &&
( $Command eq $EndCommand ) ) {
return( $Request );
}
}
# if we didn't find a match, return undef
dbgmsg( "Failed to find a matching begin, returning undef ..." );
return( undef );
}
#
# CheckForStop
#
# Arguments: none
#
# Purpose: this function will check the current logfile for errors. if there
# are any errors, it will signal by returning "TRUE".
#
# Returns: "TRUE" if errors were encountered, undef otherwise
sub CheckForStop
{
# declare locals
my( $LogFileName, @LogLines, $Line );
# open the current logfile
unless ( $LogFileName ) {
# postbuild.cmd defines INTERLEAVE_LOG so Logmsg.pm will log all calls
# to logmsg and errmsg in this file making it a good place to check
# for errors
$LogFileName = $ENV{ "INTERLEAVE_LOG" };
}
unless ( $LogFileName ) {
errmsg( "No logfile found, assuming NO errors ..." );
return( undef );
}
unless ( open( INFILE, $LogFileName ) ) {
errmsg( "Failed to open logfile, assuming errors ..." );
return( "TRUE" );
}
@LogLines = <INFILE>;
close( INFILE );
foreach $Line ( @LogLines ) {
if ( $Line =~ /error\:/i ) {
logmsg( "Errors found ..." );
return( "TRUE" );
}
}
# if we're here, no errors were found.
logmsg( "No errors encountered at this time ..." );
return( undef );
}