#include <sys/types.h>
#include <sys/wait.h>
#include <testcase.h>
+
+#include <time.h>
#include <unistd.h>
+#include <chrono>
#include <cstring>
#include <map>
#include <vector>
{
typedef std::map<int32_t, TestCase> RunningTestCases;
+const double MAXIMUM_CHILD_LIFETIME(60.0f); // 1 minute
+
const char* basename(const char* path)
{
const char* ptr = path;
else // Parent process
{
TestCase tc(nextTestCase, tc_array[nextTestCase].name);
+ tc.startTime = std::chrono::steady_clock::now();
+
children[pid] = tc;
nextTestCase++;
numRunningChildren++;
}
}
- // Wait for the next child to finish
-
+ // Check to see if any children have finished yet
int32_t status = 0;
- int32_t childPid = waitpid(-1, &status, 0);
- if(childPid == -1)
+ int32_t childPid = waitpid(-1, &status, WNOHANG);
+ if(childPid == 0)
+ {
+ // No children have finished.
+ // Check if any have exceeded execution time
+ auto endTime = std::chrono::steady_clock::now();
+
+ for(auto& tc : children)
+ {
+ std::chrono::steady_clock::duration timeSpan = endTime - tc.second.startTime;
+ std::chrono::duration<double> seconds = std::chrono::duration_cast<std::chrono::duration<double>>(timeSpan);
+ if(seconds.count() > MAXIMUM_CHILD_LIFETIME)
+ {
+ // Kill the child process. A subsequent call to waitpid will process signal result below.
+ kill(tc.first, SIGKILL);
+ }
+ }
+ }
+ else if(childPid == -1) // waitpid errored
{
perror("waitpid");
exit(EXIT_STATUS_WAITPID_FAILED);
}
-
- if(WIFEXITED(status))
+ else // a child has finished
{
- if(childPid > 0)
+ if(WIFEXITED(status))
{
int32_t testResult = WEXITSTATUS(status);
if(testResult)
}
numRunningChildren--;
}
- }
-
- else if(WIFSIGNALED(status) || WIFSTOPPED(status))
- {
- status = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status);
- if(childPid > 0)
+ else if(WIFSIGNALED(status) || WIFSTOPPED(status))
{
+ status = WIFSIGNALED(status) ? WTERMSIG(status) : WSTOPSIG(status);
+
RunningTestCases::iterator iter = children.find(childPid);
if(iter != children.end())
{
#include <stdio.h>
#include <testcase.h>
+#include <chrono>
#include <cstdint>
namespace TestHarness
struct TestCase
{
- int32_t testCase;
- const char* testCaseName;
+ int32_t testCase;
+ const char* testCaseName;
+ std::chrono::steady_clock::time_point startTime;
TestCase()
: testCase(0),
- testCaseName(NULL)
+ testCaseName(NULL),
+ startTime()
{
}
TestCase(int32_t tc, const char* name)
: testCase(tc),
- testCaseName(name)
+ testCaseName(name),
+ startTime()
{
}
TestCase(const TestCase& rhs)
: testCase(rhs.testCase),
- testCaseName(rhs.testCaseName)
+ testCaseName(rhs.testCaseName),
+ startTime(rhs.startTime)
{
}
TestCase& operator=(const TestCase& rhs)
{
testCase = rhs.testCase;
testCaseName = rhs.testCaseName;
+ startTime = rhs.startTime;
return *this;
}
};