llvfile.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:10k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llvfile.cpp
  3.  * @brief Implementation of virtual file
  4.  *
  5.  * $LicenseInfo:firstyear=2002&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2002-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "linden_common.h"
  33. #include "llvfile.h"
  34. #include "llerror.h"
  35. #include "llthread.h"
  36. #include "llstat.h"
  37. #include "llvfs.h"
  38. const S32 LLVFile::READ = 0x00000001;
  39. const S32 LLVFile::WRITE = 0x00000002;
  40. const S32 LLVFile::READ_WRITE = 0x00000003;  // LLVFile::READ & LLVFile::WRITE
  41. const S32 LLVFile::APPEND = 0x00000006;  // 0x00000004 & LLVFile::WRITE
  42. static LLFastTimer::DeclareTimer FTM_VFILE_WAIT("VFile Wait");
  43. //----------------------------------------------------------------------------
  44. LLVFSThread* LLVFile::sVFSThread = NULL;
  45. BOOL LLVFile::sAllocdVFSThread = FALSE;
  46. //----------------------------------------------------------------------------
  47. //============================================================================
  48. LLVFile::LLVFile(LLVFS *vfs, const LLUUID &file_id, const LLAssetType::EType file_type, S32 mode)
  49. {
  50. mFileType = file_type;
  51. mFileID = file_id;
  52. mPosition = 0;
  53. mMode = mode;
  54. mVFS = vfs;
  55. mBytesRead = 0;
  56. mHandle = LLVFSThread::nullHandle();
  57. mPriority = 128.f;
  58. mVFS->incLock(mFileID, mFileType, VFSLOCK_OPEN);
  59. }
  60. LLVFile::~LLVFile()
  61. {
  62. if (!isReadComplete())
  63. {
  64. if (mHandle != LLVFSThread::nullHandle())
  65. {
  66. if (!(mMode & LLVFile::WRITE))
  67. {
  68. //llwarns << "Destroying LLVFile with pending async read/write, aborting..." << llendl;
  69. sVFSThread->setFlags(mHandle, LLVFSThread::FLAG_AUTO_COMPLETE | LLVFSThread::FLAG_ABORT);
  70. }
  71. else // WRITE
  72. {
  73. sVFSThread->setFlags(mHandle, LLVFSThread::FLAG_AUTO_COMPLETE);
  74. }
  75. }
  76. }
  77. mVFS->decLock(mFileID, mFileType, VFSLOCK_OPEN);
  78. }
  79. BOOL LLVFile::read(U8 *buffer, S32 bytes, BOOL async, F32 priority)
  80. {
  81. if (! (mMode & READ))
  82. {
  83. llwarns << "Attempt to read from file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
  84. return FALSE;
  85. }
  86. if (mHandle != LLVFSThread::nullHandle())
  87. {
  88. llwarns << "Attempt to read from vfile object " << mFileID << " with pending async operation" << llendl;
  89. return FALSE;
  90. }
  91. mPriority = priority;
  92. BOOL success = TRUE;
  93. // We can't do a read while there are pending async writes
  94. waitForLock(VFSLOCK_APPEND);
  95. // *FIX: (???)
  96. if (async)
  97. {
  98. mHandle = sVFSThread->read(mVFS, mFileID, mFileType, buffer, mPosition, bytes, threadPri());
  99. }
  100. else
  101. {
  102. // We can't do a read while there are pending async writes on this file
  103. mBytesRead = sVFSThread->readImmediate(mVFS, mFileID, mFileType, buffer, mPosition, bytes);
  104. mPosition += mBytesRead;
  105. if (! mBytesRead)
  106. {
  107. success = FALSE;
  108. }
  109. }
  110. return success;
  111. }
  112. //static
  113. U8* LLVFile::readFile(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, S32* bytes_read)
  114. {
  115. U8 *data;
  116. LLVFile file(vfs, uuid, type, LLVFile::READ);
  117. S32 file_size = file.getSize();
  118. if (file_size == 0)
  119. {
  120. // File is empty.
  121. data = NULL;
  122. }
  123. else
  124. {
  125. data = new U8[file_size];
  126. file.read(data, file_size); /* Flawfinder: ignore */ 
  127. if (file.getLastBytesRead() != (S32)file_size)
  128. {
  129. delete[] data;
  130. data = NULL;
  131. file_size = 0;
  132. }
  133. }
  134. if (bytes_read)
  135. {
  136. *bytes_read = file_size;
  137. }
  138. return data;
  139. }
  140. void LLVFile::setReadPriority(const F32 priority)
  141. {
  142. mPriority = priority;
  143. if (mHandle != LLVFSThread::nullHandle())
  144. {
  145. sVFSThread->setPriority(mHandle, threadPri());
  146. }
  147. }
  148. BOOL LLVFile::isReadComplete()
  149. {
  150. BOOL res = TRUE;
  151. if (mHandle != LLVFSThread::nullHandle())
  152. {
  153. LLVFSThread::Request* req = (LLVFSThread::Request*)sVFSThread->getRequest(mHandle);
  154. LLVFSThread::status_t status = req->getStatus();
  155. if (status == LLVFSThread::STATUS_COMPLETE)
  156. {
  157. mBytesRead = req->getBytesRead();
  158. mPosition += mBytesRead;
  159. sVFSThread->completeRequest(mHandle);
  160. mHandle = LLVFSThread::nullHandle();
  161. }
  162. else
  163. {
  164. res = FALSE;
  165. }
  166. }
  167. return res;
  168. }
  169. S32 LLVFile::getLastBytesRead()
  170. {
  171. return mBytesRead;
  172. }
  173. BOOL LLVFile::eof()
  174. {
  175. return mPosition >= getSize();
  176. }
  177. BOOL LLVFile::write(const U8 *buffer, S32 bytes)
  178. {
  179. if (! (mMode & WRITE))
  180. {
  181. llwarns << "Attempt to write to file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
  182. }
  183. if (mHandle != LLVFSThread::nullHandle())
  184. {
  185. llerrs << "Attempt to write to vfile object " << mFileID << " with pending async operation" << llendl;
  186. return FALSE;
  187. }
  188. BOOL success = TRUE;
  189. // *FIX: allow async writes? potential problem wit mPosition...
  190. if (mMode == APPEND) // all appends are async (but WRITEs are not)
  191. {
  192. U8* writebuf = new U8[bytes];
  193. memcpy(writebuf, buffer, bytes);
  194. S32 offset = -1;
  195. mHandle = sVFSThread->write(mVFS, mFileID, mFileType,
  196. writebuf, offset, bytes,
  197. LLVFSThread::FLAG_AUTO_COMPLETE | LLVFSThread::FLAG_AUTO_DELETE);
  198. mHandle = LLVFSThread::nullHandle(); // FLAG_AUTO_COMPLETE means we don't track this
  199. }
  200. else
  201. {
  202. // We can't do a write while there are pending reads or writes on this file
  203. waitForLock(VFSLOCK_READ);
  204. waitForLock(VFSLOCK_APPEND);
  205. S32 pos = (mMode & APPEND) == APPEND ? -1 : mPosition;
  206. S32 wrote = sVFSThread->writeImmediate(mVFS, mFileID, mFileType, (U8*)buffer, pos, bytes);
  207. mPosition += wrote;
  208. if (wrote < bytes)
  209. {
  210. llwarns << "Tried to write " << bytes << " bytes, actually wrote " << wrote << llendl;
  211. success = FALSE;
  212. }
  213. }
  214. return success;
  215. }
  216. //static
  217. BOOL LLVFile::writeFile(const U8 *buffer, S32 bytes, LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type)
  218. {
  219. LLVFile file(vfs, uuid, type, LLVFile::WRITE);
  220. file.setMaxSize(bytes);
  221. return file.write(buffer, bytes);
  222. }
  223. BOOL LLVFile::seek(S32 offset, S32 origin)
  224. {
  225. if (mMode == APPEND)
  226. {
  227. llwarns << "Attempt to seek on append-only file" << llendl;
  228. return FALSE;
  229. }
  230. if (-1 == origin)
  231. {
  232. origin = mPosition;
  233. }
  234. S32 new_pos = origin + offset;
  235. S32 size = getSize(); // Calls waitForLock(VFSLOCK_APPEND)
  236. if (new_pos > size)
  237. {
  238. llwarns << "Attempt to seek past end of file" << llendl;
  239. mPosition = size;
  240. return FALSE;
  241. }
  242. else if (new_pos < 0)
  243. {
  244. llwarns << "Attempt to seek past beginning of file" << llendl;
  245. mPosition = 0;
  246. return FALSE;
  247. }
  248. mPosition = new_pos;
  249. return TRUE;
  250. }
  251. S32 LLVFile::tell() const
  252. {
  253. return mPosition;
  254. }
  255. S32 LLVFile::getSize()
  256. {
  257. waitForLock(VFSLOCK_APPEND);
  258. S32 size = mVFS->getSize(mFileID, mFileType);
  259. return size;
  260. }
  261. S32 LLVFile::getMaxSize()
  262. {
  263. S32 size = mVFS->getMaxSize(mFileID, mFileType);
  264. return size;
  265. }
  266. BOOL LLVFile::setMaxSize(S32 size)
  267. {
  268. if (! (mMode & WRITE))
  269. {
  270. llwarns << "Attempt to change size of file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
  271. return FALSE;
  272. }
  273. if (!mVFS->checkAvailable(size))
  274. {
  275. LLFastTimer t(FTM_VFILE_WAIT);
  276. S32 count = 0;
  277. while (sVFSThread->getPending() > 1000)
  278. {
  279. if (count % 100 == 0)
  280. {
  281. llinfos << "VFS catching up... Pending: " << sVFSThread->getPending() << llendl;
  282. }
  283. if (sVFSThread->isPaused())
  284. {
  285. sVFSThread->update(0);
  286. }
  287. ms_sleep(10);
  288. }
  289. }
  290. return mVFS->setMaxSize(mFileID, mFileType, size);
  291. }
  292. BOOL LLVFile::rename(const LLUUID &new_id, const LLAssetType::EType new_type)
  293. {
  294. if (! (mMode & WRITE))
  295. {
  296. llwarns << "Attempt to rename file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
  297. return FALSE;
  298. }
  299. if (mHandle != LLVFSThread::nullHandle())
  300. {
  301. llwarns << "Renaming file with pending async read" << llendl;
  302. }
  303. waitForLock(VFSLOCK_READ);
  304. waitForLock(VFSLOCK_APPEND);
  305. // we need to release / replace our own lock
  306. // since the renamed file will inherit locks from the new name
  307. mVFS->decLock(mFileID, mFileType, VFSLOCK_OPEN);
  308. mVFS->renameFile(mFileID, mFileType, new_id, new_type);
  309. mVFS->incLock(new_id, new_type, VFSLOCK_OPEN);
  310. mFileID = new_id;
  311. mFileType = new_type;
  312. return TRUE;
  313. }
  314. BOOL LLVFile::remove()
  315. {
  316. //  llinfos << "Removing file " << mFileID << llendl;
  317. if (! (mMode & WRITE))
  318. {
  319. // Leaving paranoia warning just because this should be a very infrequent
  320. // operation.
  321. llwarns << "Remove file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
  322. }
  323. if (mHandle != LLVFSThread::nullHandle())
  324. {
  325. llwarns << "Removing file with pending async read" << llendl;
  326. }
  327. // why not seek back to the beginning of the file too?
  328. mPosition = 0;
  329. waitForLock(VFSLOCK_READ);
  330. waitForLock(VFSLOCK_APPEND);
  331. mVFS->removeFile(mFileID, mFileType);
  332. return TRUE;
  333. }
  334. // static
  335. void LLVFile::initClass(LLVFSThread* vfsthread)
  336. {
  337. if (!vfsthread)
  338. {
  339. if (LLVFSThread::sLocal != NULL)
  340. {
  341. vfsthread = LLVFSThread::sLocal;
  342. }
  343. else
  344. {
  345. vfsthread = new LLVFSThread();
  346. sAllocdVFSThread = TRUE;
  347. }
  348. }
  349. sVFSThread = vfsthread;
  350. }
  351. // static
  352. void LLVFile::cleanupClass()
  353. {
  354. if (sAllocdVFSThread)
  355. {
  356. delete sVFSThread;
  357. }
  358. sVFSThread = NULL;
  359. }
  360. bool LLVFile::isLocked(EVFSLock lock)
  361. {
  362. return mVFS->isLocked(mFileID, mFileType, lock) ? true : false;
  363. }
  364. void LLVFile::waitForLock(EVFSLock lock)
  365. {
  366. LLFastTimer t(FTM_VFILE_WAIT);
  367. // spin until the lock clears
  368. while (isLocked(lock))
  369. {
  370. if (sVFSThread->isPaused())
  371. {
  372. sVFSThread->update(0);
  373. }
  374. ms_sleep(1);
  375. }
  376. }