blob: ae68000826cd7bb5fb5bca38f3d8eadcff51b927 [file] [log] [blame]
Jarkko Poyry3c827362014-09-02 11:48:52 +03001/*-------------------------------------------------------------------------
2 * drawElements Quality Program Test Executor
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 Cross-thread function call dispatcher.
22 *//*--------------------------------------------------------------------*/
23
24#include "xeCallQueue.hpp"
25#include "deInt32.h"
26#include "deMemory.h"
27
28using std::vector;
29
30static inline int getNextQueueSize (int curSize, int minNewSize)
31{
32 return de::max(curSize*2, 1<<deLog2Ceil32(minNewSize));
33}
34
35namespace xe
36{
37
38// CallQueue
39
40CallQueue::CallQueue (void)
Mika Isojärvi57177852015-05-19 13:44:08 -070041 : m_canceled (false)
42 , m_callSem (0)
Jarkko Poyry3c827362014-09-02 11:48:52 +030043 , m_callQueue (64)
44{
45}
46
47CallQueue::~CallQueue (void)
48{
49 // Destroy all calls.
50 for (vector<Call*>::iterator i = m_calls.begin(); i != m_calls.end(); i++)
51 delete *i;
52}
53
Mika Isojärvi57177852015-05-19 13:44:08 -070054void CallQueue::cancel (void)
55{
56 m_canceled = true;
57 m_callSem.increment();
58}
59
Jarkko Poyry3c827362014-09-02 11:48:52 +030060void CallQueue::callNext (void)
61{
62 Call* call = DE_NULL;
63
64 // Wait for a call.
65 m_callSem.decrement();
66
Mika Isojärvi57177852015-05-19 13:44:08 -070067 if (m_canceled)
68 return;
69
Jarkko Poyry3c827362014-09-02 11:48:52 +030070 // Acquire call from buffer.
71 {
72 de::ScopedLock lock(m_lock);
73 call = m_callQueue.popBack();
74 }
75
76 try
77 {
78 // \note Enqueue lock is not held during call so it is possible to enqueue more work from dispatched call.
Jarkko Pöyry1592f162015-05-29 14:40:11 -070079 CallReader reader(call);
80
81 call->getFunction()(reader);
82
83 // check callee consumed all
84 DE_ASSERT(reader.isDataConsumed());
Jarkko Poyry3c827362014-09-02 11:48:52 +030085 call->clear();
86 }
87 catch (const std::exception&)
88 {
89 try
90 {
91 // Try to push call into free calls list.
92 de::ScopedLock lock(m_lock);
93 m_freeCalls.push_back(call);
94 }
95 catch (const std::exception&)
96 {
97 // We can't do anything but ignore this.
98 }
99
100 throw;
101 }
102
103 // Push back to free calls list.
104 {
105 de::ScopedLock lock(m_lock);
106 m_freeCalls.push_back(call);
107 }
108}
109
110Call* CallQueue::getEmptyCall (void)
111{
112 de::ScopedLock lock (m_lock);
113 Call* call = DE_NULL;
114
115 // Try to get from free calls list.
116 if (!m_freeCalls.empty())
117 {
118 call = m_freeCalls.back();
119 m_freeCalls.pop_back();
120 }
121
122 // If no free calls were available, create a new.
123 if (!call)
124 {
125 m_calls.reserve(m_calls.size()+1);
126 call = new Call();
127 m_calls.push_back(call);
128 }
129
130 return call;
131}
132
133void CallQueue::enqueue (Call* call)
134{
135 de::ScopedLock lock(m_lock);
136
137 if (m_callQueue.getNumFree() == 0)
138 {
139 // Call queue must be grown.
140 m_callQueue.resize(getNextQueueSize(m_callQueue.getSize(), m_callQueue.getSize()+1));
141 }
142
143 m_callQueue.pushFront(call);
144 m_callSem.increment();
145}
146
147void CallQueue::freeCall (Call* call)
148{
149 de::ScopedLock lock(m_lock);
150 m_freeCalls.push_back(call);
151}
152
153// Call
154
155Call::Call (void)
156 : m_func(DE_NULL)
157{
158}
159
160Call::~Call (void)
161{
162}
163
164void Call::clear (void)
165{
166 m_func = DE_NULL;
167 m_data.clear();
168}
169
170// CallReader
171
172CallReader::CallReader (Call* call)
173 : m_call (call)
174 , m_curPos (0)
175{
176}
177
Jarkko Pöyry745d7c62015-05-19 12:24:51 -0700178void CallReader::read (deUint8* bytes, size_t numBytes)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300179{
180 DE_ASSERT(m_curPos + numBytes <= m_call->getDataSize());
181 deMemcpy(bytes, m_call->getData()+m_curPos, numBytes);
182 m_curPos += numBytes;
183}
184
Jarkko Pöyry745d7c62015-05-19 12:24:51 -0700185const deUint8* CallReader::getDataBlock (size_t numBytes)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300186{
187 DE_ASSERT(m_curPos + numBytes <= m_call->getDataSize());
188
189 const deUint8* ptr = m_call->getData()+m_curPos;
190 m_curPos += numBytes;
191
192 return ptr;
193}
194
Jarkko Pöyry1592f162015-05-29 14:40:11 -0700195bool CallReader::isDataConsumed (void) const
196{
197 return m_curPos == m_call->getDataSize();
198}
199
Jarkko Poyry3c827362014-09-02 11:48:52 +0300200CallReader& operator>> (CallReader& reader, std::string& value)
201{
202 value.clear();
203 for (;;)
204 {
205 char c;
206 reader.read((deUint8*)&c, sizeof(char));
207 if (c != 0)
208 value.push_back(c);
209 else
210 break;
211 }
212
213 return reader;
214}
215
216// CallWriter
217
218CallWriter::CallWriter (CallQueue* queue, Call::Function function)
219 : m_queue (queue)
220 , m_call (queue->getEmptyCall())
221 , m_enqueued (false)
222{
223 m_call->setFunction(function);
224}
225
226CallWriter::~CallWriter (void)
227{
228 if (!m_enqueued)
229 m_queue->freeCall(m_call);
230}
231
Jarkko Pöyry745d7c62015-05-19 12:24:51 -0700232void CallWriter::write (const deUint8* bytes, size_t numBytes)
Jarkko Poyry3c827362014-09-02 11:48:52 +0300233{
234 DE_ASSERT(!m_enqueued);
Jarkko Pöyry745d7c62015-05-19 12:24:51 -0700235 size_t curPos = m_call->getDataSize();
Jarkko Poyry3c827362014-09-02 11:48:52 +0300236 m_call->setDataSize(curPos+numBytes);
237 deMemcpy(m_call->getData()+curPos, bytes, numBytes);
238}
239
240void CallWriter::enqueue (void)
241{
242 DE_ASSERT(!m_enqueued);
243 m_queue->enqueue(m_call);
244 m_enqueued = true;
245}
246
247CallWriter& operator<< (CallWriter& writer, const char* str)
248{
249 int pos = 0;
250 for (;;)
251 {
252 writer.write((const deUint8*)str + pos, sizeof(char));
253 if (str[pos] == 0)
254 break;
255 pos += 1;
256 }
257
258 return writer;
259}
260
261} // xe