5 package PerlACE
::Process
;
12 # Make sure the File::Which module is installed on the machine
13 # before trying to use it. If the module is installed on this
14 # machine, then it will be included because of the eval ()
16 my $has_which = eval ("use File::Which; 1;") ?
1 : 0;
18 ###############################################################################
20 # This is what GetExitCode will return if the process is still running.
21 my $STILL_ACTIVE = 259;
23 ###############################################################################
25 ### Constructor and Destructor
28 # Hack in purify support thru 2 environment variables:
29 # ACE_RUN_PURIFY_CMD: complete path to purify executable
30 # ACE_RUNTEST_DELAY: wait delay factor, default to 10 if
31 # ACE_RUN_PURIFY_CMD is defined, or 1 if
32 # ACE_RUN_PURIFY_CMD is not defined.
33 # ** Notice that when ACE_RUN_PURIFY_CMD is define, PerlACE::Process
34 # reports the return status of *purify*, not the process being purified.
36 # Also hack in the ability to run the test on a WinCE device using the
37 # ACE_WINCE_TEST_CONTROLLER environment variable. If set, it specifies a
38 # controlling program to use for setting up and executing the test.
39 # Further setup can be specialized depending on the value of the variable.
44 my $class = ref ($proto) || $proto;
47 $self->{EXECUTABLE
} = shift;
48 $self->{ARGUMENTS
} = shift;
49 $self->{TARGET
} = undef;
51 $self->{IGNOREEXESUBDIR
} = 0;
52 $self->{IGNOREHOSTROOT
} = 0;
53 $self->{PROCESS
} = undef;
54 $self->{PURIFY_CMD
} = $ENV{'ACE_RUN_PURIFY_CMD'};
55 $self->{PURIFY_OPT
} = $ENV{'ACE_RUN_PURIFY_OPT'};
56 if (!defined $PerlACE::Process
::WAIT_DELAY_FACTOR
) {
57 if (defined $self->{PURIFY_CMD
}) {
58 $PerlACE::Process
::WAIT_DELAY_FACTOR
= 10;
61 $PerlACE::Process
::WAIT_DELAY_FACTOR
= 1;
64 $self->{WINCE_CTL
} = $ENV{'ACE_WINCE_TEST_CONTROLLER'};
66 bless ($self, $class);
74 if ($self->{RUNNING
} == 1) {
75 print STDERR
"ERROR: <", $self->{EXECUTABLE
},
76 "> still running upon object destruction\n";
82 ###############################################################################
86 sub Normalize_Executable_Name
($)
89 my $executable = shift;
90 my $basename = basename
($executable);
91 my $dirname = dirname
($executable). '/';
93 if (defined $self->{TARGET
}) {
94 $subdir = $self->{TARGET
}->ExeSubDir();
97 $subdir = $PerlACE::Process
::ExeSubDir
;
99 $executable = $dirname.$subdir.$basename.".EXE";
101 ## Installed executables do not conform to the ExeSubDir
102 if (! -x
$executable && -x
$dirname.$basename.'.EXE') {
103 $executable = $dirname.$basename.'.EXE';
106 $executable =~ s/\//\\/g; # / <- # color coding issue in devenv
117 $self->{EXECUTABLE
} = shift;
120 my $executable = $self->{EXECUTABLE
};
121 # If the target's config has a different ACE_ROOT, rebase the executable
122 # from $ACE_ROOT to the target's root.
123 if (defined $self->{TARGET
} &&
124 $self->{TARGET
}->ACE_ROOT() ne $ENV{'ACE_ROOT'}) {
125 $executable = File
::Spec
->rel2abs($executable);
126 $executable = File
::Spec
->abs2rel($executable, $ENV{'ACE_ROOT'});
127 $executable = $self->{TARGET
}->ACE_ROOT() . "/$executable";
130 # After VxWorks adopts the TARGET scheme, can do away with this block.
131 if ($self->{IGNOREHOSTROOT
} == 0) {
132 if (PerlACE
::is_vxworks_test
()) {
133 $executable = PerlACE
::VX_HostFile
($executable);
137 if ($self->{IGNOREEXESUBDIR
} == 0) {
138 $executable = $self->Normalize_Executable_Name ($executable);
141 if ($executable !~ m/\.(BAT|EXE|COM)$/i) {
142 $executable = $executable.".EXE";
145 $executable =~ s/\//\\/g; # / <- # color coding issue in devenv
147 # If there is no directory in the executable name, then we are going
148 # to search the PATH for the executable.
149 if ($has_which && $executable !~ m/\//) {
150 my $which = File
::Which
::which
($executable);
153 $executable = $which;
166 $self->{ARGUMENTS
} = shift;
169 return $self->{ARGUMENTS
};
176 my $commandline = $self->Executable ();
177 $commandline = '"' . $commandline . '"' if $commandline =~ /\s/;
179 if (defined $self->{ARGUMENTS
}) {
180 $commandline .= ' '.$self->{ARGUMENTS
};
190 # If we have -Config ARCH, do not set IGNOREEXESUBDIR, since with ARCH
191 # all executables (even those in $ACE_ROOT/bin, etc.) are located in the
192 # architecture-specific subdirectory.
193 if (@_ != 0 && !grep(($_ eq 'ARCH'), @PerlACE::ConfigList
::Configs
)) {
194 $self->{IGNOREEXESUBDIR
} = shift;
196 elsif (@_ != 0 && $self->{EXECUTABLE
} =~ /perl$/) {
197 print ("==== automatically ignoring...\n");
198 $self->{IGNOREEXESUBDIR
} = shift;
201 return $self->{IGNOREEXESUBDIR
};
209 $self->{IGNOREHOSTROOT
} = shift;
212 return $self->{IGNOREHOSTROOT
};
215 ###############################################################################
217 ### Spawning processes
220 # Spawn the process and continue.
226 if ($self->{RUNNING
} == 1) {
227 print STDERR
"ERROR: Cannot Spawn: <", $self->Executable (),
228 "> already running\n";
232 if (!defined $self->{EXECUTABLE
}) {
233 print STDERR
"ERROR: Cannot Spawn: No executable specified\n";
237 if ($self->{IGNOREEXESUBDIR
} == 0) {
238 if (!-f
$self->Executable ()) {
239 print STDERR
"ERROR: Cannot Spawn: <", $self->Executable (),
244 if (!-x
$self->Executable ()) {
245 print STDERR
"ERROR: Cannot Spawn: <", $self->Executable (),
246 "> not executable\n";
255 my $chdir_needed = 0;
258 if (defined $self->{PURIFY_CMD
}) {
259 my $orig_cmdline = $self->CommandLine ();
260 $executable = $self->{PURIFY_CMD
};
261 my $basename = basename
($self->{EXECUTABLE
});
263 my $PurifyOptions = $self->{PURIFY_OPT
};
264 if (!defined $PurifyOptions) {
267 # "/save-data=$basename.pfy ".
268 "/save-text-data=$basename.pfytxt ".
269 "/AllocCallStackLength=20 ".
270 "/ErrorCallStackLength=20 ".
271 "/HandlesInUseAtExit ".
280 elsif (defined $self->{WINCE_CTL
}) {
281 $executable = $self->Executable ();
282 $cmdline = $self->CommandLine ();
284 # Generate a script to copy the test down to the device, run it,
285 # copy the log file(s) back to the log directory, then delete the
286 # program and log files on the remote device.
287 unless (open (SCRIPT
, ">start_test.cmd")) {
288 print STDERR
"ERROR: Cannot Spawn: <", $self->Executable (),
289 "> failed to create start_test.cmd\n";
293 my $testname = basename
($executable,'.EXE');
296 $executable =~ s/^\.//; # Chop leading .
297 $executable = $here . $executable; # Fully qualified name
298 # Take off the test name from the start of the command line.
299 # The command name is preprended in the script below.
300 my @tokens = split(' ', $cmdline);
301 @tokens = splice(@tokens,1);
302 $cmdline = join(' ', @tokens);
303 print SCRIPT
"copy $executable 1:\\Windows\n";
304 print SCRIPT
"start /wait $testname $cmdline\n";
305 print SCRIPT
"copy 1:\\log\\$testname*.txt $here\\log\n";
306 print SCRIPT
"del 1:\\Windows\\$testname.exe\n";
307 print SCRIPT
"del 1:\\log\\$testname*.txt\n";
310 $executable = $ENV{'ComSpec'};
311 my $pocket_device_opts = $ENV{'ACE_PCE_DEVICE'};
312 $cmdline = "cmd /C start /B /WAIT $self->{WINCE_CTL} $pocket_device_opts -m NAME=start_test.cmd;WAIT=401000; -e"
314 elsif (defined $ENV{'ACE_TEST_WINDOW'}) {
315 $state = ($ENV{'ACE_TEST_WINDOW'} =~ /\/k
/i ? CREATE_NEW_CONSOLE
: DETACHED_PROCESS
);
316 $executable = $ENV{'ComSpec'};
317 $cmdline = $ENV{'ACE_TEST_WINDOW'} . ' ' . $self->CommandLine();
320 $executable = $self->Executable ();
321 $cmdline = $self->CommandLine ();
322 if ((defined $self->{TARGET
}) && ($ENV{'ACE_ROOT'} ne $self->{TARGET
}->ACE_ROOT ())) {
324 $curdir_bak = cwd
();
325 chdir (dirname
($executable));
328 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
329 print "$executable $cmdline\n";
331 my %backup_ENV = %ENV;
332 # update environment for target
333 if (defined $self->{TARGET
}) {
334 if (!defined $self->{TARGET
}->{REMOTE_SHELL
}) {
335 my $x_env_ref = $self->{TARGET
}->{EXTRA_ENV
};
336 while ( my ($env_key, $env_value) = each(%$x_env_ref) ) {
337 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
338 print "INFO: adding target environment $env_key=$env_value\n";
340 $ENV{$env_key} = $env_value;
343 if ($self->{TARGET
}->{LIBPATH
}) {
344 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
345 print "INFO: adding target libpath ".$self->{TARGET
}->{LIBPATH
}."\n";
347 PerlACE
::add_lib_path
($self->{TARGET
}->{LIBPATH
});
350 my $status = Win32
::Process
::Create
($self->{PROCESS
},
353 ($state == 0 ?
1 : 0),
361 print STDERR
"ERROR: Spawn failed for <", $self->CommandLine (), ">\n";
365 $self->{RUNNING
} = 1;
370 # Wait for the process to exit or kill after a time period
377 my $status = $self->TimedWait ($timeout);
380 print STDERR
"ERROR: $self->{EXECUTABLE} timedout\n";
382 # Don't need to Wait since we are on Win32
385 $self->{RUNNING
} = 0;
391 # Do a Spawn and immediately WaitKill
393 sub SpawnWaitKill
($)
398 if ($self->Spawn () == -1) {
402 return $self->WaitKill ($timeout);
411 my $notused = shift; #Used in Process_Unix.pm
413 if ($self->{RUNNING
} && !defined $ENV{'ACE_TEST_WINDOW'}) {
414 Win32
::Process
::Kill
($self->{PROCESS
}, -1);
417 $self->{RUNNING
} = 0;
421 # Terminate the process and wait for it to finish
423 sub TerminateWaitKill
($)
428 if ($self->{RUNNING
}) {
429 print STDERR
"INFO: $self->{EXECUTABLE} being killed.\n";
430 Win32
::Process
::Kill
($self->{PROCESS
}, 0);
433 return $self->WaitKill ($timeout);
437 # Wait until a process exits.
438 # return -1 if the process is still alive.
444 if (!defined $timeout || $timeout < 0) {
447 $timeout = $timeout * 1000 * $PerlACE::Process
::WAIT_DELAY_FACTOR
;
452 if ($self->{RUNNING
}) {
453 $result = Win32
::Process
::Wait
($self->{PROCESS
}, $timeout);
458 Win32
::Process
::GetExitCode
($self->{PROCESS
}, $result);
459 $self->{RUNNING
} = 0;
464 # Wait for a process to exit with a timeout
469 my($timeout) = shift;
470 return $self->Wait($timeout);
477 my $procmask = shift;
480 for my $line (`tasklist /nh /fo csv`) {
481 # find matching process line
482 if ($line =~ /$procmask/) {
484 if ($line =~ /^\"[^\"]+\",\"(\d+)\",/) {
486 Win32
::Process
::KillProcess
($pid, 0); # kill process
487 if (defined $ENV{'ACE_TEST_VERBOSE'}) {
488 print STDERR
"INFO: Killed process at [$line]\n"