diff options
author | Andrey Lihatskiy <alihatskiy@productengine.com> | 2021-03-09 21:56:14 +0200 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2021-03-09 21:56:14 +0200 |
commit | bb17e4b78e37daec481dede64ee7fdaf5a05b205 (patch) | |
tree | e7fe1c4e05b5a782012eacdb437042c02876b68f /indra/llvfs/lllfsthread.cpp | |
parent | 54c2608d45e5b0368a07e383046a465375ccb03f (diff) | |
parent | 88d837c16e768c5262073a7df965066d4bd8842c (diff) |
Merge branch 'master' into DRTVWR-515-maint
Diffstat (limited to 'indra/llvfs/lllfsthread.cpp')
-rw-r--r-- | indra/llvfs/lllfsthread.cpp | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/indra/llvfs/lllfsthread.cpp b/indra/llvfs/lllfsthread.cpp new file mode 100644 index 0000000000..be8e83a56f --- /dev/null +++ b/indra/llvfs/lllfsthread.cpp @@ -0,0 +1,245 @@ +/** + * @file lllfsthread.cpp + * @brief LLLFSThread base class + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "lllfsthread.h" +#include "llstl.h" +#include "llapr.h" + +//============================================================================ + +/*static*/ LLLFSThread* LLLFSThread::sLocal = NULL; + +//============================================================================ +// Run on MAIN thread +//static +void LLLFSThread::initClass(bool local_is_threaded) +{ + llassert(sLocal == NULL); + sLocal = new LLLFSThread(local_is_threaded); +} + +//static +S32 LLLFSThread::updateClass(U32 ms_elapsed) +{ + sLocal->update((F32)ms_elapsed); + return sLocal->getPending(); +} + +//static +void LLLFSThread::cleanupClass() +{ + llassert(sLocal != NULL); + sLocal->setQuitting(); + while (sLocal->getPending()) + { + sLocal->update(0); + } + delete sLocal; + sLocal = NULL; +} + +//---------------------------------------------------------------------------- + +LLLFSThread::LLLFSThread(bool threaded) : + LLQueuedThread("LFS", threaded), + mPriorityCounter(PRIORITY_LOWBITS) +{ + if(!mLocalAPRFilePoolp) + { + mLocalAPRFilePoolp = new LLVolatileAPRPool() ; + } +} + +LLLFSThread::~LLLFSThread() +{ + // mLocalAPRFilePoolp cleanup in LLThread + // ~LLQueuedThread() will be called here +} + +//---------------------------------------------------------------------------- + +LLLFSThread::handle_t LLLFSThread::read(const std::string& filename, /* Flawfinder: ignore */ + U8* buffer, S32 offset, S32 numbytes, + Responder* responder, U32 priority) +{ + handle_t handle = generateHandle(); + + if (priority == 0) priority = PRIORITY_NORMAL | priorityCounter(); + else if (priority < PRIORITY_LOW) priority |= PRIORITY_LOW; // All reads are at least PRIORITY_LOW + + Request* req = new Request(this, handle, priority, + FILE_READ, filename, + buffer, offset, numbytes, + responder); + + bool res = addRequest(req); + if (!res) + { + LL_ERRS() << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << LL_ENDL; + } + + return handle; +} + +LLLFSThread::handle_t LLLFSThread::write(const std::string& filename, + U8* buffer, S32 offset, S32 numbytes, + Responder* responder, U32 priority) +{ + handle_t handle = generateHandle(); + + if (priority == 0) priority = PRIORITY_LOW | priorityCounter(); + + Request* req = new Request(this, handle, priority, + FILE_WRITE, filename, + buffer, offset, numbytes, + responder); + + bool res = addRequest(req); + if (!res) + { + LL_ERRS() << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << LL_ENDL; + } + + return handle; +} + +//============================================================================ + +LLLFSThread::Request::Request(LLLFSThread* thread, + handle_t handle, U32 priority, + operation_t op, const std::string& filename, + U8* buffer, S32 offset, S32 numbytes, + Responder* responder) : + QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE), + mThread(thread), + mOperation(op), + mFileName(filename), + mBuffer(buffer), + mOffset(offset), + mBytes(numbytes), + mBytesRead(0), + mResponder(responder) +{ + if (numbytes <= 0) + { + LL_WARNS() << "LLLFSThread: Request with numbytes = " << numbytes << LL_ENDL; + } +} + +LLLFSThread::Request::~Request() +{ +} + +// virtual, called from own thread +void LLLFSThread::Request::finishRequest(bool completed) +{ + if (mResponder.notNull()) + { + mResponder->completed(completed ? mBytesRead : 0); + mResponder = NULL; + } +} + +void LLLFSThread::Request::deleteRequest() +{ + if (getStatus() == STATUS_QUEUED) + { + LL_ERRS() << "Attempt to delete a queued LLLFSThread::Request!" << LL_ENDL; + } + if (mResponder.notNull()) + { + mResponder->completed(0); + mResponder = NULL; + } + LLQueuedThread::QueuedRequest::deleteRequest(); +} + +bool LLLFSThread::Request::processRequest() +{ + bool complete = false; + if (mOperation == FILE_READ) + { + llassert(mOffset >= 0); + LLAPRFile infile ; // auto-closes + infile.open(mFileName, LL_APR_RB, mThread->getLocalAPRFilePool()); + if (!infile.getFileHandle()) + { + LL_WARNS() << "LLLFS: Unable to read file: " << mFileName << LL_ENDL; + mBytesRead = 0; // fail + return true; + } + S32 off; + if (mOffset < 0) + off = infile.seek(APR_END, 0); + else + off = infile.seek(APR_SET, mOffset); + llassert_always(off >= 0); + mBytesRead = infile.read(mBuffer, mBytes ); + complete = true; +// LL_INFOS() << "LLLFSThread::READ:" << mFileName << " Bytes: " << mBytesRead << LL_ENDL; + } + else if (mOperation == FILE_WRITE) + { + apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; + if (mOffset < 0) + flags |= APR_APPEND; + LLAPRFile outfile ; // auto-closes + outfile.open(mFileName, flags, mThread->getLocalAPRFilePool()); + if (!outfile.getFileHandle()) + { + LL_WARNS() << "LLLFS: Unable to write file: " << mFileName << LL_ENDL; + mBytesRead = 0; // fail + return true; + } + if (mOffset >= 0) + { + S32 seek = outfile.seek(APR_SET, mOffset); + if (seek < 0) + { + LL_WARNS() << "LLLFS: Unable to write file (seek failed): " << mFileName << LL_ENDL; + mBytesRead = 0; // fail + return true; + } + } + mBytesRead = outfile.write(mBuffer, mBytes ); + complete = true; +// LL_INFOS() << "LLLFSThread::WRITE:" << mFileName << " Bytes: " << mBytesRead << "/" << mBytes << " Offset:" << mOffset << LL_ENDL; + } + else + { + LL_ERRS() << "LLLFSThread::unknown operation: " << (S32)mOperation << LL_ENDL; + } + return complete; +} + +//============================================================================ + +LLLFSThread::Responder::~Responder() +{ +} + +//============================================================================ |