summaryrefslogtreecommitdiff
path: root/indra/llvfs/llvfsthread.cpp
diff options
context:
space:
mode:
authorAndrey Lihatskiy <alihatskiy@productengine.com>2021-03-09 21:55:37 +0200
committerAndrey Lihatskiy <alihatskiy@productengine.com>2021-03-09 21:55:37 +0200
commita68c527eae7ba8e47d15e5a86ca7b6eff6d4d7b4 (patch)
tree0653d7d1930ceaa18a75887305f5921ae6af8259 /indra/llvfs/llvfsthread.cpp
parentc06f43adde3aeb87a1510583b6f35b9327598408 (diff)
parent88d837c16e768c5262073a7df965066d4bd8842c (diff)
Merge branch 'master' into DRTVWR-518-ui
Diffstat (limited to 'indra/llvfs/llvfsthread.cpp')
-rw-r--r--indra/llvfs/llvfsthread.cpp300
1 files changed, 300 insertions, 0 deletions
diff --git a/indra/llvfs/llvfsthread.cpp b/indra/llvfs/llvfsthread.cpp
new file mode 100644
index 0000000000..8cd85929e2
--- /dev/null
+++ b/indra/llvfs/llvfsthread.cpp
@@ -0,0 +1,300 @@
+/**
+ * @file llvfsthread.cpp
+ * @brief LLVFSThread implementation
+ *
+ * $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 "llvfsthread.h"
+#include "llstl.h"
+
+//============================================================================
+
+/*static*/ std::string LLVFSThread::sDataPath = "";
+
+/*static*/ LLVFSThread* LLVFSThread::sLocal = NULL;
+
+//============================================================================
+// Run on MAIN thread
+//static
+void LLVFSThread::initClass(bool local_is_threaded)
+{
+ llassert(sLocal == NULL);
+ sLocal = new LLVFSThread(local_is_threaded);
+}
+
+//static
+S32 LLVFSThread::updateClass(U32 ms_elapsed)
+{
+ sLocal->update((F32)ms_elapsed);
+ return sLocal->getPending();
+}
+
+//static
+void LLVFSThread::cleanupClass()
+{
+ sLocal->setQuitting();
+ while (sLocal->getPending())
+ {
+ sLocal->update(0);
+ }
+ delete sLocal;
+ sLocal = 0;
+}
+
+//----------------------------------------------------------------------------
+
+LLVFSThread::LLVFSThread(bool threaded) :
+ LLQueuedThread("VFS", threaded)
+{
+}
+
+LLVFSThread::~LLVFSThread()
+{
+ // ~LLQueuedThread() will be called here
+}
+
+//----------------------------------------------------------------------------
+
+LLVFSThread::handle_t LLVFSThread::read(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type,
+ U8* buffer, S32 offset, S32 numbytes, U32 priority, U32 flags)
+{
+ handle_t handle = generateHandle();
+
+ priority = llmax(priority, (U32)PRIORITY_LOW); // All reads are at least PRIORITY_LOW
+ Request* req = new Request(handle, priority, flags, FILE_READ, vfs, file_id, file_type,
+ buffer, offset, numbytes);
+
+ bool res = addRequest(req);
+ if (!res)
+ {
+ LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL;
+ req->deleteRequest();
+ handle = nullHandle();
+ }
+
+ return handle;
+}
+
+S32 LLVFSThread::readImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type,
+ U8* buffer, S32 offset, S32 numbytes)
+{
+ handle_t handle = generateHandle();
+
+ Request* req = new Request(handle, PRIORITY_IMMEDIATE, 0, FILE_READ, vfs, file_id, file_type,
+ buffer, offset, numbytes);
+
+ S32 res = addRequest(req) ? 1 : 0;
+ if (res == 0)
+ {
+ LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL;
+ req->deleteRequest();
+ }
+ else
+ {
+ llverify(waitForResult(handle, false) == true);
+ res = req->getBytesRead();
+ completeRequest(handle);
+ }
+ return res;
+}
+
+LLVFSThread::handle_t LLVFSThread::write(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type,
+ U8* buffer, S32 offset, S32 numbytes, U32 flags)
+{
+ handle_t handle = generateHandle();
+
+ Request* req = new Request(handle, 0, flags, FILE_WRITE, vfs, file_id, file_type,
+ buffer, offset, numbytes);
+
+ bool res = addRequest(req);
+ if (!res)
+ {
+ LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL;
+ req->deleteRequest();
+ handle = nullHandle();
+ }
+
+ return handle;
+}
+
+S32 LLVFSThread::writeImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type,
+ U8* buffer, S32 offset, S32 numbytes)
+{
+ handle_t handle = generateHandle();
+
+ Request* req = new Request(handle, PRIORITY_IMMEDIATE, 0, FILE_WRITE, vfs, file_id, file_type,
+ buffer, offset, numbytes);
+
+ S32 res = addRequest(req) ? 1 : 0;
+ if (res == 0)
+ {
+ LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL;
+ req->deleteRequest();
+ }
+ else
+ {
+ llverify(waitForResult(handle, false) == true);
+ res = req->getBytesRead();
+ completeRequest(handle);
+ }
+ return res;
+}
+
+
+// LLVFSThread::handle_t LLVFSThread::rename(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type,
+// const LLUUID &new_id, const LLAssetType::EType new_type, U32 flags)
+// {
+// handle_t handle = generateHandle();
+
+// LLUUID* new_idp = new LLUUID(new_id); // deleted with Request
+// // new_type is passed as "numbytes"
+// Request* req = new Request(handle, 0, flags, FILE_RENAME, vfs, file_id, file_type,
+// (U8*)new_idp, 0, (S32)new_type);
+
+// bool res = addRequest(req);
+// if (!res)
+// {
+// LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL;
+// req->deleteRequest();
+// handle = nullHandle();
+// }
+
+// return handle;
+// }
+
+//============================================================================
+
+LLVFSThread::Request::Request(handle_t handle, U32 priority, U32 flags,
+ operation_t op, LLVFS* vfs,
+ const LLUUID &file_id, const LLAssetType::EType file_type,
+ U8* buffer, S32 offset, S32 numbytes) :
+ QueuedRequest(handle, priority, flags),
+ mOperation(op),
+ mVFS(vfs),
+ mFileID(file_id),
+ mFileType(file_type),
+ mBuffer(buffer),
+ mOffset(offset),
+ mBytes(numbytes),
+ mBytesRead(0)
+{
+ llassert(mBuffer);
+
+ if (numbytes <= 0 && mOperation != FILE_RENAME)
+ {
+ LL_WARNS() << "LLVFSThread: Request with numbytes = " << numbytes
+ << " operation = " << op
+ << " offset " << offset
+ << " file_type " << file_type << LL_ENDL;
+ }
+ if (mOperation == FILE_WRITE)
+ {
+ S32 blocksize = mVFS->getMaxSize(mFileID, mFileType);
+ if (blocksize < 0)
+ {
+ LL_WARNS() << "VFS write to temporary block (shouldn't happen)" << LL_ENDL;
+ }
+ mVFS->incLock(mFileID, mFileType, VFSLOCK_APPEND);
+ }
+ else if (mOperation == FILE_RENAME)
+ {
+ mVFS->incLock(mFileID, mFileType, VFSLOCK_APPEND);
+ }
+ else // if (mOperation == FILE_READ)
+ {
+ mVFS->incLock(mFileID, mFileType, VFSLOCK_READ);
+ }
+}
+
+// dec locks as soon as a request finishes
+void LLVFSThread::Request::finishRequest(bool completed)
+{
+ if (mOperation == FILE_WRITE)
+ {
+ mVFS->decLock(mFileID, mFileType, VFSLOCK_APPEND);
+ }
+ else if (mOperation == FILE_RENAME)
+ {
+ mVFS->decLock(mFileID, mFileType, VFSLOCK_APPEND);
+ }
+ else // if (mOperation == FILE_READ)
+ {
+ mVFS->decLock(mFileID, mFileType, VFSLOCK_READ);
+ }
+}
+
+void LLVFSThread::Request::deleteRequest()
+{
+ if (getStatus() == STATUS_QUEUED)
+ {
+ LL_ERRS() << "Attempt to delete a queued LLVFSThread::Request!" << LL_ENDL;
+ }
+ if (mOperation == FILE_WRITE)
+ {
+ if (mFlags & FLAG_AUTO_DELETE)
+ {
+ delete [] mBuffer;
+ }
+ }
+ else if (mOperation == FILE_RENAME)
+ {
+ LLUUID* new_idp = (LLUUID*)mBuffer;
+ delete new_idp;
+ }
+ LLQueuedThread::QueuedRequest::deleteRequest();
+}
+
+bool LLVFSThread::Request::processRequest()
+{
+ bool complete = false;
+ if (mOperation == FILE_READ)
+ {
+ llassert(mOffset >= 0);
+ mBytesRead = mVFS->getData(mFileID, mFileType, mBuffer, mOffset, mBytes);
+ complete = true;
+ //LL_INFOS() << llformat("LLVFSThread::READ '%s': %d bytes arg:%d",getFilename(),mBytesRead) << LL_ENDL;
+ }
+ else if (mOperation == FILE_WRITE)
+ {
+ mBytesRead = mVFS->storeData(mFileID, mFileType, mBuffer, mOffset, mBytes);
+ complete = true;
+ //LL_INFOS() << llformat("LLVFSThread::WRITE '%s': %d bytes arg:%d",getFilename(),mBytesRead) << LL_ENDL;
+ }
+ else if (mOperation == FILE_RENAME)
+ {
+ LLUUID* new_idp = (LLUUID*)mBuffer;
+ LLAssetType::EType new_type = (LLAssetType::EType)mBytes;
+ mVFS->renameFile(mFileID, mFileType, *new_idp, new_type);
+ mFileID = *new_idp;
+ complete = true;
+ //LL_INFOS() << llformat("LLVFSThread::RENAME '%s': %d bytes arg:%d",getFilename(),mBytesRead) << LL_ENDL;
+ }
+ else
+ {
+ LL_ERRS() << llformat("LLVFSThread::unknown operation: %d", mOperation) << LL_ENDL;
+ }
+ return complete;
+}
+
+//============================================================================