PageRenderTime 29ms CodeModel.GetById 15ms app.highlight 11ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llvfs/lllfsthread.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 243 lines | 174 code | 29 blank | 40 comment | 27 complexity | e24223b915c8513f8cd102b3ad090dad MD5 | raw file
  1/** 
  2 * @file lllfsthread.cpp
  3 * @brief LLLFSThread base class
  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 "lllfsthread.h"
 29#include "llstl.h"
 30#include "llapr.h"
 31
 32//============================================================================
 33
 34/*static*/ LLLFSThread* LLLFSThread::sLocal = NULL;
 35
 36//============================================================================
 37// Run on MAIN thread
 38//static
 39void LLLFSThread::initClass(bool local_is_threaded)
 40{
 41	llassert(sLocal == NULL);
 42	sLocal = new LLLFSThread(local_is_threaded);
 43}
 44
 45//static
 46S32 LLLFSThread::updateClass(U32 ms_elapsed)
 47{
 48	sLocal->update(ms_elapsed);
 49	return sLocal->getPending();
 50}
 51
 52//static
 53void LLLFSThread::cleanupClass()
 54{
 55	sLocal->setQuitting();
 56	while (sLocal->getPending())
 57	{
 58		sLocal->update(0);
 59	}
 60	delete sLocal;
 61	sLocal = 0;
 62}
 63
 64//----------------------------------------------------------------------------
 65
 66LLLFSThread::LLLFSThread(bool threaded) :
 67	LLQueuedThread("LFS", threaded),
 68	mPriorityCounter(PRIORITY_LOWBITS)
 69{
 70	if(!mLocalAPRFilePoolp)
 71	{
 72		mLocalAPRFilePoolp = new LLVolatileAPRPool() ;
 73	}
 74}
 75
 76LLLFSThread::~LLLFSThread()
 77{
 78	// ~LLQueuedThread() will be called here
 79}
 80
 81//----------------------------------------------------------------------------
 82
 83LLLFSThread::handle_t LLLFSThread::read(const std::string& filename,	/* Flawfinder: ignore */ 
 84										U8* buffer, S32 offset, S32 numbytes,
 85										Responder* responder, U32 priority)
 86{
 87	handle_t handle = generateHandle();
 88
 89	if (priority == 0) priority = PRIORITY_NORMAL | priorityCounter();
 90	else if (priority < PRIORITY_LOW) priority |= PRIORITY_LOW; // All reads are at least PRIORITY_LOW
 91
 92	Request* req = new Request(this, handle, priority,
 93							   FILE_READ, filename,
 94							   buffer, offset, numbytes,
 95							   responder);
 96
 97	bool res = addRequest(req);
 98	if (!res)
 99	{
100		llerrs << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << llendl;
101	}
102
103	return handle;
104}
105
106LLLFSThread::handle_t LLLFSThread::write(const std::string& filename,
107										 U8* buffer, S32 offset, S32 numbytes,
108										 Responder* responder, U32 priority)
109{
110	handle_t handle = generateHandle();
111
112	if (priority == 0) priority = PRIORITY_LOW | priorityCounter();
113	
114	Request* req = new Request(this, handle, priority,
115							   FILE_WRITE, filename,
116							   buffer, offset, numbytes,
117							   responder);
118
119	bool res = addRequest(req);
120	if (!res)
121	{
122		llerrs << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << llendl;
123	}
124	
125	return handle;
126}
127
128//============================================================================
129
130LLLFSThread::Request::Request(LLLFSThread* thread,
131							  handle_t handle, U32 priority,
132							  operation_t op, const std::string& filename,
133							  U8* buffer, S32 offset, S32 numbytes,
134							  Responder* responder) :
135	QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE),
136	mThread(thread),
137	mOperation(op),
138	mFileName(filename),
139	mBuffer(buffer),
140	mOffset(offset),
141	mBytes(numbytes),
142	mBytesRead(0),
143	mResponder(responder)
144{
145	if (numbytes <= 0)
146	{
147		llwarns << "LLLFSThread: Request with numbytes = " << numbytes << llendl;
148	}
149}
150
151LLLFSThread::Request::~Request()
152{
153}
154
155// virtual, called from own thread
156void LLLFSThread::Request::finishRequest(bool completed)
157{
158	if (mResponder.notNull())
159	{
160		mResponder->completed(completed ? mBytesRead : 0);
161		mResponder = NULL;
162	}
163}
164
165void LLLFSThread::Request::deleteRequest()
166{
167	if (getStatus() == STATUS_QUEUED)
168	{
169		llerrs << "Attempt to delete a queued LLLFSThread::Request!" << llendl;
170	}	
171	if (mResponder.notNull())
172	{
173		mResponder->completed(0);
174		mResponder = NULL;
175	}
176	LLQueuedThread::QueuedRequest::deleteRequest();
177}
178
179bool LLLFSThread::Request::processRequest()
180{
181	bool complete = false;
182	if (mOperation ==  FILE_READ)
183	{
184		llassert(mOffset >= 0);
185		LLAPRFile infile ; // auto-closes
186		infile.open(mFileName, LL_APR_RB, mThread->getLocalAPRFilePool());
187		if (!infile.getFileHandle())
188		{
189			llwarns << "LLLFS: Unable to read file: " << mFileName << llendl;
190			mBytesRead = 0; // fail
191			return true;
192		}
193		S32 off;
194		if (mOffset < 0)
195			off = infile.seek(APR_END, 0);
196		else
197			off = infile.seek(APR_SET, mOffset);
198		llassert_always(off >= 0);
199		mBytesRead = infile.read(mBuffer, mBytes );
200		complete = true;
201// 		llinfos << "LLLFSThread::READ:" << mFileName << " Bytes: " << mBytesRead << llendl;
202	}
203	else if (mOperation ==  FILE_WRITE)
204	{
205		apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
206		if (mOffset < 0)
207			flags |= APR_APPEND;
208		LLAPRFile outfile ; // auto-closes
209		outfile.open(mFileName, flags, mThread->getLocalAPRFilePool());
210		if (!outfile.getFileHandle())
211		{
212			llwarns << "LLLFS: Unable to write file: " << mFileName << llendl;
213			mBytesRead = 0; // fail
214			return true;
215		}
216		if (mOffset >= 0)
217		{
218			S32 seek = outfile.seek(APR_SET, mOffset);
219			if (seek < 0)
220			{
221				llwarns << "LLLFS: Unable to write file (seek failed): " << mFileName << llendl;
222				mBytesRead = 0; // fail
223				return true;
224			}
225		}
226		mBytesRead = outfile.write(mBuffer, mBytes );
227		complete = true;
228// 		llinfos << "LLLFSThread::WRITE:" << mFileName << " Bytes: " << mBytesRead << "/" << mBytes << " Offset:" << mOffset << llendl;
229	}
230	else
231	{
232		llerrs << "LLLFSThread::unknown operation: " << (S32)mOperation << llendl;
233	}
234	return complete;
235}
236
237//============================================================================
238
239LLLFSThread::Responder::~Responder()
240{
241}
242
243//============================================================================