summaryrefslogtreecommitdiff
path: root/indra/llvfs/lllfsthread.cpp
diff options
context:
space:
mode:
authorAndrey Lihatskiy <alihatskiy@productengine.com>2021-03-09 21:56:14 +0200
committerAndrey Lihatskiy <alihatskiy@productengine.com>2021-03-09 21:56:14 +0200
commitbb17e4b78e37daec481dede64ee7fdaf5a05b205 (patch)
treee7fe1c4e05b5a782012eacdb437042c02876b68f /indra/llvfs/lllfsthread.cpp
parent54c2608d45e5b0368a07e383046a465375ccb03f (diff)
parent88d837c16e768c5262073a7df965066d4bd8842c (diff)
Merge branch 'master' into DRTVWR-515-maint
Diffstat (limited to 'indra/llvfs/lllfsthread.cpp')
-rw-r--r--indra/llvfs/lllfsthread.cpp245
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()
+{
+}
+
+//============================================================================