0

I'm trying to set up some test software for code that is already written (that I cannot change). The issue I'm having is that it is getting hung up on certain calls, so I want to try to implement something that will kill the process if it does not complete in x seconds.

The two methods I've tried to solve this problem were to use fork or pthread, both haven't worked for me so far though. I'm not sure why pthread didn't work, I'm assuming it's because the static call I used to set up the thread had some issues with the memory needed to run the function I was calling (I continually got a segfault while the function I was testing was running). Fork worked initially, but on the second time I would fork a process, it wouldn't be able to check to see if the child had finished or not.

In terms of semi-pseudo code, this is what I've written

test_runner()
{
    bool result;

    testClass* myTestClass = new testClass();

    pid_t pID = fork();
    if(pID == 0) //Child
    {
        myTestClass->test_function(); //function in question being tested
    }
    else if(pID > 0) //Parent
    {
        int status;
        sleep(5);
        if(waitpid(0,&status,WNOHANG) == 0)
        {
            kill(pID,SIGKILL); //If child hasn't finished, kill process and fail test
            result = false;
        }
        else
            result = true;
    }
}

This method worked for the initial test, but then when I would go to test a second function, the if(waitpid(0,&status,WNOHANG) == 0) would return that the child had finished, even when it had not.

The pthread method looked along these lines

bool result;

test_runner()
{
    long thread = 1;

    pthread_t* thread_handle = (pthread_t*) malloc (sizeof(pthread_t));
    pthread_create(&thread_handle[thread], NULL, &funcTest, (void *)&thread); //Begin class that tests function in question

    sleep(10);

    if(pthread_cancel(thread_handle[thread] == 0))
        //Child process got stuck, deal with accordingly
    else
        //Child process did not get stuck, deal with accordingly
}

static void* funcTest(void*)
{
    result = false;

    testClass* myTestClass = new testClass();
    result = myTestClass->test_function();
}

Obviously there is a little more going on than what I've shown, I just wanted to put the general idea down. I guess what I'm looking for is if there is a better way to go about handling a problem like this, or maybe if someone sees any blatant issues with what I'm trying to do (I'm relatively new to C++). Like I mentioned, I'm not allowed to go into the code that I'm setting up the test software for, which prevents me from putting signal handlers in the function I'm testing. I can only call the function, and then deal with it from there.

  • 1
    You have the pid of the child process. Why not pass it to waitpid? – Khouri Giordano Jul 22 '14 at 16:33
  • 1
    Aren't you supposed to wait for the exaxt child pid `pID` instead of `0` in `waitpid(0,&status,WNOHANG)`? – didierc Jul 22 '14 at 16:33
  • And you're missing a closing parenthesis in `pthread_cancel(thread_handle[thread] == 0`. – didierc Jul 22 '14 at 16:50
  • 1
    I guess I wasn't sure how to get the exact child pid, it always returns 0 when I try to get it. And I also just quickly wrote this up, it's just meant to be similar to what I have, not exactly the same (so there may be some typos!). And when I use waitpid, it will wait forever since the child process never finishes. – user3666250 Jul 23 '14 at 18:43

1 Answers1

2

If c++11 is legit you could utilize future with wait_for for this purpose.

For example (live demo):

std::future<int> future = std::async(std::launch::async, [](){ 
    std::this_thread::sleep_for(std::chrono::seconds(3));
    return 8;  
});

std::future_status status = future.wait_for(std::chrono::seconds(5));
if (status == std::future_status::timeout) {
    std::cout << "Timeout" <<endl ;
} else{
    cout << "Success" <<endl ;
} // will print Success

std::future<int> future2 = std::async(std::launch::async, [](){ 
    std::this_thread::sleep_for(std::chrono::seconds(3));
    return 8;  
});

std::future_status status2 = future2.wait_for(std::chrono::seconds(1));
if (status2 == std::future_status::timeout) {
    std::cout << "Timeout" <<endl ;
} else{
    cout << "Success" <<endl ;
} // will print Timeout

Another thing:

As per the documentation using waitpid with 0 :

meaning wait for any child process whose process group ID is equal to that of the calling process.

Avoid using pthread_cancel it's probably not a good idea.

Community
  • 1
  • 1
Scis
  • 2,934
  • 3
  • 23
  • 37