13c827367444ee418f129b2c238299f49d3264554Jarkko Poyry/*------------------------------------------------------------------------- 23c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * drawElements Quality Program Test Executor 33c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * ------------------------------------------ 43c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * 53c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Copyright 2014 The Android Open Source Project 63c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * 73c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Licensed under the Apache License, Version 2.0 (the "License"); 83c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * you may not use this file except in compliance with the License. 93c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * You may obtain a copy of the License at 103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * 113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * http://www.apache.org/licenses/LICENSE-2.0 123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * 133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * Unless required by applicable law or agreed to in writing, software 143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * distributed under the License is distributed on an "AS IS" BASIS, 153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * See the License for the specific language governing permissions and 173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * limitations under the License. 183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * 193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*! 203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \file 213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry * \brief Cross-thread function call dispatcher. 223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry *//*--------------------------------------------------------------------*/ 233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "xeCallQueue.hpp" 253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deInt32.h" 263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry#include "deMemory.h" 273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 283c827367444ee418f129b2c238299f49d3264554Jarkko Poyryusing std::vector; 293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 303c827367444ee418f129b2c238299f49d3264554Jarkko Poyrystatic inline int getNextQueueSize (int curSize, int minNewSize) 313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return de::max(curSize*2, 1<<deLog2Ceil32(minNewSize)); 333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 353c827367444ee418f129b2c238299f49d3264554Jarkko Poyrynamespace xe 363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// CallQueue 393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 403c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCallQueue::CallQueue (void) 415717785063a5db999d8f5a1cc067eba5fcc7409aMika Isojärvi : m_canceled (false) 425717785063a5db999d8f5a1cc067eba5fcc7409aMika Isojärvi , m_callSem (0) 433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry , m_callQueue (64) 443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 473c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCallQueue::~CallQueue (void) 483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Destroy all calls. 503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (vector<Call*>::iterator i = m_calls.begin(); i != m_calls.end(); i++) 513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry delete *i; 523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 545717785063a5db999d8f5a1cc067eba5fcc7409aMika Isojärvivoid CallQueue::cancel (void) 555717785063a5db999d8f5a1cc067eba5fcc7409aMika Isojärvi{ 565717785063a5db999d8f5a1cc067eba5fcc7409aMika Isojärvi m_canceled = true; 575717785063a5db999d8f5a1cc067eba5fcc7409aMika Isojärvi m_callSem.increment(); 585717785063a5db999d8f5a1cc067eba5fcc7409aMika Isojärvi} 595717785063a5db999d8f5a1cc067eba5fcc7409aMika Isojärvi 603c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid CallQueue::callNext (void) 613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry Call* call = DE_NULL; 633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 643c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Wait for a call. 653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_callSem.decrement(); 663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 675717785063a5db999d8f5a1cc067eba5fcc7409aMika Isojärvi if (m_canceled) 685717785063a5db999d8f5a1cc067eba5fcc7409aMika Isojärvi return; 695717785063a5db999d8f5a1cc067eba5fcc7409aMika Isojärvi 703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Acquire call from buffer. 713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 723c827367444ee418f129b2c238299f49d3264554Jarkko Poyry de::ScopedLock lock(m_lock); 733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry call = m_callQueue.popBack(); 743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry try 773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 783c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // \note Enqueue lock is not held during call so it is possible to enqueue more work from dispatched call. 791592f16d1fc9edde443474e1835746f705ed79a9Jarkko Pöyry CallReader reader(call); 801592f16d1fc9edde443474e1835746f705ed79a9Jarkko Pöyry 811592f16d1fc9edde443474e1835746f705ed79a9Jarkko Pöyry call->getFunction()(reader); 821592f16d1fc9edde443474e1835746f705ed79a9Jarkko Pöyry 831592f16d1fc9edde443474e1835746f705ed79a9Jarkko Pöyry // check callee consumed all 841592f16d1fc9edde443474e1835746f705ed79a9Jarkko Pöyry DE_ASSERT(reader.isDataConsumed()); 853c827367444ee418f129b2c238299f49d3264554Jarkko Poyry call->clear(); 863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry catch (const std::exception&) 883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry try 903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Try to push call into free calls list. 923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry de::ScopedLock lock(m_lock); 933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_freeCalls.push_back(call); 943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 953c827367444ee418f129b2c238299f49d3264554Jarkko Poyry catch (const std::exception&) 963c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 973c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // We can't do anything but ignore this. 983c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 993c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1003c827367444ee418f129b2c238299f49d3264554Jarkko Poyry throw; 1013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Push back to free calls list. 1043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 1053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry de::ScopedLock lock(m_lock); 1063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_freeCalls.push_back(call); 1073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1103c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCall* CallQueue::getEmptyCall (void) 1113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 1123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry de::ScopedLock lock (m_lock); 1133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry Call* call = DE_NULL; 1143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Try to get from free calls list. 1163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!m_freeCalls.empty()) 1173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 1183c827367444ee418f129b2c238299f49d3264554Jarkko Poyry call = m_freeCalls.back(); 1193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_freeCalls.pop_back(); 1203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // If no free calls were available, create a new. 1233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!call) 1243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 1253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_calls.reserve(m_calls.size()+1); 1263c827367444ee418f129b2c238299f49d3264554Jarkko Poyry call = new Call(); 1273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_calls.push_back(call); 1283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return call; 1313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1323c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1333c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid CallQueue::enqueue (Call* call) 1343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 1353c827367444ee418f129b2c238299f49d3264554Jarkko Poyry de::ScopedLock lock(m_lock); 1363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (m_callQueue.getNumFree() == 0) 1383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 1393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry // Call queue must be grown. 1403c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_callQueue.resize(getNextQueueSize(m_callQueue.getSize(), m_callQueue.getSize()+1)); 1413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 1423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_callQueue.pushFront(call); 1443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_callSem.increment(); 1453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1473c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid CallQueue::freeCall (Call* call) 1483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 1493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry de::ScopedLock lock(m_lock); 1503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_freeCalls.push_back(call); 1513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// Call 1543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1553c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCall::Call (void) 1563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry : m_func(DE_NULL) 1573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 1583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1603c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCall::~Call (void) 1613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 1623c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1633c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1643c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid Call::clear (void) 1653c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 1663c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_func = DE_NULL; 1673c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_data.clear(); 1683c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1693c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1703c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// CallReader 1713c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1723c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCallReader::CallReader (Call* call) 1733c827367444ee418f129b2c238299f49d3264554Jarkko Poyry : m_call (call) 1743c827367444ee418f129b2c238299f49d3264554Jarkko Poyry , m_curPos (0) 1753c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 1763c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1773c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 178745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyryvoid CallReader::read (deUint8* bytes, size_t numBytes) 1793c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 1803c827367444ee418f129b2c238299f49d3264554Jarkko Poyry DE_ASSERT(m_curPos + numBytes <= m_call->getDataSize()); 1813c827367444ee418f129b2c238299f49d3264554Jarkko Poyry deMemcpy(bytes, m_call->getData()+m_curPos, numBytes); 1823c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_curPos += numBytes; 1833c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1843c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 185745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyryconst deUint8* CallReader::getDataBlock (size_t numBytes) 1863c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 1873c827367444ee418f129b2c238299f49d3264554Jarkko Poyry DE_ASSERT(m_curPos + numBytes <= m_call->getDataSize()); 1883c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1893c827367444ee418f129b2c238299f49d3264554Jarkko Poyry const deUint8* ptr = m_call->getData()+m_curPos; 1903c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_curPos += numBytes; 1913c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1923c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return ptr; 1933c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 1943c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 1951592f16d1fc9edde443474e1835746f705ed79a9Jarkko Pöyrybool CallReader::isDataConsumed (void) const 1961592f16d1fc9edde443474e1835746f705ed79a9Jarkko Pöyry{ 1971592f16d1fc9edde443474e1835746f705ed79a9Jarkko Pöyry return m_curPos == m_call->getDataSize(); 1981592f16d1fc9edde443474e1835746f705ed79a9Jarkko Pöyry} 1991592f16d1fc9edde443474e1835746f705ed79a9Jarkko Pöyry 2003c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCallReader& operator>> (CallReader& reader, std::string& value) 2013c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 2023c827367444ee418f129b2c238299f49d3264554Jarkko Poyry value.clear(); 2033c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (;;) 2043c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 2053c827367444ee418f129b2c238299f49d3264554Jarkko Poyry char c; 2063c827367444ee418f129b2c238299f49d3264554Jarkko Poyry reader.read((deUint8*)&c, sizeof(char)); 2073c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (c != 0) 2083c827367444ee418f129b2c238299f49d3264554Jarkko Poyry value.push_back(c); 2093c827367444ee418f129b2c238299f49d3264554Jarkko Poyry else 2103c827367444ee418f129b2c238299f49d3264554Jarkko Poyry break; 2113c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 2123c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2133c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return reader; 2143c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 2153c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2163c827367444ee418f129b2c238299f49d3264554Jarkko Poyry// CallWriter 2173c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2183c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCallWriter::CallWriter (CallQueue* queue, Call::Function function) 2193c827367444ee418f129b2c238299f49d3264554Jarkko Poyry : m_queue (queue) 2203c827367444ee418f129b2c238299f49d3264554Jarkko Poyry , m_call (queue->getEmptyCall()) 2213c827367444ee418f129b2c238299f49d3264554Jarkko Poyry , m_enqueued (false) 2223c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 2233c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_call->setFunction(function); 2243c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 2253c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2263c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCallWriter::~CallWriter (void) 2273c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 2283c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (!m_enqueued) 2293c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_queue->freeCall(m_call); 2303c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 2313c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 232745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyryvoid CallWriter::write (const deUint8* bytes, size_t numBytes) 2333c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 2343c827367444ee418f129b2c238299f49d3264554Jarkko Poyry DE_ASSERT(!m_enqueued); 235745d7c616351405cfb6d2a7133d261eb4989d626Jarkko Pöyry size_t curPos = m_call->getDataSize(); 2363c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_call->setDataSize(curPos+numBytes); 2373c827367444ee418f129b2c238299f49d3264554Jarkko Poyry deMemcpy(m_call->getData()+curPos, bytes, numBytes); 2383c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 2393c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2403c827367444ee418f129b2c238299f49d3264554Jarkko Poyryvoid CallWriter::enqueue (void) 2413c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 2423c827367444ee418f129b2c238299f49d3264554Jarkko Poyry DE_ASSERT(!m_enqueued); 2433c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_queue->enqueue(m_call); 2443c827367444ee418f129b2c238299f49d3264554Jarkko Poyry m_enqueued = true; 2453c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 2463c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2473c827367444ee418f129b2c238299f49d3264554Jarkko PoyryCallWriter& operator<< (CallWriter& writer, const char* str) 2483c827367444ee418f129b2c238299f49d3264554Jarkko Poyry{ 2493c827367444ee418f129b2c238299f49d3264554Jarkko Poyry int pos = 0; 2503c827367444ee418f129b2c238299f49d3264554Jarkko Poyry for (;;) 2513c827367444ee418f129b2c238299f49d3264554Jarkko Poyry { 2523c827367444ee418f129b2c238299f49d3264554Jarkko Poyry writer.write((const deUint8*)str + pos, sizeof(char)); 2533c827367444ee418f129b2c238299f49d3264554Jarkko Poyry if (str[pos] == 0) 2543c827367444ee418f129b2c238299f49d3264554Jarkko Poyry break; 2553c827367444ee418f129b2c238299f49d3264554Jarkko Poyry pos += 1; 2563c827367444ee418f129b2c238299f49d3264554Jarkko Poyry } 2573c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2583c827367444ee418f129b2c238299f49d3264554Jarkko Poyry return writer; 2593c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} 2603c827367444ee418f129b2c238299f49d3264554Jarkko Poyry 2613c827367444ee418f129b2c238299f49d3264554Jarkko Poyry} // xe 262