1 /*-------------------------------------------------------------------------
2 * drawElements Quality Program Test Executor
3 * ------------------------------------------
5 * Copyright 2014 The Android Open Source Project
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * \brief Cross-thread function call dispatcher.
22 *//*--------------------------------------------------------------------*/
24 #include "xeCallQueue.hpp"
30 static inline int getNextQueueSize (int curSize, int minNewSize)
32 return de::max(curSize*2, 1<<deLog2Ceil32(minNewSize));
40 CallQueue::CallQueue (void)
47 CallQueue::~CallQueue (void)
50 for (vector<Call*>::iterator i = m_calls.begin(); i != m_calls.end(); i++)
54 void CallQueue::cancel (void)
57 m_callSem.increment();
60 void CallQueue::callNext (void)
65 m_callSem.decrement();
70 // Acquire call from buffer.
72 de::ScopedLock lock(m_lock);
73 call = m_callQueue.popBack();
78 // \note Enqueue lock is not held during call so it is possible to enqueue more work from dispatched call.
79 CallReader reader(call);
81 call->getFunction()(reader);
83 // check callee consumed all
84 DE_ASSERT(reader.isDataConsumed());
87 catch (const std::exception&)
91 // Try to push call into free calls list.
92 de::ScopedLock lock(m_lock);
93 m_freeCalls.push_back(call);
95 catch (const std::exception&)
97 // We can't do anything but ignore this.
103 // Push back to free calls list.
105 de::ScopedLock lock(m_lock);
106 m_freeCalls.push_back(call);
110 Call* CallQueue::getEmptyCall (void)
112 de::ScopedLock lock (m_lock);
113 Call* call = DE_NULL;
115 // Try to get from free calls list.
116 if (!m_freeCalls.empty())
118 call = m_freeCalls.back();
119 m_freeCalls.pop_back();
122 // If no free calls were available, create a new.
125 m_calls.reserve(m_calls.size()+1);
127 m_calls.push_back(call);
133 void CallQueue::enqueue (Call* call)
135 de::ScopedLock lock(m_lock);
137 if (m_callQueue.getNumFree() == 0)
139 // Call queue must be grown.
140 m_callQueue.resize(getNextQueueSize(m_callQueue.getSize(), m_callQueue.getSize()+1));
143 m_callQueue.pushFront(call);
144 m_callSem.increment();
147 void CallQueue::freeCall (Call* call)
149 de::ScopedLock lock(m_lock);
150 m_freeCalls.push_back(call);
164 void Call::clear (void)
172 CallReader::CallReader (Call* call)
178 void CallReader::read (deUint8* bytes, size_t numBytes)
180 DE_ASSERT(m_curPos + numBytes <= m_call->getDataSize());
181 deMemcpy(bytes, m_call->getData()+m_curPos, numBytes);
182 m_curPos += numBytes;
185 const deUint8* CallReader::getDataBlock (size_t numBytes)
187 DE_ASSERT(m_curPos + numBytes <= m_call->getDataSize());
189 const deUint8* ptr = m_call->getData()+m_curPos;
190 m_curPos += numBytes;
195 bool CallReader::isDataConsumed (void) const
197 return m_curPos == m_call->getDataSize();
200 CallReader& operator>> (CallReader& reader, std::string& value)
206 reader.read((deUint8*)&c, sizeof(char));
218 CallWriter::CallWriter (CallQueue* queue, Call::Function function)
220 , m_call (queue->getEmptyCall())
223 m_call->setFunction(function);
226 CallWriter::~CallWriter (void)
229 m_queue->freeCall(m_call);
232 void CallWriter::write (const deUint8* bytes, size_t numBytes)
234 DE_ASSERT(!m_enqueued);
235 size_t curPos = m_call->getDataSize();
236 m_call->setDataSize(curPos+numBytes);
237 deMemcpy(m_call->getData()+curPos, bytes, numBytes);
240 void CallWriter::enqueue (void)
242 DE_ASSERT(!m_enqueued);
243 m_queue->enqueue(m_call);
247 CallWriter& operator<< (CallWriter& writer, const char* str)
252 writer.write((const deUint8*)str + pos, sizeof(char));