PageRenderTime 55ms CodeModel.GetById 2ms app.highlight 48ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llvfs/llvfsthread.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 300 lines | 206 code | 37 blank | 57 comment | 42 complexity | 7ce7081a49ab9b791d136466089b5a4b MD5 | raw file
  1/** 
  2 * @file llvfsthread.cpp
  3 * @brief LLVFSThread implementation
  4 *
  5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28#include "llvfsthread.h"
 29#include "llstl.h"
 30
 31//============================================================================
 32
 33/*static*/ std::string LLVFSThread::sDataPath = "";
 34
 35/*static*/ LLVFSThread* LLVFSThread::sLocal = NULL;
 36
 37//============================================================================
 38// Run on MAIN thread
 39//static
 40void LLVFSThread::initClass(bool local_is_threaded)
 41{
 42	llassert(sLocal == NULL);
 43	sLocal = new LLVFSThread(local_is_threaded);
 44}
 45
 46//static
 47S32 LLVFSThread::updateClass(U32 ms_elapsed)
 48{
 49	sLocal->update(ms_elapsed);
 50	return sLocal->getPending();
 51}
 52
 53//static
 54void LLVFSThread::cleanupClass()
 55{
 56	sLocal->setQuitting();
 57	while (sLocal->getPending())
 58	{
 59		sLocal->update(0);
 60	}
 61	delete sLocal;
 62	sLocal = 0;
 63}
 64
 65//----------------------------------------------------------------------------
 66
 67LLVFSThread::LLVFSThread(bool threaded) :
 68	LLQueuedThread("VFS", threaded)
 69{
 70}
 71
 72LLVFSThread::~LLVFSThread()
 73{
 74	// ~LLQueuedThread() will be called here
 75}
 76
 77//----------------------------------------------------------------------------
 78
 79LLVFSThread::handle_t LLVFSThread::read(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type,
 80										U8* buffer, S32 offset, S32 numbytes, U32 priority, U32 flags)
 81{
 82	handle_t handle = generateHandle();
 83
 84	priority = llmax(priority, (U32)PRIORITY_LOW); // All reads are at least PRIORITY_LOW
 85	Request* req = new Request(handle, priority, flags, FILE_READ, vfs, file_id, file_type,
 86							   buffer, offset, numbytes);
 87
 88	bool res = addRequest(req);
 89	if (!res)
 90	{
 91		llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl;
 92		req->deleteRequest();
 93		handle = nullHandle();
 94	}
 95
 96	return handle;
 97}
 98
 99S32 LLVFSThread::readImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type,
