Fix missing dependency on sparse binds
[platform/upstream/VK-GL-CTS.git] / framework / qphelper / qpWatchDog.c
1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program Helper Library
3  * -------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Watch dog for detecting timeouts
22  *//*--------------------------------------------------------------------*/
23
24 #include "qpWatchDog.h"
25
26 #include "deThread.h"
27 #include "deClock.h"
28 #include "deMemory.h"
29
30 #include <stdio.h>
31
32 #if 0
33 #       define DBGPRINT(X) qpPrintf X
34 #else
35 #       define DBGPRINT(X)
36 #endif
37
38 typedef enum Status_e
39 {
40         STATUS_THREAD_RUNNING = 0,
41         STATUS_STOP_THREAD,
42
43         STATUS_LAST
44 } Status;
45
46 struct qpWatchDog_s
47 {
48         qpWatchDogFunc          timeOutFunc;
49         void*                           timeOutUserPtr;
50         int                                     totalTimeLimit;                 /* Total test case time limit in seconds        */
51         int                                     intervalTimeLimit;              /* Iteration length limit in seconds            */
52         /*
53                 Iteration time limit in seconds specified to the constructor. This is stored so that
54                 intervalTimeLimit can be restored after qpWatchDog_touchAndDisableIntervalTimeLimit
55                 is called.
56         */
57         int                                     defaultIntervalTimeLimit;
58
59         volatile deUint64       resetTime;
60         volatile deUint64       lastTouchTime;
61
62         deThread                        watchDogThread;
63         volatile Status         status;
64 };
65
66 static void watchDogThreadFunc (void* arg)
67 {
68         qpWatchDog* dog = (qpWatchDog*)arg;
69         DE_ASSERT(dog);
70
71         DBGPRINT(("watchDogThreadFunc(): start\n"));
72
73         while (dog->status == STATUS_THREAD_RUNNING)
74         {
75                 deUint64        curTime                                 = deGetMicroseconds();
76                 int                     totalSecondsPassed              = (int)((curTime - dog->resetTime) / 1000000ull);
77                 int                     secondsSinceLastTouch   = (int)((curTime - dog->lastTouchTime) / 1000000ull);
78                 deBool          overIntervalLimit               = secondsSinceLastTouch > dog->intervalTimeLimit;
79                 deBool          overTotalLimit                  = totalSecondsPassed > dog->totalTimeLimit;
80
81                 if (overIntervalLimit || overTotalLimit)
82                 {
83                     qpTimeoutReason reason = overTotalLimit ? QP_TIMEOUT_REASON_TOTAL_LIMIT : QP_TIMEOUT_REASON_INTERVAL_LIMIT;
84                         DBGPRINT(("watchDogThreadFunc(): call timeout func\n"));
85                         dog->timeOutFunc(dog, dog->timeOutUserPtr, reason);
86                         break;
87                 }
88
89                 deSleep(100);
90         }
91
92         DBGPRINT(("watchDogThreadFunc(): stop\n"));
93 }
94
95 qpWatchDog* qpWatchDog_create (qpWatchDogFunc timeOutFunc, void* userPtr, int totalTimeLimitSecs, int intervalTimeLimitSecs)
96 {
97         /* Allocate & initialize. */
98         qpWatchDog* dog = (qpWatchDog*)deCalloc(sizeof(qpWatchDog));
99         if (!dog)
100                 return dog;
101
102         DE_ASSERT(timeOutFunc);
103         DE_ASSERT((totalTimeLimitSecs > 0) && (intervalTimeLimitSecs > 0));
104
105         DBGPRINT(("qpWatchDog::create(%ds, %ds)\n", totalTimeLimitSecs, intervalTimeLimitSecs));
106
107         dog->timeOutFunc                                = timeOutFunc;
108         dog->timeOutUserPtr                             = userPtr;
109         dog->totalTimeLimit                             = totalTimeLimitSecs;
110         dog->intervalTimeLimit                  = intervalTimeLimitSecs;
111         dog->defaultIntervalTimeLimit   = intervalTimeLimitSecs;
112
113         /* Reset (sets time values). */
114         qpWatchDog_reset(dog);
115
116         /* Initialize watchdog thread. */
117         dog->status                     = STATUS_THREAD_RUNNING;
118         dog->watchDogThread = deThread_create(watchDogThreadFunc, dog, DE_NULL);
119         if (!dog->watchDogThread)
120         {
121                 deFree(dog);
122                 return DE_NULL;
123         }
124
125         return dog;
126 }
127
128 void qpWatchDog_reset (qpWatchDog* dog)
129 {
130         deUint64 curTime = deGetMicroseconds();
131
132         DE_ASSERT(dog);
133         DBGPRINT(("qpWatchDog::reset()\n"));
134
135         dog->resetTime                  = curTime;
136         dog->lastTouchTime              = curTime;
137 }
138
139 void qpWatchDog_destroy (qpWatchDog* dog)
140 {
141         DE_ASSERT(dog);
142         DBGPRINT(("qpWatchDog::destroy()\n"));
143
144         /* Finish the watchdog thread. */
145         dog->status = STATUS_STOP_THREAD;
146         deThread_join(dog->watchDogThread);
147         deThread_destroy(dog->watchDogThread);
148
149         DBGPRINT(("qpWatchDog::destroy() finished\n"));
150         deFree(dog);
151 }
152
153 void qpWatchDog_touch (qpWatchDog* dog)
154 {
155         DE_ASSERT(dog);
156         DBGPRINT(("qpWatchDog::touch()\n"));
157         dog->lastTouchTime = deGetMicroseconds();
158 }
159
160 /*
161         These function exists to allow the interval timer to be disabled for special cases
162         like very long shader compilations. Heavy code can be put between calls
163         to qpWatchDog_touchAndDisableIntervalTimeLimit and qpWatchDog_touchAndEnableIntervalTimeLimit
164         and during that period the interval time limit will become the same as the total
165         time limit. Afterwards, the interval timer is set back to its default.
166 */
167 void qpWatchDog_touchAndDisableIntervalTimeLimit(qpWatchDog *dog)
168 {
169         dog->intervalTimeLimit = dog->totalTimeLimit;
170         qpWatchDog_touch(dog);
171 }
172
173 void qpWatchDog_touchAndEnableIntervalTimeLimit(qpWatchDog *dog)
174 {
175         dog->intervalTimeLimit = dog->defaultIntervalTimeLimit;
176         qpWatchDog_touch(dog);
177 }