diff --git a/libs/image/tiles3/swap/kis_memory_window.cpp b/libs/image/tiles3/swap/kis_memory_window.cpp index 7c0fae6fd9..50454a5312 100644 --- a/libs/image/tiles3/swap/kis_memory_window.cpp +++ b/libs/image/tiles3/swap/kis_memory_window.cpp @@ -1,150 +1,150 @@ /* * Copyright (c) 2010 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_debug.h" #include "kis_memory_window.h" #include #define SWP_PREFIX "KRITA_SWAP_FILE_XXXXXX" KisMemoryWindow::KisMemoryWindow(const QString &swapDir, quint64 writeWindowSize) : m_readWindowEx(writeWindowSize / 4), m_writeWindowEx(writeWindowSize) { m_valid = true; // swapDir will never be empty, as KisImageConfig::swapDir() always provides // us with a (platform specific) default directory, even if none is explicitly // configured by the user; also we do not want any logic that determines the // default swap dir here. - Q_ASSERT(!swapDir.isEmpty()); + KIS_SAFE_ASSERT_RECOVER_NOOP(!swapDir.isEmpty()); QDir d(swapDir); if (!d.exists()) { m_valid = d.mkpath(swapDir); } const QString swapFileTemplate = swapDir + QDir::separator() + SWP_PREFIX; if (m_valid) { m_file.setFileTemplate(swapFileTemplate); bool res = m_file.open(); if (!res || m_file.fileName().isEmpty()) { m_valid = false; } } if (!m_valid) { qWarning() << "Could not create or open swapfile; disabling swapfile" << swapFileTemplate; } } KisMemoryWindow::~KisMemoryWindow() { } quint8* KisMemoryWindow::getReadChunkPtr(const KisChunkData &readChunk) { if (!adjustWindow(readChunk, &m_readWindowEx, &m_writeWindowEx)) { return nullptr; } return m_readWindowEx.calculatePointer(readChunk); } quint8* KisMemoryWindow::getWriteChunkPtr(const KisChunkData &writeChunk) { if (!adjustWindow(writeChunk, &m_writeWindowEx, &m_readWindowEx)) { return nullptr; } return m_writeWindowEx.calculatePointer(writeChunk); } bool KisMemoryWindow::adjustWindow(const KisChunkData &requestedChunk, MappingWindow *adjustingWindow, MappingWindow *otherWindow) { if(!(adjustingWindow->window) || !(requestedChunk.m_begin >= adjustingWindow->chunk.m_begin && requestedChunk.m_end <= adjustingWindow->chunk.m_end)) { m_file.unmap(adjustingWindow->window); quint64 windowSize = adjustingWindow->defaultSize; if(requestedChunk.size() > windowSize) { warnKrita << "KisMemoryWindow: the requested chunk is too " "big to fit into the mapping! " "Adjusting mapping to avoid SIGSEGV..."; windowSize = requestedChunk.size(); } adjustingWindow->chunk.setChunk(requestedChunk.m_begin, windowSize); if(adjustingWindow->chunk.m_end >= (quint64)m_file.size()) { // Align by 32 bytes quint64 newSize = (adjustingWindow->chunk.m_end + 1 + 32) & (~31ULL); #ifdef Q_OS_WIN32 /** * Workaround for Qt's "feature" * * On windows QFSEnginePrivate caches the value of * mapHandle which is limited to the size of the file at * the moment of its (handle's) creation. That is we will * not be able to use it after resizing the file. The * only way to free the handle is to release all the * mappings we have. Sad but true. */ if (otherWindow->chunk.size()) { m_file.unmap(otherWindow->window); } #else Q_UNUSED(otherWindow); #endif if (!m_file.resize(newSize)) { return false; } #ifdef Q_OS_WIN32 if (otherWindow->chunk.size()) { otherWindow->window = m_file.map(otherWindow->chunk.m_begin, otherWindow->chunk.size()); } #endif } #ifdef Q_OS_UNIX // A workaround for https://bugreports.qt-project.org/browse/QTBUG-6330 m_file.exists(); #endif adjustingWindow->window = m_file.map(adjustingWindow->chunk.m_begin, adjustingWindow->chunk.size()); if (!adjustingWindow->window) { return false; } } return true; } diff --git a/libs/image/tiles3/tests/kis_memory_window_test.cpp b/libs/image/tiles3/tests/kis_memory_window_test.cpp index 81456aeb33..9ae169a7fb 100644 --- a/libs/image/tiles3/tests/kis_memory_window_test.cpp +++ b/libs/image/tiles3/tests/kis_memory_window_test.cpp @@ -1,104 +1,106 @@ /* * Copyright (c) 2010 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_memory_window_test.h" #include #include "kis_debug.h" +#include #include "../swap/kis_memory_window.h" void KisMemoryWindowTest::testWindow() { - KisMemoryWindow memory(QString(), 1024); + QTemporaryDir swapDir; + KisMemoryWindow memory(swapDir.path(), 1024); quint8 oddValue = 0xee; const quint8 chunkLength = 10; quint8 oddBuf[chunkLength]; memset(oddBuf, oddValue, chunkLength); KisChunkData chunk1(0, chunkLength); KisChunkData chunk2(1025, chunkLength); quint8 *ptr; ptr = memory.getWriteChunkPtr(chunk1); memcpy(ptr, oddBuf, chunkLength); ptr = memory.getWriteChunkPtr(chunk2); memcpy(ptr, oddBuf, chunkLength); ptr = memory.getReadChunkPtr(chunk2); QVERIFY(!memcmp(ptr, oddBuf, chunkLength)); ptr = memory.getWriteChunkPtr(chunk1); QVERIFY(!memcmp(ptr, oddBuf, chunkLength)); } void KisMemoryWindowTest::testTopReports() { // default window size in 16 MiB KisMemoryWindow memory(QString(QDir::currentPath()), DEFAULT_WINDOW_SIZE); // write 1024 chunks 4 MiB each, hi-limit 4GiB const quint8 oddValue = 0xee; const qint64 chunkLength = 4 * MiB; QScopedArrayPointer writeBuffer(new quint8[chunkLength]); memset(writeBuffer.data(), oddValue, chunkLength); QScopedArrayPointer readBuffer(new quint8[chunkLength]); qint64 maxChunk = 0; for (int i = 0; i < 1024; i++) { { int chunkIndex = qrand() % 1024; qint64 chunkStart = chunkIndex * chunkLength; maxChunk = qMax(chunkStart, maxChunk); quint8 *ptr; ptr = memory.getWriteChunkPtr(KisChunkData(chunkStart, chunkLength)); memcpy(ptr, writeBuffer.data(), chunkLength); dbgKrita << "Writing chunk at" << chunkStart / chunkLength << "MiB" << "max" << maxChunk / chunkLength; QTest::qWait(250); } { int chunkIndex = qrand() % 1024; qint64 chunkStart = chunkIndex * chunkLength; quint8 *ptr; ptr = memory.getReadChunkPtr(KisChunkData(chunkStart, chunkLength)); memcpy(readBuffer.data(), ptr, chunkLength); dbgKrita << "Reading chunk at" << chunkStart / chunkLength << "MiB" << "max" << maxChunk / chunkLength; QTest::qWait(250); } } } QTEST_MAIN(KisMemoryWindowTest)