100							   U8* buffer, S32 offset, S32 numbytes)
101{
102	handle_t handle = generateHandle();
103
104	Request* req = new Request(handle, PRIORITY_IMMEDIATE, 0, FILE_READ, vfs, file_id, file_type,
105							   buffer, offset, numbytes);
106	
107	S32 res = addRequest(req) ? 1 : 0;
108	if (res == 0)
109	{
110		llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl;
111		req->deleteRequest();
112	}
113	else
114	{
115		llverify(waitForResult(handle, false) == true);
116		res = req->getBytesRead();
117		completeRequest(handle);
118	}
119	return res;
120}
121
122LLVFSThread::handle_t LLVFSThread::write(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type,
123										 U8* buffer, S32 offset, S32 numbytes, U32 flags)
124{
125	handle_t handle = generateHandle();
126
127	Request* req = new Request(handle, 0, flags, FILE_WRITE, vfs, file_id, file_type,
128							   buffer, offset, numbytes);
129
130	bool res = addRequest(req);
131	if (!res)
132	{
133		llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl;
134		req->deleteRequest();
135		handle = nullHandle();
136	}
137	
138	return handle;
139}
140
141S32 LLVFSThread::writeImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type,
142								 U8* buffer, S32 offset, S32 numbytes)
143{
144	handle_t handle = generateHandle();
145
146	Request* req = new Request(handle, PRIORITY_IMMEDIATE, 0, FILE_WRITE, vfs, file_id, file_type,
147							   buffer, offset, numbytes);
148
149	S32 res = addRequest(req) ? 1 : 0;
150	if (res == 0)
151	{
152		llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl;
153		req->deleteRequest();
154	}
155	else
156	{
157		llverify(waitForResult(handle, false) == true);
158		res = req->getBytesRead();
159		completeRequest(handle);
160	}
161	return res;
162}
163
164
165// LLVFSThread::handle_t LLVFSThread::rename(LLVFS* vfs, const LLUUID &file_id, const LLAssetType::EType file_type,
166// 										  const LLUUID &new_id, const LLAssetType::EType new_type, U32 flags)
167// {
168// 	handle_t handle = generateHandle();
169
170// 	LLUUID* new_idp = new LLUUID(new_id); // deleted with Request
171// 	// new_type is passed as "numbytes"
172// 	Request* req = new Request(handle, 0, flags, FILE_RENAME, vfs, file_id, file_type,
173// 							   (U8*)new_idp, 0, (S32)new_type);
174
175// 	bool res = addRequest(req);
176// 	if (!res)
177// 	{
178// 		llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl;
179// 		req->deleteRequest();
180// 		handle = nullHandle();
181// 	}
182	
183// 	return handle;
184// }
185
186//============================================================================
187
188LLVFSThread::Request::Request(handle_t handle, U32 priority, U32 flags,
189							  operation_t op, LLVFS* vfs,
190							  const LLUUID &file_id, const LLAssetType::EType file_type,
191							  U8* buffer, S32 offset, S32 numbytes) :
192	QueuedRequest(handle, priority, flags),
193	mOperation(op),
194	mVFS(vfs),
195	mFileID(file_id),
196	mFileType(file_type),
197	mBuffer(buffer),
198	mOffset(offset),
199	mBytes(numbytes),
200	mBytesRead(0)
201{
202	llassert(mBuffer);
203
204	if (numbytes <= 0 && mOperation != FILE_RENAME)
205	{
206		llwarns << "LLVFSThread: Request with numbytes = " << numbytes 
207			<< " operation = " << op
208			<< " offset " << offset 
209			<< " file_type " << file_type << llendl;
210	}
211	if (mOperation == FILE_WRITE)
212	{
213		S32 blocksize =  mVFS->getMaxSize(mFileID, mFileType);
214		if (blocksize < 0)
215		{
216			llwarns << "VFS write to temporary block (shouldn't happen)" << llendl;
217		}
218		mVFS->incLock(mFileID, mFileType, VFSLOCK_APPEND);
219	}
220	else if (mOperation == FILE_RENAME)
221	{
222		mVFS->incLock(mFileID, mFileType, VFSLOCK_APPEND);
223	}
224	else // if (mOperation == FILE_READ)
225	{
226		mVFS->incLock(mFileID, mFileType, VFSLOCK_READ);
227	}
228}
229
230// dec locks as soon as a request finishes
231void LLVFSThread::Request::finishRequest(bool completed)
232{
233	if (mOperation == FILE_WRITE)
234	{
235		mVFS->decLock(mFileID, mFileType, VFSLOCK_APPEND);
236	}
237	else if (mOperation == FILE_RENAME)
238	{
239		mVFS->decLock(mFileID, mFileType, VFSLOCK_APPEND);
240	}
241	else // if (mOperation == FILE_READ)
242	{
243		mVFS->decLock(mFileID, mFileType, VFSLOCK_READ);
244	}
245}
246
247void LLVFSThread::Request::deleteRequest()
248{
249	if (getStatus() == STATUS_QUEUED)
250	{
251		llerrs << "Attempt to delete a queued LLVFSThread::Request!" << llendl;
252	}	
253	if (mOperation == FILE_WRITE)
254	{
255		if (mFlags & FLAG_AUTO_DELETE)
256		{
257			delete [] mBuffer;
258		}
259	}
260	else if (mOperation == FILE_RENAME)
261	{
262		LLUUID* new_idp = (LLUUID*)mBuffer;
263		delete new_idp;
264	}
265	LLQueuedThread::QueuedRequest::deleteRequest();
266}
267
268bool LLVFSThread::Request::processRequest()
269{
270	bool complete = false;
271	if (mOperation ==  FILE_READ)
272	{
273		llassert(mOffset >= 0);
274		mBytesRead = mVFS->getData(mFileID, mFileType, mBuffer, mOffset, mBytes);
275		complete = true;
276		//llinfos << llformat("LLVFSThread::READ '%s': %d bytes arg:%d",getFilename(),mBytesRead) << llendl;
277	}
278	else if (mOperation ==  FILE_WRITE)
279	{
280		mBytesRead = mVFS->storeData(mFileID, mFileType, mBuffer, mOffset, mBytes);
281		complete = true;
282		//llinfos << llformat("LLVFSThread::WRITE '%s': %d bytes arg:%d",getFilename(),mBytesRead) << llendl;
283	}
284	else if (mOperation ==  FILE_RENAME)
285	{
286		LLUUID* new_idp = (LLUUID*)mBuffer;
287		LLAssetType::EType new_type = (LLAssetType::EType)mBytes;
288		mVFS->renameFile(mFileID, mFileType, *new_idp, new_type);
289		mFileID = *new_idp;
290		complete = true;
291		//llinfos << llformat("LLVFSThread::RENAME '%s': %d bytes arg:%d",getFilename(),mBytesRead) << llendl;
292	}
293	else
294	{
295		llerrs << llformat("LLVFSThread::unknown operation: %d", mOperation) << llendl;
296	}
297	return complete;
298}
299
300//============================================================================