| /*------------------------------------------------------------------------- |
| * 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(); |
| } |