2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-13 12:22:17 +00:00

Add "-lx" option which limits the amount of time actions can run (in seconds). Currently only implemented for Windows NT and above.

[SVN r31266]
This commit is contained in:
Rene Rivera
2005-10-10 20:33:22 +00:00
parent 9317a593d5
commit a34669c462
3 changed files with 142 additions and 7 deletions

View File

@@ -24,6 +24,9 @@
# define WIN32_LEAN_AND_MEAN
# include <windows.h> /* do the ugly deed */
# include <process.h>
# if !defined( __BORLANDC__ )
# include <tlhelp32.h>
# endif
# if !defined( __BORLANDC__ ) && !defined( OS_OS2 )
# define wait my_wait
@@ -916,6 +919,107 @@ check_process_exit(
return result;
}
static double
running_time(HANDLE process)
{
FILETIME creation, exit, kernel, user, current;
if (GetProcessTimes(process, &creation, &exit, &kernel, &user))
{
/* Compute the elapsed time */
GetSystemTimeAsFileTime(&current);
{
double delta = filetime_seconds(
add_FILETIME( current, negate_FILETIME(creation) )
);
return delta;
}
}
return 0.0;
}
/* it's just stupidly silly that one has to do this! */
typedef struct PROCESS_BASIC_INFORMATION__ {
LONG ExitStatus;
PVOID PebBaseAddress;
ULONG AffinityMask;
LONG BasePriority;
ULONG UniqueProcessId;
ULONG InheritedFromUniqueProcessId;
} PROCESS_BASIC_INFORMATION_;
typedef LONG (__stdcall * NtQueryInformationProcess__)(
HANDLE ProcessHandle,
LONG ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength);
static NtQueryInformationProcess__ NtQueryInformationProcess_ = NULL;
static HMODULE NTDLL_ = NULL;
DWORD get_process_id(HANDLE process)
{
PROCESS_BASIC_INFORMATION_ pinfo;
if ( ! NtQueryInformationProcess_ )
{
if ( ! NTDLL_ )
{
NTDLL_ = GetModuleHandleA("ntdll");
}
if ( NTDLL_ )
{
NtQueryInformationProcess_
= (NtQueryInformationProcess__)GetProcAddress( NTDLL_,"NtQueryInformationProcess" );
}
}
if ( NtQueryInformationProcess_ )
{
LONG r = (*NtQueryInformationProcess_)(
process,/* ProcessBasicInformation == */ 0,&pinfo,sizeof(PROCESS_BASIC_INFORMATION_),NULL);
return pinfo.UniqueProcessId;
}
else
{
return 0;
}
}
/* not really optimal, or efficient, but it's easier this way, and it's not
like we are going to be killing thousands, or even tens or processes. */
static void
kill_all(DWORD pid, HANDLE process)
{
HANDLE process_snapshot_h = INVALID_HANDLE_VALUE;
if ( !pid )
{
pid = get_process_id(process);
}
process_snapshot_h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if (INVALID_HANDLE_VALUE != process_snapshot_h)
{
BOOL ok = TRUE;
PROCESSENTRY32 pinfo;
pinfo.dwSize = sizeof(PROCESSENTRY32);
for (
ok = Process32First(process_snapshot_h,&pinfo);
TRUE == ok;
ok = Process32Next(process_snapshot_h,&pinfo) )
{
if (pinfo.th32ParentProcessID == pid)
{
/* found a child, recurse to kill it and anything else below it */
HANDLE ph = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pinfo.th32ProcessID);
if (NULL != ph)
{
kill_all(pinfo.th32ProcessID,ph);
CloseHandle(ph);
}
}
}
CloseHandle(process_snapshot_h);
}
/* now that the children are all dead, kill the root */
TerminateProcess(process,-2);
}
static int
my_wait( int *status )
{
@@ -949,10 +1053,35 @@ my_wait( int *status )
return -1;
}
waitcode = WaitForMultipleObjects( num_active,
active_handles,
FALSE,
INFINITE );
if ( globs.timeout > 0 )
{
/* with a timeout we wait for a finish or a timeout, we check every second
to see if something timed out */
for (waitcode = WAIT_TIMEOUT; waitcode == WAIT_TIMEOUT;)
{
waitcode = WaitForMultipleObjects( num_active, active_handles, FALSE, 1*1000 /* 1 second */ );
if ( waitcode == WAIT_TIMEOUT )
{
/* check if any jobs have surpassed the maximum run time. */
for ( i = 0; i < num_active; ++i )
{
double t = running_time(active_handles[i]);
if ( t > (double)globs.timeout )
{
/* we have a "runaway" job, kill it */
kill_all(0,active_handles[i]);
/* indicate the job "finished" so we query its status below */
waitcode = WAIT_ABANDONED_0+i;
}
}
}
}
}
else
{
/* no timeout, so just wait indefinately for something to finish */
waitcode = WaitForMultipleObjects( num_active, active_handles, FALSE, INFINITE );
}
if ( waitcode != WAIT_FAILED )
{
if ( waitcode >= WAIT_ABANDONED_0

View File

@@ -146,7 +146,8 @@ struct globs globs = {
# else
{ 0, 1 }, /* debug ... */
# endif
0 /* output commands, not run them */
0, /* output commands, not run them */
0 /* action timeout */
} ;
/* Symbols to be defined as true for use in Jambase */
@@ -241,7 +242,7 @@ int main( int argc, char **argv, char **arg_environ )
argc--, argv++;
if( getoptions( argc, argv, "-:d:j:f:gs:t:ano:qv", optv ) < 0 )
if( getoptions( argc, argv, "-:l:d:j:f:gs:t:ano:qv", optv ) < 0 )
{
printf( "\nusage: %s [ options ] targets...\n\n", progname );
@@ -250,6 +251,7 @@ int main( int argc, char **argv, char **arg_environ )
printf( "-fx Read x instead of Jambase.\n" );
/* printf( "-g Build from newest sources first.\n" ); */
printf( "-jx Run up to x shell commands concurrently.\n" );
printf( "-lx Limit actions to x number of seconds after which they are stopped.\n" );
printf( "-n Don't actually execute the updating actions.\n" );
printf( "-ox Write the updating actions to file x.\n" );
printf( "-q Quit quickly as soon as a target fails.\n" );
@@ -292,6 +294,9 @@ int main( int argc, char **argv, char **arg_environ )
if( ( s = getoptval( optv, 'g', 0 ) ) )
globs.newestfirst = 1;
if( ( s = getoptval( optv, 'l', 0 ) ) )
globs.timeout = atoi( s );
/* Turn on/off debugging */
for( n = 0; s = getoptval( optv, 'd', n ); n++ )
@@ -423,7 +428,7 @@ int main( int argc, char **argv, char **arg_environ )
{
if ( arg_v[n][0] == '-' )
{
char *f = "-:d:j:f:gs:t:ano:qv";
char *f = "-:l:d:j:f:gs:t:ano:qv";
for( ; *f; f++ ) if( *f == arg_v[n][1] ) break;
if ( f[1] == ':' && arg_v[n][2] == '\0' ) { ++n; }
}

View File

@@ -520,6 +520,7 @@ struct globs {
int newestfirst; /* build newest sources first */
char debug[DEBUG_MAX];
FILE *cmdout; /* print cmds, not run them */
long timeout; /* number of seconds to limit actions to, default 0 for no limit. */
} ;
extern struct globs globs;