934 lines
27 KiB
Batchfile
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 );
|
|
|
|
}
|