/*-------------------------------------------------------------------------
* drawElements Quality Program Helper Library
* -------------------------------------------
*
* Copyright 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \file
* \brief Watch dog for detecting timeouts
*//*--------------------------------------------------------------------*/
#include "qpWatchDog.h"
#include "deThread.h"
#include "deClock.h"
#include "deMemory.h"
#include <stdio.h>
#if 0
# define DBGPRINT(X) qpPrintf X
#else
# define DBGPRINT(X)
#endif
typedef enum Status_e
{
STATUS_THREAD_RUNNING = 0,
STATUS_STOP_THREAD,
STATUS_LAST
} Status;
struct qpWatchDog_s
{
qpWatchDogFunc timeOutFunc;
void* timeOutUserPtr;
int totalTimeLimit; /* Total test case time limit in seconds */
int intervalTimeLimit; /* Iteration length limit in seconds */
volatile deUint64 resetTime;
volatile deUint64 lastTouchTime;
deThread watchDogThread;
volatile Status status;
};
static void watchDogThreadFunc (void* arg)
{
qpWatchDog* dog = (qpWatchDog*)arg;
DE_ASSERT(dog);
DBGPRINT(("watchDogThreadFunc(): start\n"));
while (dog->status == STATUS_THREAD_RUNNING)
{
deUint64 curTime = deGetMicroseconds();
int totalSecondsPassed = (int)((curTime - dog->resetTime) / 1000000ull);
int secondsSinceLastTouch = (int)((curTime - dog->lastTouchTime) / 1000000ull);
deBool overIntervalLimit = secondsSinceLastTouch > dog->intervalTimeLimit;
deBool overTotalLimit = totalSecondsPassed > dog->totalTimeLimit;
if (overIntervalLimit || overTotalLimit)
{
qpTimeoutReason reason = overTotalLimit ? QP_TIMEOUT_REASON_TOTAL_LIMIT : QP_TIMEOUT_REASON_INTERVAL_LIMIT;
DBGPRINT(("watchDogThreadFunc(): call timeout func\n"));
dog->timeOutFunc(dog, dog->timeOutUserPtr, reason);
break;
}
deSleep(100);
}
DBGPRINT(("watchDogThreadFunc(): stop\n"));
}
qpWatchDog* qpWatchDog_create (qpWatchDogFunc timeOutFunc, void* userPtr, int totalTimeLimitSecs, int intervalTimeLimitSecs)
{
/* Allocate & initialize. */
qpWatchDog* dog = (qpWatchDog*)deCalloc(sizeof(qpWatchDog));
if (!dog)
return dog;
DE_ASSERT(timeOutFunc);
DE_ASSERT((totalTimeLimitSecs > 0) && (intervalTimeLimitSecs > 0));
DBGPRINT(("qpWatchDog::create(%ds, %ds)\n", totalTimeLimitSecs, intervalTimeLimitSecs));
dog->timeOutFunc = timeOutFunc;
dog->timeOutUserPtr = userPtr;
dog->totalTimeLimit = totalTimeLimitSecs;
dog->intervalTimeLimit = intervalTimeLimitSecs;
/* Reset (sets time values). */
qpWatchDog_reset(dog);
/* Initialize watchdog thread. */
dog->status = STATUS_THREAD_RUNNING;
dog->watchDogThread = deThread_create(watchDogThreadFunc, dog, DE_NULL);
if (!dog->watchDogThread)
{
deFree(dog);
return DE_NULL;
}
return dog;
}
void qpWatchDog_reset (qpWatchDog* dog)
{
deUint64 curTime = deGetMicroseconds();
DE_ASSERT(dog);
DBGPRINT(("qpWatchDog::reset()\n"));
dog->resetTime = curTime;
dog->lastTouchTime = curTime;
}
void qpWatchDog_destroy (qpWatchDog* dog)
{
DE_ASSERT(dog);
DBGPRINT(("qpWatchDog::destroy()\n"));
/* Finish the watchdog thread. */
dog->status = STATUS_STOP_THREAD;
deThread_join(dog->watchDogThread);
deThread_destroy(dog->watchDogThread);
DBGPRINT(("qpWatchDog::destroy() finished\n"));
deFree(dog);
}
void qpWatchDog_touch (qpWatchDog* dog)
{
DE_ASSERT(dog);
DBGPRINT(("qpWatchDog::touch()\n"));
dog->lastTouchTime = deGetMicroseconds();
}