Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2546 lines
71 KiB

  1. //========== Copyright � 2009, Valve Corporation, All rights reserved. ========
  2. //
  3. // file: filesystem_newasync.cpp
  4. //
  5. // Purpose: Upgraded Async I/O system for source 2.0
  6. //
  7. //
  8. // System Support (so far): Win32, 360 (see #POSIX usage in filesystem_async.cpp)
  9. //
  10. //=============================================================================
  11. #include "basefilesystem.h"
  12. #include "filesystem.h"
  13. #include "filesystemasync.h"
  14. #include "threadtools.h"
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include "tier0/memdbgon.h"
  17. #ifdef _DEBUG
  18. #define VALIDATE_REQUEST_MODIFICATION if ( !ValidateRequestModification() ) { return; }
  19. #else
  20. #define VALIDATE_REQUEST_MODIFICATION (void) 0;
  21. #endif
  22. //-----------------------------------------------------------------------------
  23. // Globals object instance? put in tier2.cpp?
  24. //-----------------------------------------------------------------------------
  25. extern CAsyncFileSystem g_FileSystem_Async;
  26. //-----------------------------------------------------------------------------
  27. // CAsyncRequestBase::Default Constructor
  28. // -- inits all members common to all Async Requests
  29. //-----------------------------------------------------------------------------
  30. CAsyncRequestBase::CAsyncRequestBase()
  31. {
  32. m_pOuter = NULL;
  33. m_pCallback = NULL;
  34. m_pResultQueue = NULL;
  35. m_Operation = ASYNC_OP_UNDEFINED;
  36. m_priority = 0;
  37. m_pNext = NULL;
  38. m_pPrev = NULL;
  39. m_RequestState = ASYNC_REQUEST_STATE_COMPOSING;
  40. m_RequestStatus = ASYNC_REQUEST_OK;
  41. m_bAbortRequest = false;
  42. m_bProcessingCallback = false;
  43. m_bDontAutoRelease = false;
  44. m_pSyncThreadEvent = NULL;
  45. m_pOldAsyncControl = NULL;
  46. m_pOldAsyncStatus = FSASYNC_OK;
  47. m_pGroup = NULL;
  48. }
  49. //-----------------------------------------------------------------------------
  50. // CAsyncRequestBase::Destructor
  51. //
  52. //-----------------------------------------------------------------------------
  53. CAsyncRequestBase::~CAsyncRequestBase()
  54. {
  55. RefreshCallback( NULL ); // Release functor
  56. // We do this in the base class as it will be the last destructor called
  57. g_FileSystem_Async.RemoveRequest( this ); // Tell the Async System to remove us from its lists
  58. }
  59. //-----------------------------------------------------------------------------
  60. // CAsyncRequestBase::Destructor
  61. //
  62. //-----------------------------------------------------------------------------
  63. IAsyncRequestBase* CAsyncRequestBase::GetInterfaceBase()
  64. {
  65. if ( m_pOuter != NULL )
  66. {
  67. switch ( m_Operation )
  68. {
  69. case ASYNC_OP_READFILE:
  70. case ASYNC_OP_WRITEFILE:
  71. case ASYNC_OP_APPENDFILE:
  72. {
  73. CAsyncFileRequest* pOuter = ( CAsyncFileRequest* ) m_pOuter;
  74. return static_cast< IAsyncRequestBase* >( pOuter );
  75. }
  76. case ASYNC_OP_SCANDIR:
  77. {
  78. CAsyncSearchRequest* pOuter = ( CAsyncSearchRequest* ) m_pOuter;
  79. return static_cast< IAsyncRequestBase* >( pOuter );
  80. }
  81. default:
  82. {
  83. Error( "Bad Outer in CAsyncRequestBase::DeleteOuter" );
  84. break;
  85. }
  86. }
  87. }
  88. return NULL;
  89. }
  90. //-----------------------------------------------------------------------------
  91. // CAsyncRequestBase::AssignCallback
  92. // Add a completion callback to this request
  93. //-----------------------------------------------------------------------------
  94. void CAsyncRequestBase::AssignCallback( CFunctor* pCallback )
  95. {
  96. VALIDATE_REQUEST_MODIFICATION;
  97. RefreshCallback( pCallback );
  98. }
  99. //-----------------------------------------------------------------------------
  100. // CAsyncRequestBase::AssignResultQueue
  101. // Send the results to this queue object
  102. //-----------------------------------------------------------------------------
  103. void CAsyncRequestBase::AssignResultQueue( CIOCompletionQueue* pMsgQueue )
  104. {
  105. VALIDATE_REQUEST_MODIFICATION;
  106. m_pResultQueue = pMsgQueue;
  107. }
  108. //-----------------------------------------------------------------------------
  109. // CAsyncRequestBase::AssignCallbackAndQueue
  110. //
  111. //-----------------------------------------------------------------------------
  112. void CAsyncRequestBase::AssignCallbackAndQueue( CIOCompletionQueue* pMsgQueue, CFunctor* pCallback )
  113. {
  114. VALIDATE_REQUEST_MODIFICATION;
  115. RefreshCallback( pCallback );
  116. m_pResultQueue = pMsgQueue;
  117. }
  118. //-----------------------------------------------------------------------------
  119. // CAsyncRequestBase::RefreshFileName
  120. // Change the filename, release memory held by previous
  121. //-----------------------------------------------------------------------------
  122. void CAsyncRequestBase::ProcessCallback( bool bRelease )
  123. {
  124. if ( m_RequestState != ASYNC_REQUEST_STATE_AWATING_FINISH )
  125. {
  126. Error( "Callback called at wrong time" );
  127. return;
  128. }
  129. // Callback is a one shot thing
  130. if ( m_pCallback != NULL )
  131. {
  132. m_bProcessingCallback = true;
  133. (*m_pCallback)();
  134. m_pCallback->Release();
  135. m_pCallback = NULL;
  136. m_bProcessingCallback = false;
  137. }
  138. // Callback is completed (or NULL), move to next state
  139. m_RequestState = ASYNC_REQUEST_STATE_COMPLETED;
  140. // Do we release automatically this object?
  141. if ( bRelease && !m_bDontAutoRelease )
  142. {
  143. // Upon return, this object will no longer be in the Async System...
  144. Release();
  145. }
  146. }
  147. //-----------------------------------------------------------------------------
  148. // CAsyncRequestBase::Release
  149. // Let's the user manually release/destroy an async request object
  150. // Can only be done once the request is complete, if the async system
  151. // needs to at other times, call DeleteOuter() instead
  152. //-----------------------------------------------------------------------------
  153. void CAsyncRequestBase::Release()
  154. {
  155. if ( m_RequestState != ASYNC_REQUEST_STATE_COMPLETED )
  156. {
  157. Error( "Async Request has not finished, unable to release" );
  158. return;
  159. }
  160. // The magic is in the destructor...
  161. // the destructor will detach this request from the async filesystem
  162. // and clean everything up
  163. DeleteOuter();
  164. }
  165. //-----------------------------------------------------------------------------
  166. // CAsyncRequestBase::DeleteOuter
  167. // calls the destructor on the containing object
  168. // must update this when adding a new async request type
  169. //-----------------------------------------------------------------------------
  170. void CAsyncRequestBase::DeleteOuter()
  171. {
  172. if ( m_pOuter != NULL )
  173. {
  174. switch ( m_Operation )
  175. {
  176. case ASYNC_OP_READFILE:
  177. case ASYNC_OP_WRITEFILE:
  178. case ASYNC_OP_APPENDFILE:
  179. {
  180. CAsyncFileRequest* pOuter = ( CAsyncFileRequest* ) m_pOuter;
  181. delete pOuter;
  182. return;
  183. }
  184. case ASYNC_OP_SCANDIR:
  185. {
  186. CAsyncSearchRequest* pOuter = ( CAsyncSearchRequest* ) m_pOuter;
  187. delete pOuter;
  188. return;
  189. }
  190. default:
  191. {
  192. Error( "Bad Outer in CAsyncRequestBase::DeleteOuter" );
  193. break;
  194. }
  195. }
  196. }
  197. }
  198. //-----------------------------------------------------------------------------
  199. // CAsyncRequestBase::SetPriority
  200. //
  201. //-----------------------------------------------------------------------------
  202. void CAsyncRequestBase::SetPriority( int32 nPriority )
  203. {
  204. VALIDATE_REQUEST_MODIFICATION;
  205. m_priority = nPriority;
  206. }
  207. //-----------------------------------------------------------------------------
  208. // CAsyncRequestBase::RefreshCallback
  209. // Update the callback functor, release the previous one (if any)
  210. //-----------------------------------------------------------------------------
  211. void CAsyncRequestBase::RefreshCallback( CFunctor* pCallback )
  212. {
  213. // release existing callback
  214. if ( m_pCallback != NULL )
  215. {
  216. m_pCallback->Release();
  217. }
  218. m_pCallback = pCallback;
  219. }
  220. //-----------------------------------------------------------------------------
  221. // CAsyncRequestBase::AbortAfterServicing
  222. // calls the correct containing object's method and does any cleanup needed
  223. // by the base object
  224. //-----------------------------------------------------------------------------
  225. void CAsyncRequestBase::AbortAfterServicing( CAsyncResultInfo_t& results )
  226. {
  227. if ( m_pOuter != NULL )
  228. {
  229. switch ( m_Operation )
  230. {
  231. case ASYNC_OP_READFILE:
  232. case ASYNC_OP_WRITEFILE:
  233. case ASYNC_OP_APPENDFILE:
  234. {
  235. CAsyncFileRequest* pOuter = ( CAsyncFileRequest* ) m_pOuter;
  236. pOuter->AbortAfterServicing( results );
  237. break;
  238. }
  239. case ASYNC_OP_SCANDIR:
  240. {
  241. CAsyncSearchRequest* pOuter = ( CAsyncSearchRequest* ) m_pOuter;
  242. pOuter->AbortAfterServicing( results );
  243. break;
  244. }
  245. default:
  246. {
  247. Error( "Bad Outer in CAsyncRequestBase::AbortAfterServicing" );
  248. break;
  249. }
  250. }
  251. }
  252. }
  253. //-----------------------------------------------------------------------------
  254. // CAsyncRequestBase::UpdateAfterServicing
  255. // calls the correct containing object's method and does any update needed
  256. // by the base object
  257. //-----------------------------------------------------------------------------
  258. void CAsyncRequestBase::UpdateAfterServicing( CAsyncResultInfo_t& results )
  259. {
  260. if ( m_pOuter != NULL )
  261. {
  262. switch ( m_Operation )
  263. {
  264. case ASYNC_OP_READFILE:
  265. case ASYNC_OP_WRITEFILE:
  266. case ASYNC_OP_APPENDFILE:
  267. {
  268. CAsyncFileRequest* pOuter = ( CAsyncFileRequest* ) m_pOuter;
  269. pOuter->UpdateAfterServicing( results );
  270. break;
  271. }
  272. case ASYNC_OP_SCANDIR:
  273. {
  274. CAsyncSearchRequest* pOuter = ( CAsyncSearchRequest* ) m_pOuter;
  275. pOuter->UpdateAfterServicing( results );
  276. break;
  277. }
  278. default:
  279. {
  280. Error( "Bad Outer in CAsyncRequestBase::UpdateAfterServicing" );
  281. break;
  282. }
  283. }
  284. }
  285. }
  286. //-----------------------------------------------------------------------------
  287. // CAsyncRequestBase::ValidateSubmittedRequest
  288. // calls the correct containing object's method and does any validation needed
  289. // by the base object
  290. //-----------------------------------------------------------------------------
  291. AsyncRequestStatus_t CAsyncRequestBase::ValidateSubmittedRequest( bool bPerformSync )
  292. {
  293. if ( m_pOuter != NULL )
  294. {
  295. switch ( m_Operation )
  296. {
  297. case ASYNC_OP_READFILE:
  298. case ASYNC_OP_WRITEFILE:
  299. case ASYNC_OP_APPENDFILE:
  300. {
  301. CAsyncFileRequest* pOuter = ( CAsyncFileRequest* ) m_pOuter;
  302. return pOuter->ValidateSubmittedRequest( bPerformSync );
  303. }
  304. case ASYNC_OP_SCANDIR:
  305. {
  306. CAsyncSearchRequest* pOuter = ( CAsyncSearchRequest* ) m_pOuter;
  307. return pOuter->ValidateSubmittedRequest( bPerformSync );
  308. }
  309. default:
  310. {
  311. Error( "Bad Outer in CAsyncRequestBase::ValidateSubmittedRequest" );
  312. break;
  313. }
  314. }
  315. }
  316. return ASYNC_REQUEST_OK;
  317. }
  318. //-----------------------------------------------------------------------------
  319. // CAsyncRequestBase::ValidateRequestModification
  320. // Makes sure it's ok to modify this request
  321. //-----------------------------------------------------------------------------
  322. bool CAsyncRequestBase::ValidateRequestModification()
  323. {
  324. if ( m_RequestState == ASYNC_REQUEST_STATE_COMPOSING )
  325. {
  326. return true;
  327. }
  328. Error( "Modifying Async Filesystem Request after it has been submitted" );
  329. return false;
  330. }
  331. //-----------------------------------------------------------------------------
  332. // CAsyncGroupRequest::Default Constructor
  333. // -- inits all members
  334. //-----------------------------------------------------------------------------
  335. CAsyncGroupRequest::CAsyncGroupRequest()
  336. {
  337. m_Base.SetOuter( this );
  338. m_nNumRequestsOutstanding = 0;
  339. }
  340. //-----------------------------------------------------------------------------
  341. // CAsyncGroupRequest::Destructor
  342. // -- cleans up a group request.. we should assume that
  343. //-----------------------------------------------------------------------------
  344. CAsyncGroupRequest::~CAsyncGroupRequest()
  345. {
  346. // We shouldn't be destroying ourself unless the entire group has released
  347. Assert ( m_RequestList.Count() == 0 );
  348. Assert ( m_nNumRequestsOutstanding == 0 );
  349. }
  350. //-----------------------------------------------------------------------------
  351. // CAsyncGroupRequest::AddAsyncRequest Adds a request to a group.
  352. //
  353. //-----------------------------------------------------------------------------
  354. void CAsyncGroupRequest::AddAsyncRequest( IAsyncRequestBase* pRequest )
  355. {
  356. // A bunch of assertions. we're moving away from error checking in release builds
  357. Assert( pRequest != NULL );
  358. Assert( g_FileSystem_Async.ValidateRequestPtr( pRequest->GetBase() ) );
  359. Assert( m_RequestList.Find( pRequest ) == -1 );
  360. Assert( pRequest->GetRequestStatus() == ASYNC_REQUEST_STATE_COMPOSING );
  361. Assert( pRequest->GetBase()->m_pGroup == NULL );
  362. // Add a valid request to the end of the list
  363. m_RequestList.AddToTail( pRequest );
  364. m_ValidList.AddToTail( true );
  365. }
  366. //-----------------------------------------------------------------------------
  367. // CAsyncGroupRequest::GetAsyncRequest -
  368. //
  369. //-----------------------------------------------------------------------------
  370. IAsyncRequestBase* CAsyncGroupRequest::GetAsyncRequest( int32 nRNum )
  371. {
  372. if ( nRNum < 0 || nRNum >= m_RequestList.Count() )
  373. {
  374. Assert( false );
  375. return NULL;
  376. }
  377. return m_RequestList[ nRNum ];
  378. }
  379. //-----------------------------------------------------------------------------
  380. // CAsyncGroupRequest::GetAsyncFileRequest
  381. //
  382. //-----------------------------------------------------------------------------
  383. IAsyncFileRequest* CAsyncGroupRequest::GetAsyncFileRequest( int32 nRNum )
  384. {
  385. if ( nRNum < 0 || nRNum >= m_RequestList.Count() )
  386. {
  387. Assert( false );
  388. return NULL;
  389. }
  390. IAsyncRequestBase* pRequest = m_RequestList[ nRNum ];
  391. AsyncFileOperation_t opType = pRequest->GetAsyncOperationType();
  392. if ( opType == ASYNC_OP_READFILE || opType == ASYNC_OP_WRITEFILE || opType == ASYNC_OP_APPENDFILE )
  393. {
  394. return ( IAsyncFileRequest* ) pRequest;
  395. }
  396. else
  397. {
  398. return NULL;
  399. }
  400. }
  401. //-----------------------------------------------------------------------------
  402. // CAsyncGroupRequest::GetAsyncSearchRequest
  403. //
  404. //-----------------------------------------------------------------------------
  405. IAsyncSearchRequest* CAsyncGroupRequest::GetAsyncSearchRequest( int32 nRNum )
  406. {
  407. if ( nRNum < 0 || nRNum >= m_RequestList.Count() )
  408. {
  409. Assert( false );
  410. return NULL;
  411. }
  412. IAsyncRequestBase* pRequest = m_RequestList[ nRNum ];
  413. AsyncFileOperation_t opType = pRequest->GetAsyncOperationType();
  414. if ( opType == ASYNC_OP_SCANDIR )
  415. {
  416. return ( IAsyncSearchRequest* ) pRequest;
  417. }
  418. else
  419. {
  420. return NULL;
  421. }
  422. }
  423. //-----------------------------------------------------------------------------
  424. // CAsyncGroupRequest::
  425. //
  426. //-----------------------------------------------------------------------------
  427. void CAsyncGroupRequest::ReleaseAsyncRequest( int32 nRNum )
  428. {
  429. }
  430. //-----------------------------------------------------------------------------
  431. // CAsyncGroupRequest::
  432. //
  433. //-----------------------------------------------------------------------------
  434. void CAsyncGroupRequest::NotifyOfCompletion( IAsyncRequestBase* pRequest )
  435. {
  436. }
  437. //-----------------------------------------------------------------------------
  438. // CAsyncFileRequest::Default Constructor
  439. // -- inits all members
  440. //-----------------------------------------------------------------------------
  441. CAsyncFileRequest::CAsyncFileRequest()
  442. {
  443. m_Base.SetOuter( this );
  444. m_pFileName = NULL;
  445. m_pUserProvidedDataBuffer = NULL;
  446. m_nUserProvidedBufferSize = 0;
  447. m_nFileSeekOffset = 0;
  448. m_nMaxIOSizeInBytes = 0;
  449. m_pResultsBuffer = NULL;
  450. m_nResultsBufferSize = 0;
  451. m_nIOActualSize = 0;
  452. m_bDeleteBufferMemory = false;
  453. }
  454. //-----------------------------------------------------------------------------
  455. // CAsyncFileRequest::Destructor
  456. //
  457. //-----------------------------------------------------------------------------
  458. CAsyncFileRequest::~CAsyncFileRequest()
  459. {
  460. // Release memory we own...
  461. RefreshFileName( NULL ); // Release our copy of filename
  462. // and the data buffer?
  463. if ( m_bDeleteBufferMemory )
  464. {
  465. if ( m_pResultsBuffer != NULL )
  466. {
  467. g_FileSystem_Async.ReleaseBuffer( m_pResultsBuffer );
  468. }
  469. }
  470. // The CAsyncRequestBase Release/DeleteOuter will take care of the rest and the release
  471. }
  472. //-----------------------------------------------------------------------------
  473. // methods from the IAsyncFileRequest Interface
  474. //-----------------------------------------------------------------------------
  475. //-----------------------------------------------------------------------------
  476. // CAsyncFileRequest::LoadFile
  477. //
  478. //-----------------------------------------------------------------------------
  479. void CAsyncFileRequest::LoadFile( const char* pFileName )
  480. {
  481. VALIDATE_REQUEST_MODIFICATION;
  482. RefreshFileName( pFileName );
  483. m_Base.m_Operation = ASYNC_OP_READFILE;
  484. }
  485. //-----------------------------------------------------------------------------
  486. // CAsyncFileRequest::SaveFile
  487. //
  488. //-----------------------------------------------------------------------------
  489. void CAsyncFileRequest::SaveFile( const char* pFileName )
  490. {
  491. VALIDATE_REQUEST_MODIFICATION;
  492. RefreshFileName( pFileName );
  493. m_Base.m_Operation = ASYNC_OP_WRITEFILE;
  494. }
  495. //-----------------------------------------------------------------------------
  496. // CAsyncFileRequest::AppendFile
  497. //
  498. //-----------------------------------------------------------------------------
  499. void CAsyncFileRequest::AppendFile( const char* pFileName )
  500. {
  501. VALIDATE_REQUEST_MODIFICATION;
  502. RefreshFileName( pFileName );
  503. m_Base.m_Operation = ASYNC_OP_APPENDFILE;
  504. }
  505. //-----------------------------------------------------------------------------
  506. // CAsyncFileRequest::AppendFile
  507. //
  508. //-----------------------------------------------------------------------------
  509. void CAsyncFileRequest::SetFileName( const char* pFileName )
  510. {
  511. VALIDATE_REQUEST_MODIFICATION;
  512. RefreshFileName( pFileName );
  513. }
  514. //-----------------------------------------------------------------------------
  515. // CAsyncFileRequest::SetUserBuffer
  516. // - user supplies buffer to use
  517. //-----------------------------------------------------------------------------
  518. void CAsyncFileRequest::SetUserBuffer( void* pDataBuffer, size_t nBufferSize )
  519. {
  520. VALIDATE_REQUEST_MODIFICATION;
  521. m_pUserProvidedDataBuffer = pDataBuffer;
  522. m_nUserProvidedBufferSize = nBufferSize;
  523. m_bDeleteBufferMemory = false;
  524. }
  525. //-----------------------------------------------------------------------------
  526. // CAsyncFileRequest::ProvideDataBuffer
  527. // file system provide a buffer with the results
  528. //-----------------------------------------------------------------------------
  529. void CAsyncFileRequest::ProvideDataBuffer()
  530. {
  531. VALIDATE_REQUEST_MODIFICATION;
  532. m_pUserProvidedDataBuffer = NULL;
  533. m_nUserProvidedBufferSize = 0;
  534. m_bDeleteBufferMemory = true;
  535. }
  536. //-----------------------------------------------------------------------------
  537. // CAsyncFileRequest::ReadFileDataAt
  538. // Read file data starting at supplied offset, optional max size to read
  539. //-----------------------------------------------------------------------------
  540. void CAsyncFileRequest::ReadFileDataAt( int64 nOffset, size_t nReadSize )
  541. {
  542. VALIDATE_REQUEST_MODIFICATION;
  543. m_nFileSeekOffset = nOffset;
  544. m_nMaxIOSizeInBytes = nReadSize;
  545. }
  546. //-----------------------------------------------------------------------------
  547. // CAsyncFileRequest::WriteFileDataAt
  548. // Write data to file at supplied offset, optional size to write (max size of buffer)
  549. //-----------------------------------------------------------------------------
  550. void CAsyncFileRequest::WriteFileDataAt( int64 nOffset, size_t nWriteSize )
  551. {
  552. VALIDATE_REQUEST_MODIFICATION;
  553. m_nFileSeekOffset = nOffset;
  554. m_nMaxIOSizeInBytes = nWriteSize;
  555. m_bDeleteBufferMemory = false;
  556. }
  557. //-----------------------------------------------------------------------------
  558. // CAsyncFileRequest::AbortAfterServicing
  559. // Handle a request that got aborted while being serviced
  560. //-----------------------------------------------------------------------------
  561. void CAsyncFileRequest::AbortAfterServicing( CAsyncResultInfo_t& results )
  562. {
  563. // was it a read and did the request allocate a buffer?
  564. if ( GetAsyncOperationType()== ASYNC_OP_READFILE && m_pUserProvidedDataBuffer == NULL )
  565. {
  566. // the old async code allocated a buffer that we aren't going to use/return
  567. if ( results.m_pAllocatedBuffer != NULL )
  568. {
  569. // this should call our allocation function
  570. delete[] results.m_pAllocatedBuffer;
  571. }
  572. }
  573. }
  574. //-----------------------------------------------------------------------------
  575. // CAsyncFileRequest::UpdateAfterServicing
  576. // Handle a request that was successfully serviced
  577. //-----------------------------------------------------------------------------
  578. void CAsyncFileRequest::UpdateAfterServicing( CAsyncResultInfo_t& results )
  579. {
  580. // copy our return info from the old results struct
  581. m_pResultsBuffer = results.m_pAllocatedBuffer;
  582. m_nResultsBufferSize = ( m_pUserProvidedDataBuffer == NULL ) ? results.m_nBytesTransferred : m_nUserProvidedBufferSize;
  583. m_nIOActualSize = results.m_nBytesTransferred;
  584. }
  585. //-----------------------------------------------------------------------------
  586. // CAsyncFileRequest::ValidateSubmittedRequest
  587. // Validate that this request can be submitted successfully
  588. //-----------------------------------------------------------------------------
  589. AsyncRequestStatus_t CAsyncFileRequest::ValidateSubmittedRequest( bool bPerformSync )
  590. {
  591. // filename must be supplied
  592. if ( GetFileName() == NULL )
  593. {
  594. return ASYNC_REQUEST_ERROR_BADOPER;
  595. }
  596. #ifdef _DEBUG
  597. // In debug mode, Check the filename for length, usage issues
  598. AsyncRequestStatus_t err = ValidateFileName( GetFileName() );
  599. if ( err != ASYNC_REQUEST_OK ) return err;
  600. #endif
  601. // if the user supplies a buffer, it must have a size
  602. if ( GetUserBuffer() != NULL && GetUserBufferSize() == 0 )
  603. {
  604. return ASYNC_REQUEST_ERROR_BADUSERBUFFER; // cant supply a zero sized buffer
  605. }
  606. // if we are writing, then a buffer must be specified
  607. if ( ( CAsyncFileRequest::GetAsyncOperationType() == ASYNC_OP_WRITEFILE || CAsyncFileRequest::GetAsyncOperationType() == ASYNC_OP_APPENDFILE ) && GetUserBuffer() == NULL )
  608. {
  609. return ASYNC_REQUEST_ERROR_NOBUFFER;
  610. }
  611. return ASYNC_REQUEST_OK;
  612. }
  613. //-----------------------------------------------------------------------------
  614. // CAsyncFileRequest::RefreshFileName
  615. // Change the filename, release memory held by previous
  616. //-----------------------------------------------------------------------------
  617. void CAsyncFileRequest::RefreshFileName( const char* pNewFileName )
  618. {
  619. // release existing filename
  620. if ( m_pFileName != NULL )
  621. {
  622. delete[] m_pFileName;
  623. }
  624. // we duplicate the file name, and own its memory
  625. if ( pNewFileName != NULL )
  626. {
  627. m_pFileName = strdup( pNewFileName );
  628. }
  629. else
  630. {
  631. m_pFileName = NULL;
  632. }
  633. }
  634. //-----------------------------------------------------------------------------
  635. // CAsyncFileRequest::ValidateRequestModification
  636. // Makes sure it's ok to modify this request
  637. //-----------------------------------------------------------------------------
  638. bool CAsyncFileRequest::ValidateRequestModification()
  639. {
  640. return m_Base.ValidateRequestModification();
  641. }
  642. //-----------------------------------------------------------------------------
  643. // CAsyncSearchRequest::Default Constructor
  644. // -- inits all members
  645. //-----------------------------------------------------------------------------
  646. CAsyncSearchRequest::CAsyncSearchRequest()
  647. {
  648. m_Base.SetOuter( this );
  649. V_memset( m_FileSpec, 0, sizeof( m_FileSpec ) );
  650. V_memset( m_PathID, 0, sizeof( m_PathID ) );
  651. V_memset( m_SearchPath, 0, sizeof( m_SearchPath ) );
  652. V_memset( m_SearchSpec, 0, sizeof( m_SearchSpec ) );
  653. m_nNumResults = 0;
  654. m_bRecurseSubdirs = false;
  655. }
  656. //-----------------------------------------------------------------------------
  657. // CAsyncSearchRequest::Destructor
  658. //
  659. //-----------------------------------------------------------------------------
  660. CAsyncSearchRequest::~CAsyncSearchRequest()
  661. {
  662. // Release any memory we own...
  663. // The base object destructor will take care of the rest and the release
  664. }
  665. //-----------------------------------------------------------------------------
  666. // Methods from the IAsyncSearchRequest Interface
  667. //-----------------------------------------------------------------------------
  668. //-----------------------------------------------------------------------------
  669. // CAsyncSearchRequest::SetSearchFilespec
  670. // - assign the path and filename to search for
  671. //-----------------------------------------------------------------------------
  672. void CAsyncSearchRequest::SetSearchFilespec( const char* pFullSearchSpec )
  673. {
  674. VALIDATE_REQUEST_MODIFICATION;
  675. Assert( pFullSearchSpec != NULL && strlen( pFullSearchSpec ) < sizeof( m_SearchSpec ) );
  676. V_strcpy( m_SearchSpec, pFullSearchSpec );
  677. m_Base.m_Operation = ASYNC_OP_SCANDIR;
  678. }
  679. //-----------------------------------------------------------------------------
  680. // CAsyncSearchRequest::SetSearchFilespec
  681. // - assign the path and filename to search for
  682. //-----------------------------------------------------------------------------
  683. void CAsyncSearchRequest::SetSearchPathAndFileSpec( const char* pPathId, const char* pRelativeSearchSpec )
  684. {
  685. VALIDATE_REQUEST_MODIFICATION;
  686. Assert( pPathId != NULL && strlen( pPathId ) < sizeof( m_PathID ) );
  687. Assert( pRelativeSearchSpec != NULL && strlen( pRelativeSearchSpec ) < sizeof( m_FileSpec ) );
  688. Q_strcpy( m_FileSpec, V_UnqualifiedFileName( pRelativeSearchSpec) );
  689. V_ExtractFilePath (pRelativeSearchSpec, m_SearchPath, sizeof(m_SearchPath) );
  690. V_StripTrailingSlash( m_SearchPath );
  691. char pTempPath[MAX_PATH];
  692. g_pFullFileSystem->RelativePathToFullPath( m_SearchPath, pPathId, pTempPath, sizeof(pTempPath) );
  693. char pFixedupPath[MAX_PATH];
  694. Q_FixupPathName( pFixedupPath, sizeof(pFixedupPath), pTempPath );
  695. V_ComposeFileName( pFixedupPath, m_FileSpec, m_SearchSpec, sizeof(m_SearchSpec) );
  696. m_Base.m_Operation = ASYNC_OP_SCANDIR;
  697. }
  698. //-----------------------------------------------------------------------------
  699. // CAsyncSearchRequest::SetSearchFilespec
  700. // - assign the path and filename to search for
  701. //-----------------------------------------------------------------------------
  702. void CAsyncSearchRequest::SetSearchPathAndFileSpec( const char* pPathId, const char* pRelativeSearchPath, const char* pSearchSpec )
  703. {
  704. VALIDATE_REQUEST_MODIFICATION;
  705. Assert( pPathId != NULL && strlen( pPathId ) < sizeof( m_PathID ) );
  706. Assert( pRelativeSearchPath != NULL && strlen( pRelativeSearchPath ) < sizeof( m_SearchPath ) );
  707. Assert( pSearchSpec != NULL && strlen( pSearchSpec ) < sizeof( m_FileSpec ) );
  708. Q_strcpy( m_FileSpec, pSearchSpec );
  709. Q_strcpy( m_SearchPath, pRelativeSearchPath );
  710. V_StripTrailingSlash( m_SearchPath );
  711. char pTempPath[MAX_PATH];
  712. g_pFullFileSystem->RelativePathToFullPath( m_SearchPath, pPathId, pTempPath, sizeof(pTempPath) );
  713. char pFixedupPath[MAX_PATH];
  714. Q_FixupPathName( pFixedupPath, sizeof(pFixedupPath), pTempPath );
  715. V_ComposeFileName( pFixedupPath, m_FileSpec, m_SearchSpec, sizeof(m_SearchSpec) );
  716. m_Base.m_Operation = ASYNC_OP_SCANDIR;
  717. }
  718. //-----------------------------------------------------------------------------
  719. // CAsyncSearchRequest::SetSubdirectoryScan
  720. //
  721. //-----------------------------------------------------------------------------
  722. void CAsyncSearchRequest::SetSubdirectoryScan( const bool bInclude )
  723. {
  724. VALIDATE_REQUEST_MODIFICATION;
  725. m_bRecurseSubdirs = bInclude;
  726. }
  727. //-----------------------------------------------------------------------------
  728. // CAsyncSearchRequest::GetResult
  729. // returns a search result
  730. //-----------------------------------------------------------------------------
  731. CDirectoryEntryInfo_t* CAsyncSearchRequest::GetResult( int rNum )
  732. {
  733. if ( m_Base.GetRequestState() < ASYNC_REQUEST_STATE_AWATING_FINISH || m_Base.GetRequestState() > ASYNC_REQUEST_STATE_COMPLETED )
  734. {
  735. Assert( false );
  736. return NULL;
  737. }
  738. if ( rNum < 0 || rNum >= m_nNumResults )
  739. {
  740. Assert( false );
  741. return NULL;
  742. }
  743. return &( m_Results[ rNum ] );
  744. }
  745. //-----------------------------------------------------------------------------
  746. // CAsyncSearchRequest::GetMatchedFile
  747. // returns a search result
  748. //-----------------------------------------------------------------------------
  749. const char* CAsyncSearchRequest::GetMatchedFile( int rNum )
  750. {
  751. if ( m_Base.GetRequestState() < ASYNC_REQUEST_STATE_AWATING_FINISH || m_Base.GetRequestState() > ASYNC_REQUEST_STATE_COMPLETED )
  752. {
  753. Assert( false );
  754. return NULL;
  755. }
  756. if ( rNum < 0 || rNum >= m_nNumResults )
  757. {
  758. Assert( false );
  759. return NULL;
  760. }
  761. return m_Results[ rNum ].m_FullFileName ;
  762. }
  763. //-----------------------------------------------------------------------------
  764. // CAsyncSearchRequest::AbortAfterServicing
  765. // Handle a request that got aborted while being serviced
  766. //-----------------------------------------------------------------------------
  767. void CAsyncSearchRequest::AbortAfterServicing( CAsyncResultInfo_t& results )
  768. {
  769. // nothing dynamic to release
  770. }
  771. //-----------------------------------------------------------------------------
  772. // CAsyncSearchRequest::UpdateAfterServicing
  773. // Handle a request that was successfully serviced
  774. //-----------------------------------------------------------------------------
  775. void CAsyncSearchRequest::UpdateAfterServicing( CAsyncResultInfo_t& results )
  776. {
  777. // determine request specific values
  778. m_nNumResults = m_Results.Count();
  779. }
  780. //-----------------------------------------------------------------------------
  781. // CAsyncSearchRequest::ValidateSubmittedRequest
  782. // Validate that this request can be submitted successfully
  783. //-----------------------------------------------------------------------------
  784. AsyncRequestStatus_t CAsyncSearchRequest::ValidateSubmittedRequest( bool bPerformSync )
  785. {
  786. // filespec missing?
  787. if ( V_strlen( m_FileSpec ) < 1 )
  788. {
  789. return ASYNC_REQUEST_ERROR_INVALIDFILENAME;
  790. }
  791. return ASYNC_REQUEST_OK;
  792. }
  793. //-----------------------------------------------------------------------------
  794. // CAsyncSearchRequest::ValidateRequestModification
  795. // Makes sure it's ok to modify this request
  796. //-----------------------------------------------------------------------------
  797. bool CAsyncSearchRequest::ValidateRequestModification()
  798. {
  799. return m_Base.ValidateRequestModification();
  800. }
  801. //-----------------------------------------------------------------------------
  802. // CAsyncRequestQueue::constructor
  803. //
  804. //-----------------------------------------------------------------------------
  805. CAsyncRequestQueue::CAsyncRequestQueue()
  806. {
  807. m_nQueueSize = 0;
  808. m_pHead = NULL;
  809. m_pTail = NULL;
  810. }
  811. //-----------------------------------------------------------------------------
  812. // CAsyncRequestQueue::destructor
  813. //
  814. //-----------------------------------------------------------------------------
  815. CAsyncRequestQueue::~CAsyncRequestQueue()
  816. {
  817. AUTO_LOCK_FM( m_Mutex ); // wait for any other operations to finish
  818. // Delete any requests remaining in the queue
  819. if ( m_pHead != NULL )
  820. {
  821. Warning( " CAsyncRequestQueue destructor called while queue was not empty" );
  822. while ( m_pHead != NULL )
  823. {
  824. CAsyncRequestBase* pNext = m_pHead->m_pNext;
  825. delete m_pHead;
  826. m_pHead = pNext;
  827. }
  828. }
  829. }
  830. //-----------------------------------------------------------------------------
  831. // CAsyncRequestQueue::IsInQueue
  832. // - asks if a request is in this queue
  833. //-----------------------------------------------------------------------------
  834. bool CAsyncRequestQueue::IsInQueue( CAsyncRequestBase* pItem )
  835. {
  836. AUTO_LOCK_FM( m_Mutex ); // synchronize since we are scanning the queue?
  837. if ( pItem == NULL || m_pHead == NULL ) return false;
  838. CAsyncRequestBase* pCur = m_pHead;
  839. while ( pCur != NULL )
  840. {
  841. if ( pCur == pItem ) return true;
  842. pCur = pCur->m_pNext;
  843. }
  844. return false;
  845. }
  846. //-----------------------------------------------------------------------------
  847. // CAsyncRequestQueue::IsInQueueIp - Interface pointer version of IsInQueue
  848. // - asks if a request is in this queue
  849. //-----------------------------------------------------------------------------
  850. bool CAsyncRequestQueue::IsInQueueIp( const IAsyncRequestBase* pInterfaceBase )
  851. {
  852. AUTO_LOCK_FM( m_Mutex ); // synchronize since we are scanning the queue?
  853. if ( pInterfaceBase == NULL || m_pHead == NULL ) return false;
  854. CAsyncRequestBase* pCur = m_pHead;
  855. while ( pCur != NULL )
  856. {
  857. if ( ( const IAsyncRequestBase* ) ( pCur->GetOuter() ) == pInterfaceBase ) return true;
  858. pCur = pCur->m_pNext;
  859. }
  860. return false;
  861. }
  862. //-----------------------------------------------------------------------------
  863. // CAsyncRequestQueue::AddToHead
  864. //
  865. //-----------------------------------------------------------------------------
  866. void CAsyncRequestQueue::AddToHead( CAsyncRequestBase* pItem )
  867. {
  868. AUTO_LOCK_FM( m_Mutex );
  869. // Empty queue?
  870. if ( m_pHead == NULL )
  871. {
  872. Assert( pItem != NULL );
  873. Assert( m_pHead == m_pTail && m_nQueueSize == 0 );
  874. m_pHead = m_pTail = pItem;
  875. pItem->m_pPrev = NULL;
  876. pItem->m_pNext = NULL;
  877. m_nQueueSize = 1;
  878. }
  879. else
  880. {
  881. pItem->m_pPrev = NULL;
  882. pItem->m_pNext = m_pHead;
  883. m_pHead = pItem;
  884. pItem->m_pNext->m_pPrev = pItem; // Fixup previous head item
  885. m_nQueueSize++;
  886. }
  887. }
  888. //-----------------------------------------------------------------------------
  889. // CAsyncRequestQueue::AddToTail
  890. //
  891. //-----------------------------------------------------------------------------
  892. void CAsyncRequestQueue::AddToTail( CAsyncRequestBase* pItem )
  893. {
  894. AUTO_LOCK_FM( m_Mutex );
  895. // Empty queue?
  896. if ( m_pTail == NULL )
  897. {
  898. Assert( pItem != NULL );
  899. Assert( m_pHead == m_pTail && m_nQueueSize == 0 );
  900. m_pHead = m_pTail = pItem;
  901. pItem->m_pPrev = NULL;
  902. pItem->m_pNext = NULL;
  903. m_nQueueSize = 1;
  904. }
  905. else
  906. {
  907. pItem->m_pPrev = m_pTail;
  908. pItem->m_pNext = NULL;
  909. m_pTail = pItem;
  910. pItem->m_pPrev->m_pNext = pItem; // Fixup previous tail item
  911. m_nQueueSize++;
  912. }
  913. }
  914. //-----------------------------------------------------------------------------
  915. // CAsyncRequestQueue::InsertBefore
  916. //
  917. //-----------------------------------------------------------------------------
  918. void CAsyncRequestQueue::InsertBefore( CAsyncRequestBase* pItem, CAsyncRequestBase* pInsertAt )
  919. {
  920. AUTO_LOCK_FM( m_Mutex );
  921. if ( pInsertAt == NULL || m_nQueueSize == 0 || pItem == NULL || !IsInQueue( pInsertAt ) )
  922. {
  923. return;
  924. }
  925. // Inserting at the head of the queue?
  926. if ( pInsertAt == m_pHead )
  927. {
  928. AddToHead( pItem );
  929. }
  930. else // is somewhere in the middle of the list
  931. {
  932. CAsyncRequestBase* pPrev = pInsertAt->m_pPrev;
  933. pPrev->m_pNext = pItem;
  934. pInsertAt->m_pPrev = pItem;
  935. pItem->m_pPrev = pPrev;
  936. pItem->m_pNext = pInsertAt;
  937. m_nQueueSize++;
  938. }
  939. };
  940. //-----------------------------------------------------------------------------
  941. // CAsyncRequestQueue::InsertAfter
  942. //
  943. //-----------------------------------------------------------------------------
  944. void CAsyncRequestQueue::InsertAfter( CAsyncRequestBase* pItem, CAsyncRequestBase* pInsertAt )
  945. {
  946. AUTO_LOCK_FM( m_Mutex );
  947. if ( pInsertAt == NULL || m_nQueueSize == 0 || pItem == NULL || !IsInQueue( pInsertAt ) )
  948. {
  949. return;
  950. }
  951. // Inserting at the end of the queue?
  952. if ( pInsertAt == m_pTail )
  953. {
  954. AddToTail( pItem );
  955. }
  956. else // is somewhere in the middle of the list
  957. {
  958. CAsyncRequestBase* pNext = pInsertAt->m_pNext;
  959. pNext->m_pPrev = pItem;
  960. pInsertAt->m_pNext = pItem;
  961. pItem->m_pPrev = pInsertAt;
  962. pItem->m_pNext = pNext;
  963. m_nQueueSize++;
  964. }
  965. }
  966. //-----------------------------------------------------------------------------
  967. // CAsyncRequestQueue::PriorityInsert
  968. // - inserts an async request in the list (assumed sorted) by priority
  969. //-----------------------------------------------------------------------------
  970. void CAsyncRequestQueue::PriorityInsert( CAsyncRequestBase* pItem )
  971. {
  972. AUTO_LOCK_FM( m_Mutex );
  973. if ( pItem == NULL )
  974. {
  975. return;
  976. }
  977. CAsyncRequestBase* pCur = m_pHead;
  978. bool bInserted = false;
  979. while ( pCur != NULL )
  980. {
  981. if ( pCur->GetPriority() < pItem->GetPriority() )
  982. {
  983. InsertBefore( pItem, pCur );
  984. bInserted = true;
  985. break;
  986. }
  987. pCur = pCur->m_pNext;
  988. }
  989. // Did not find a lower priority item to insert before?
  990. if ( !bInserted )
  991. {
  992. AddToTail( pItem );
  993. }
  994. }
  995. //-----------------------------------------------------------------------------
  996. // CAsyncRequestQueue::Remove
  997. //
  998. //-----------------------------------------------------------------------------
  999. void CAsyncRequestQueue::Remove( CAsyncRequestBase* pItem )
  1000. {
  1001. AUTO_LOCK_FM( m_Mutex );
  1002. if ( pItem == NULL || m_nQueueSize == 0 || !IsInQueue( pItem ) )
  1003. {
  1004. return;
  1005. }
  1006. if ( m_nQueueSize == 1 ) // emptying queue?
  1007. {
  1008. m_pHead = m_pTail = NULL;
  1009. }
  1010. else
  1011. {
  1012. // removing head?
  1013. if ( pItem->m_pPrev == NULL )
  1014. {
  1015. Assert( pItem == m_pHead );
  1016. m_pHead = pItem->m_pNext;
  1017. }
  1018. else
  1019. {
  1020. pItem->m_pPrev->m_pNext = pItem->m_pNext;
  1021. }
  1022. // removing tail?
  1023. if ( pItem->m_pNext == NULL )
  1024. {
  1025. Assert( pItem == m_pTail );
  1026. m_pTail = pItem->m_pPrev;
  1027. }
  1028. else
  1029. {
  1030. pItem->m_pNext->m_pPrev = pItem->m_pPrev;
  1031. }
  1032. }
  1033. m_nQueueSize--;
  1034. pItem->m_pNext = NULL; // clear links inside removed request
  1035. pItem->m_pPrev = NULL;
  1036. }
  1037. //-----------------------------------------------------------------------------
  1038. // CAsyncRequestQueue::RemoveHead
  1039. // Pops the first item off the queue and returns it
  1040. //-----------------------------------------------------------------------------
  1041. CAsyncRequestBase* CAsyncRequestQueue::RemoveHead()
  1042. {
  1043. AUTO_LOCK_FM( m_Mutex );
  1044. if ( m_nQueueSize == 0 || m_pHead == NULL )
  1045. {
  1046. return NULL;
  1047. }
  1048. CAsyncRequestBase* pItem = m_pHead;
  1049. Remove( pItem );
  1050. return pItem;
  1051. }
  1052. //-----------------------------------------------------------------------------
  1053. // CAsyncFileSystem::constructor
  1054. //
  1055. //-----------------------------------------------------------------------------
  1056. CAsyncFileSystem::CAsyncFileSystem()
  1057. {
  1058. m_nJobsInflight = 0;
  1059. m_nSuspendCount = 0;
  1060. m_bIOSuspended = false;
  1061. }
  1062. //-----------------------------------------------------------------------------
  1063. // CAsyncFileSystem::destructor
  1064. //
  1065. //-----------------------------------------------------------------------------
  1066. CAsyncFileSystem::~CAsyncFileSystem()
  1067. {
  1068. m_nSuspendCount = 1; // don't let any jobs slip status on us
  1069. AbortAllAsyncIO( true ); // finish any work in flight
  1070. // Queue destructors will release the requests
  1071. }
  1072. //-----------------------------------------------------------------------------
  1073. // CAsyncFileSystem::QueryInterface
  1074. //
  1075. //-----------------------------------------------------------------------------
  1076. void *CAsyncFileSystem::QueryInterface( const char *pInterfaceName )
  1077. {
  1078. // Make sure we are asking for the right version
  1079. if ( !Q_strncmp( pInterfaceName, ASYNCFILESYSTEM_INTERFACE_VERSION, Q_strlen( ASYNCFILESYSTEM_INTERFACE_VERSION ) + 1) )
  1080. {
  1081. return ( IAsyncFileSystem* ) this;
  1082. }
  1083. return NULL;
  1084. }
  1085. //-----------------------------------------------------------------------------
  1086. // CAsyncFileSystem::CreateNewFileRequest
  1087. // Gets a new async read/write request object
  1088. //-----------------------------------------------------------------------------
  1089. IAsyncFileRequest* CAsyncFileSystem::CreateNewFileRequest()
  1090. {
  1091. // Allocate a new request object, it's constructor will set everything up
  1092. CAsyncFileRequest* pNewRequest = new CAsyncFileRequest;
  1093. // add it to our list of requests being composed
  1094. m_Composing.AddToTail( &pNewRequest->m_Base );
  1095. // pass back the public interface pointer
  1096. return pNewRequest;
  1097. }
  1098. //-----------------------------------------------------------------------------
  1099. // CAsyncFileSystem::CreateNewSearchRequest
  1100. // Gets a new async directory search request object
  1101. //-----------------------------------------------------------------------------
  1102. IAsyncSearchRequest* CAsyncFileSystem::CreateNewSearchRequest()
  1103. {
  1104. // Allocate a new request object, it's constructor will set everything up
  1105. CAsyncSearchRequest* pNewRequest = new CAsyncSearchRequest;
  1106. // add it to our list of requests being composed
  1107. m_Composing.AddToTail( &pNewRequest->m_Base );
  1108. // pass back the public interface pointer
  1109. return pNewRequest;
  1110. }
  1111. //-----------------------------------------------------------------------------
  1112. // CAsyncFileSystem::CreateNewAsyncRequestGroup
  1113. // Gets a new async request group object
  1114. //-----------------------------------------------------------------------------
  1115. IAsyncGroupRequest* CAsyncFileSystem::CreateNewAsyncRequestGroup()
  1116. {
  1117. // Allocate a new request object, it's constructor will set everything up
  1118. CAsyncGroupRequest* pNewRequest = new CAsyncGroupRequest;
  1119. // add it to our list of requests being composed
  1120. m_Composing.AddToTail( &pNewRequest->m_Base );
  1121. // pass back the public interface pointer
  1122. return pNewRequest;
  1123. }
  1124. //-----------------------------------------------------------------------------
  1125. // CAsyncFileSystem::ReleaseAsyncRequest
  1126. // Disposes of a File Request Object
  1127. // Public interface
  1128. //-----------------------------------------------------------------------------
  1129. void CAsyncFileSystem::ReleaseAsyncRequest( const IAsyncRequestBase* pRequest )
  1130. {
  1131. CAsyncRequestBase* pRequestBase = ( (IAsyncRequestBase* ) pRequest )->GetBase();
  1132. AUTO_LOCK_FM ( m_AsyncStateUpdateMutex );
  1133. if ( !ValidateRequestPtr( pRequestBase ) )
  1134. {
  1135. Error( "Bad Release Request" );
  1136. return;
  1137. }
  1138. // If we are servicing the request, just mark it to abort when done
  1139. if ( pRequestBase->m_RequestState == ASYNC_REQUEST_STATE_SERVICING )
  1140. {
  1141. pRequestBase->m_bAbortRequest = true; // have it delete itself when done
  1142. return;
  1143. }
  1144. // If we are processing a callback, wait until finished
  1145. if ( pRequestBase->m_bProcessingCallback )
  1146. {
  1147. pRequestBase->m_bDontAutoRelease = false;
  1148. return;
  1149. }
  1150. // Delete the request object
  1151. pRequestBase->DeleteOuter();
  1152. }
  1153. //-----------------------------------------------------------------------------
  1154. // CAsyncFileSystem::SubmitAsyncIORequest
  1155. //
  1156. //-----------------------------------------------------------------------------
  1157. AsyncRequestStatus_t CAsyncFileSystem::SubmitAsyncFileRequest( const IAsyncRequestBase* pRequest )
  1158. {
  1159. CAsyncRequestBase* pRequestBase = ( (IAsyncRequestBase* ) pRequest )->GetBase();
  1160. // Validate the request from the user....
  1161. AsyncRequestStatus_t RStatus = ValidateRequest( pRequestBase, false );
  1162. // An error is preventing this from being submitted
  1163. if ( RStatus != ASYNC_REQUEST_OK )
  1164. {
  1165. m_AsyncStateUpdateMutex.Lock();
  1166. {
  1167. // Move the job to the completed queue
  1168. m_Composing.Remove( pRequestBase );
  1169. m_Completed.AddToTail( pRequestBase );
  1170. // mark request as completed, with error
  1171. pRequestBase->m_RequestState = ASYNC_REQUEST_STATE_COMPLETED;
  1172. pRequestBase->m_RequestStatus = RStatus;
  1173. }
  1174. m_AsyncStateUpdateMutex.Unlock();
  1175. // notify any designed message queue and/or callback
  1176. NotifyMessageQueueOrCallback( pRequestBase );
  1177. // notify the submitter as well
  1178. return RStatus;
  1179. }
  1180. m_AsyncStateUpdateMutex.Lock();
  1181. {
  1182. // Move the job to the submitted queue and insert according to priority
  1183. m_Composing.Remove( pRequestBase );
  1184. pRequestBase->m_RequestState = ASYNC_REQUEST_STATE_SUBMITTED;
  1185. m_Submitted.PriorityInsert( pRequestBase );
  1186. }
  1187. m_AsyncStateUpdateMutex.Unlock();
  1188. // See if we can hand this request off to the old async system
  1189. KickOffFileJobs();
  1190. return RStatus;
  1191. }
  1192. //-----------------------------------------------------------------------------
  1193. // CAsyncFileSystem::SubmitSyncIORequest
  1194. //
  1195. //-----------------------------------------------------------------------------
  1196. AsyncRequestStatus_t CAsyncFileSystem::SubmitSyncFileRequest( const IAsyncRequestBase* pRequest )
  1197. {
  1198. CAsyncRequestBase* pRequestBase = ( (IAsyncRequestBase* ) pRequest)->GetBase();
  1199. // Validate the request from the user....
  1200. AsyncRequestStatus_t RStatus = ValidateRequest( pRequestBase, true );
  1201. if ( RStatus != ASYNC_REQUEST_OK )
  1202. {
  1203. m_AsyncStateUpdateMutex.Lock();
  1204. {
  1205. // Move the job to the completed queue
  1206. m_Composing.Remove( pRequestBase );
  1207. m_Completed.AddToTail( pRequestBase );
  1208. // mark request as completed, with error
  1209. pRequestBase->m_RequestState = ASYNC_REQUEST_STATE_COMPLETED;
  1210. pRequestBase->m_RequestStatus = RStatus;
  1211. }
  1212. m_AsyncStateUpdateMutex.Unlock();
  1213. return RStatus;
  1214. }
  1215. CThreadEvent syncEvent;
  1216. // Move the job to the submitted queue and insert according to priority
  1217. m_AsyncStateUpdateMutex.Lock();
  1218. {
  1219. m_Composing.Remove( pRequestBase );
  1220. pRequestBase->m_RequestState = ASYNC_REQUEST_STATE_SUBMITTED;
  1221. // We are making a local thread event, so this routine can be called simultaneously / overlapping
  1222. // by multiple threads. I know it is "expensive" to new up a CThreadEvent, but we want to discourage
  1223. // people from doing this anyway...
  1224. pRequestBase->m_pSyncThreadEvent = &syncEvent;
  1225. m_Submitted.PriorityInsert( pRequestBase );
  1226. }
  1227. m_AsyncStateUpdateMutex.Unlock();
  1228. // Submit to the async system
  1229. KickOffFileJobs();
  1230. // Wait for the job to finish, and for us to be signaled
  1231. pRequestBase->m_pSyncThreadEvent->Wait();
  1232. // Get the IO status to return.... (user has to delete the object anyway)
  1233. RStatus = pRequestBase->GetRequestStatus();
  1234. return RStatus;
  1235. }
  1236. //-----------------------------------------------------------------------------
  1237. // CAsyncFileSystem::KickOffFileJobs
  1238. // hand off async jobs to the old async file system
  1239. //-----------------------------------------------------------------------------
  1240. void CAsyncFileSystem::KickOffFileJobs()
  1241. {
  1242. // Are we suspended?
  1243. if ( m_nSuspendCount > 0 )
  1244. {
  1245. return;
  1246. }
  1247. #if 0
  1248. // Are the too many requests already being serviced?
  1249. // TODO - throttle at 2 jobs?
  1250. if ( m_nJobsInflight >= 1 )
  1251. {
  1252. return;
  1253. }
  1254. #endif
  1255. m_AsyncStateUpdateMutex.Lock();
  1256. // are there any requests waiting to be submitted?
  1257. if ( m_Submitted.GetSize() < 1 )
  1258. {
  1259. m_AsyncStateUpdateMutex.Unlock();
  1260. return;
  1261. }
  1262. // ok. translate our request to the current system
  1263. CAsyncRequestBase* pRequestBase = m_Submitted.RemoveHead();
  1264. FileAsyncRequest_t asJobReq;
  1265. CAsyncFileRequest* pFileRequest = NULL;
  1266. CAsyncSearchRequest* pSearchRequest = NULL;
  1267. char* pSearchSpec = NULL;
  1268. bool bRecurseFolders = false;
  1269. if ( pRequestBase->GetAsyncOperationType() == ASYNC_OP_READFILE ||
  1270. pRequestBase->GetAsyncOperationType() == ASYNC_OP_WRITEFILE ||
  1271. pRequestBase->GetAsyncOperationType() == ASYNC_OP_APPENDFILE )
  1272. {
  1273. // Get the FileRequest that contains the base
  1274. pFileRequest = reinterpret_cast< CAsyncFileRequest* >( pRequestBase->GetOuter() );
  1275. // IO operation size is smaller of optionally supplied buffer size and optionally supplied IO size
  1276. int nIOMax = 0;
  1277. if ( pFileRequest->GetUserBuffer() != NULL )
  1278. {
  1279. nIOMax = pFileRequest->GetUserBufferSize();
  1280. if ( pFileRequest->m_nMaxIOSizeInBytes > 0 && pFileRequest->m_nMaxIOSizeInBytes > nIOMax )
  1281. {
  1282. Error( "Buffer not big enough to hold requested File IO" );
  1283. }
  1284. }
  1285. if ( pFileRequest->m_nMaxIOSizeInBytes > 0 && pFileRequest->m_nMaxIOSizeInBytes < nIOMax )
  1286. {
  1287. nIOMax = pFileRequest->m_nMaxIOSizeInBytes;
  1288. }
  1289. // translate to old request format...
  1290. asJobReq.pszFilename = pFileRequest->GetFileName();
  1291. asJobReq.pData = pFileRequest->GetUserBuffer();
  1292. asJobReq.nOffset = pFileRequest->m_nFileSeekOffset;
  1293. asJobReq.nBytes = nIOMax;
  1294. asJobReq.pfnCallback = &CAsyncFileSystem::AsyncIOCallbackGateway;
  1295. asJobReq.pContext = (void*) pRequestBase;
  1296. asJobReq.priority = 0;
  1297. asJobReq.flags = ( pFileRequest->GetUserBuffer() == NULL ) ? FSASYNC_FLAGS_ALLOCNOFREE : 0 ;
  1298. asJobReq.pszPathID = NULL;
  1299. asJobReq.hSpecificAsyncFile = FS_INVALID_ASYNC_FILE;
  1300. asJobReq.pfnAlloc = &CAsyncFileSystem::OldAsyncAllocatorCallback;
  1301. }
  1302. if ( pRequestBase->GetAsyncOperationType() == ASYNC_OP_SCANDIR )
  1303. {
  1304. // Get the Search Request that contains the base
  1305. pSearchRequest = reinterpret_cast< CAsyncSearchRequest* >( pRequestBase->GetOuter() );
  1306. pSearchSpec = pSearchRequest->m_SearchSpec;
  1307. bRecurseFolders = pSearchRequest->m_bRecurseSubdirs;
  1308. }
  1309. m_InFlight.AddToTail( pRequestBase );
  1310. m_nJobsInflight++;
  1311. pRequestBase->m_RequestState = ASYNC_REQUEST_STATE_SERVICING;
  1312. // Make the call based on what sort of job is it...
  1313. FSAsyncStatus_t jStatus = FSASYNC_OK;
  1314. switch ( pRequestBase->GetAsyncOperationType() )
  1315. {
  1316. case ASYNC_OP_READFILE:
  1317. {
  1318. jStatus = g_pFullFileSystem->AsyncRead( asJobReq, &(pRequestBase->m_pOldAsyncControl) );
  1319. break;
  1320. }
  1321. case ASYNC_OP_WRITEFILE:
  1322. {
  1323. jStatus = g_pFullFileSystem->AsyncWrite( asJobReq.pszFilename, asJobReq.pData, pFileRequest->GetResultBufferSize(), false, false, &(pRequestBase->m_pOldAsyncControl) );
  1324. break;
  1325. }
  1326. case ASYNC_OP_SCANDIR:
  1327. {
  1328. jStatus = g_pFullFileSystem->AsyncDirectoryScan( pSearchSpec, bRecurseFolders, pRequestBase, &CAsyncFileSystem::AsyncSearchCallbackAddItem, &CAsyncFileSystem::AsyncSearchCallbackGateway, &(pRequestBase->m_pOldAsyncControl) );
  1329. break;
  1330. }
  1331. default:
  1332. {
  1333. Error( "Unable to determing async job type" );
  1334. break;
  1335. }
  1336. }
  1337. if ( jStatus != FSASYNC_OK )
  1338. {
  1339. // Error translating...
  1340. Error( "Basefilesystem Async Job submission failed" );
  1341. // TO-DO: go straight to notification/callback with failure info
  1342. }
  1343. m_AsyncStateUpdateMutex.Unlock();
  1344. }
  1345. //-----------------------------------------------------------------------------
  1346. // STATIC CAsyncFileSystem::OldAsyncAllocatorCallback
  1347. // - receives callbacks from the old Async file system
  1348. // allocates a buffer from the new async system
  1349. //-----------------------------------------------------------------------------
  1350. void* CAsyncFileSystem::OldAsyncAllocatorCallback( const char *pszFilename, unsigned nBytes )
  1351. {
  1352. return ((CAsyncFileSystem*) g_pAsyncFileSystem)->AllocateBuffer( nBytes, 16 );
  1353. }
  1354. //-----------------------------------------------------------------------------
  1355. // STATIC CAsyncFileSystem::AsyncIOCallbackGateway
  1356. // - receives callbacks from the old Async file system
  1357. // Thunks the callback back into the context of the CAsyncFileSystem object
  1358. //-----------------------------------------------------------------------------
  1359. void CAsyncFileSystem::AsyncIOCallbackGateway(const FileAsyncRequest_t &request, int nBytesRead, FSAsyncStatus_t err)
  1360. {
  1361. CAsyncRequestBase* pRequest = static_cast<CAsyncRequestBase*>( request.pContext );
  1362. // Pack the results we care about into our own structure
  1363. CAsyncResultInfo_t results;
  1364. results.m_nBytesTransferred = nBytesRead;
  1365. results.m_pAllocatedBuffer = request.pData;
  1366. results.m_ErrorCode = err;
  1367. // gateway back to the CAsyncFileSystem object instance
  1368. ((CAsyncFileSystem*) g_pAsyncFileSystem)->AsyncIOCallBackHandler( pRequest, results );
  1369. }
  1370. //-----------------------------------------------------------------------------
  1371. // STATIC CAsyncFileSystem::AsyncSearchCallbackGateway
  1372. // - receives callbacks from the old Async file system search function
  1373. // Thunks the callback back into the context of the CAsyncFileSystem object
  1374. //-----------------------------------------------------------------------------
  1375. void CAsyncFileSystem::AsyncSearchCallbackGateway( void* pContext, FSAsyncStatus_t err )
  1376. {
  1377. CAsyncRequestBase* pRequest = static_cast<CAsyncRequestBase*>( pContext );
  1378. // Pack the results we care about into our own structure
  1379. CAsyncResultInfo_t results;
  1380. results.m_ErrorCode = err;
  1381. // gateway back to the CAsyncFileSystem object instance
  1382. ((CAsyncFileSystem*) g_pAsyncFileSystem)->AsyncIOCallBackHandler( pRequest, results );
  1383. }
  1384. //-----------------------------------------------------------------------------
  1385. // CAsyncFileSystem::AsyncIOCallBackReadJob
  1386. // - Handler for a completed file Read Job
  1387. //-----------------------------------------------------------------------------
  1388. void CAsyncFileSystem::AsyncIOCallBackHandler(CAsyncRequestBase* pRequest, CAsyncResultInfo_t& results )
  1389. {
  1390. // Get the base info from the request
  1391. // CAsyncRequestBase* pRequest = static_cast<CAsyncRequestBase*>( request.pContext );
  1392. if ( !m_InFlight.IsInQueue( pRequest ) )
  1393. {
  1394. Error( "Can't find completed Async IO request" );
  1395. return;
  1396. }
  1397. // Move the request to the completed list
  1398. m_AsyncStateUpdateMutex.Lock();
  1399. m_InFlight.Remove( pRequest );
  1400. pRequest->m_RequestState = ASYNC_REQUEST_STATE_AWATING_FINISH;
  1401. m_nJobsInflight--;
  1402. // Were we asked to abort while we were servicing?
  1403. if ( pRequest->m_bAbortRequest )
  1404. {
  1405. pRequest->AbortAfterServicing( results ); // Clean up any work in progress
  1406. pRequest->DeleteOuter(); // Destroy the request
  1407. m_AsyncStateUpdateMutex.Unlock();
  1408. KickOffFileJobs(); // go on to next ho
  1409. return;
  1410. }
  1411. // we're not aborting, so do the task specific work
  1412. pRequest->UpdateAfterServicing( results );
  1413. // handle the error results from the old system
  1414. pRequest->m_pOldAsyncStatus = results.m_ErrorCode;
  1415. switch ( results.m_ErrorCode )
  1416. {
  1417. case FSASYNC_ERR_ALIGNMENT:
  1418. {
  1419. pRequest->m_RequestStatus = ASYNC_REQUEST_ERROR_ALIGNMENT;
  1420. break;
  1421. }
  1422. case FSASYNC_ERR_FAILURE:
  1423. {
  1424. pRequest->m_RequestStatus = ASYNC_REQUEST_ERROR_FAILURE;
  1425. break;
  1426. }
  1427. case FSASYNC_ERR_READING:
  1428. {
  1429. pRequest->m_RequestStatus = ASYNC_REQUEST_ERROR_READING;
  1430. break;
  1431. }
  1432. case FSASYNC_ERR_NOMEMORY:
  1433. {
  1434. pRequest->m_RequestStatus = ASYNC_REQUEST_ERROR_NOMEMORY;
  1435. break;
  1436. }
  1437. case FSASYNC_ERR_UNKNOWNID:
  1438. {
  1439. pRequest->m_RequestStatus = ASYNC_REQUEST_ERROR_UNKNOWNID;
  1440. break;
  1441. }
  1442. case FSASYNC_ERR_FILEOPEN:
  1443. {
  1444. pRequest->m_RequestStatus = ASYNC_REQUEST_ERROR_FILEOPEN;
  1445. break;
  1446. }
  1447. case FSASYNC_OK:
  1448. {
  1449. pRequest->m_RequestStatus = ASYNC_REQUEST_OK;
  1450. break;
  1451. }
  1452. case FSASYNC_STATUS_PENDING:
  1453. case FSASYNC_STATUS_INPROGRESS:
  1454. case FSASYNC_STATUS_ABORTED:
  1455. case FSASYNC_STATUS_UNSERVICED:
  1456. default:
  1457. {
  1458. Error( "Async result Status makes no sense" );
  1459. pRequest->m_RequestStatus = ASYNC_REQUEST_OK;
  1460. break;
  1461. }
  1462. };
  1463. m_Completed.AddToTail( pRequest );
  1464. m_AsyncStateUpdateMutex.Unlock();
  1465. // Notify anyone who is listening that an IO has completed
  1466. m_CompletionSignal.Set();
  1467. // if we have other jobs in the priority queue, we have the ability to submit them now
  1468. KickOffFileJobs();
  1469. // Was this a synchronous operation?
  1470. if ( pRequest->m_pSyncThreadEvent != NULL )
  1471. {
  1472. // wake up the calling thread...
  1473. pRequest->m_pSyncThreadEvent->Set();
  1474. }
  1475. else
  1476. {
  1477. // This was an Async operation, so we notify anyone who cares...
  1478. NotifyMessageQueueOrCallback( pRequest );
  1479. }
  1480. }
  1481. //-----------------------------------------------------------------------------
  1482. // CAsyncFileSystem::NotifyMessageQueueOrCallback
  1483. // Places a notification in the designated message queue.
  1484. // if no queue is specified, a callback can be directly performed
  1485. //
  1486. //-----------------------------------------------------------------------------
  1487. void CAsyncFileSystem::NotifyMessageQueueOrCallback( CAsyncRequestBase* pRequest )
  1488. {
  1489. // ok, do we have an IO completion queue to add this to?
  1490. if ( pRequest->m_pResultQueue != NULL )
  1491. {
  1492. CAsyncIOResult_t result;
  1493. result.m_pRequest = pRequest->GetInterfaceBase();
  1494. result.m_Status = pRequest->GetRequestStatus();
  1495. pRequest->m_pResultQueue->Insert( result );
  1496. }
  1497. else // otherwise we want to do the callback directly from this thread?
  1498. {
  1499. pRequest->ProcessCallback( true ); // remove request upon completion
  1500. }
  1501. }
  1502. //-----------------------------------------------------------------------------
  1503. // STATIC CAsyncFileSystem::AsyncSearchCallbackAddItem
  1504. // - receives callbacks from the old Async file system directory search
  1505. // Adds the results to the desired list
  1506. //-----------------------------------------------------------------------------
  1507. void CAsyncFileSystem::AsyncSearchCallbackAddItem( void* pContext, char* pFoundPath, char* pFoundFile )
  1508. {
  1509. CAsyncSearchRequest* pRequest = reinterpret_cast< CAsyncSearchRequest* >( ((CAsyncRequestBase*) pContext)->GetOuter() );
  1510. CDirectoryEntryInfo_t result;
  1511. V_ComposeFileName( pFoundPath, pFoundFile, result.m_FullFileName, sizeof(result.m_FullFileName) );
  1512. pRequest->m_Results.AddToTail( result );
  1513. }
  1514. //-----------------------------------------------------------------------------
  1515. // CAsyncFileSystem::GetAsyncIORequestStatus
  1516. //
  1517. //-----------------------------------------------------------------------------
  1518. AsyncRequestStatus_t CAsyncFileSystem::GetAsyncFileRequestStatus( const IAsyncRequestBase* pRequest )
  1519. {
  1520. CAsyncRequestBase* pRequestBase = ( (IAsyncRequestBase* ) pRequest)->GetBase();
  1521. if ( !ValidateRequestPtr( pRequestBase ) )
  1522. {
  1523. return ASYNC_REQUEST_ERROR_BADPTR;
  1524. }
  1525. return pRequestBase->m_RequestStatus;
  1526. }
  1527. //-----------------------------------------------------------------------------
  1528. // CAsyncFileSystem::AbortAsyncIORequest
  1529. //
  1530. //-----------------------------------------------------------------------------
  1531. AsyncRequestStatus_t CAsyncFileSystem::AbortAsyncFileRequest( const IAsyncRequestBase* pRequest )
  1532. {
  1533. AUTO_LOCK_FM( m_AsyncStateUpdateMutex );
  1534. CAsyncRequestBase* pRequestBase = NULL;
  1535. AsyncRequestState_t CurrentStage = ASYNC_REQUEST_STATE_UNDEFINED;
  1536. // determine if the pointer is still valid, and get info on it if so
  1537. if ( !ResolveAsyncRequest( pRequest, pRequestBase, CurrentStage ) )
  1538. {
  1539. return ASYNC_REQUEST_ERROR_BADPTR;
  1540. }
  1541. switch( CurrentStage )
  1542. {
  1543. case ASYNC_REQUEST_STATE_COMPOSING:
  1544. {
  1545. return ASYNC_REQUEST_ERROR_NOTSUBMITTED;
  1546. }
  1547. case ASYNC_REQUEST_STATE_SUBMITTED:
  1548. {
  1549. pRequestBase->DeleteOuter(); // destroy request, it's destructor will remove it from m_Submitted
  1550. return ASYNC_REQUEST_OK;
  1551. }
  1552. case ASYNC_REQUEST_STATE_SERVICING:
  1553. {
  1554. // Need to flag it for auto-release once it completes
  1555. return ASYNC_REQUEST_ERROR_NOTSUBMITTED;
  1556. }
  1557. // already completed, nothing to abort
  1558. case ASYNC_REQUEST_STATE_AWATING_FINISH:
  1559. case ASYNC_REQUEST_STATE_COMPLETED:
  1560. {
  1561. return ASYNC_REQUEST_ERROR_ALREADYSERVICED;
  1562. }
  1563. default:
  1564. {
  1565. return ASYNC_REQUEST_ERROR_BADPTR;
  1566. }
  1567. }
  1568. }
  1569. //-----------------------------------------------------------------------------
  1570. // CAsyncFileSystem::ResolveAsyncRequest - take an interface pointer supplied
  1571. // by a caller and 1) Determine if it is valid and 2) return base info if so
  1572. //-----------------------------------------------------------------------------
  1573. bool CAsyncFileSystem::ResolveAsyncRequest( const IAsyncRequestBase* pRequest, CAsyncRequestBase*& pRequestBase, AsyncRequestState_t& CurrentStage )
  1574. {
  1575. // We should only be called when the Mutex is taken
  1576. Assert( m_AsyncStateUpdateMutex.GetDepth() > 0 );
  1577. // search our queues for the pointer
  1578. // We do it the slow way, on the rare chance that the pointer pRequest points to invalid memory
  1579. // Once we know it is valid, we can probe it.
  1580. if ( m_Composing.IsInQueueIp( pRequest ) )
  1581. {
  1582. pRequestBase = ( (IAsyncRequestBase* ) pRequest)->GetBase();
  1583. CurrentStage = ASYNC_REQUEST_STATE_COMPOSING;
  1584. return true;
  1585. }
  1586. if ( m_Submitted.IsInQueueIp( pRequest ) )
  1587. {
  1588. pRequestBase = ( (IAsyncRequestBase* ) pRequest)->GetBase();
  1589. CurrentStage = ASYNC_REQUEST_STATE_SUBMITTED;
  1590. return true;
  1591. }
  1592. if ( m_InFlight.IsInQueueIp( pRequest ) )
  1593. {
  1594. pRequestBase = ( (IAsyncRequestBase* ) pRequest)->GetBase();
  1595. CurrentStage = ASYNC_REQUEST_STATE_SERVICING;
  1596. return true;
  1597. }
  1598. if ( m_Completed.IsInQueueIp( pRequest ) )
  1599. {
  1600. pRequestBase = ( (IAsyncRequestBase* ) pRequest)->GetBase();
  1601. CurrentStage = ( (IAsyncRequestBase* ) pRequest)->GetRequestState();
  1602. return true;
  1603. }
  1604. pRequestBase = NULL;
  1605. CurrentStage = ASYNC_REQUEST_STATE_UNDEFINED;
  1606. return false;
  1607. }
  1608. //-----------------------------------------------------------------------------
  1609. // CAsyncFileSystem::RemoveRequest
  1610. // - remove request from any queue (assume it is being deleted)
  1611. //-----------------------------------------------------------------------------
  1612. void CAsyncFileSystem::RemoveRequest( CAsyncRequestBase* pRequest )
  1613. {
  1614. AUTO_LOCK_FM( m_AsyncStateUpdateMutex );
  1615. // Is status trustworthy? maybe not?
  1616. switch ( pRequest->m_RequestState )
  1617. {
  1618. case ASYNC_REQUEST_STATE_COMPOSING:
  1619. {
  1620. m_Composing.Remove( pRequest );
  1621. break;
  1622. }
  1623. case ASYNC_REQUEST_STATE_SUBMITTED:
  1624. {
  1625. m_Submitted.Remove( pRequest );
  1626. break;
  1627. }
  1628. case ASYNC_REQUEST_STATE_SERVICING:
  1629. {
  1630. m_InFlight.Remove( pRequest);
  1631. break;
  1632. }
  1633. case ASYNC_REQUEST_STATE_AWATING_FINISH:
  1634. case ASYNC_REQUEST_STATE_COMPLETED:
  1635. {
  1636. m_Completed.Remove( pRequest );
  1637. break;
  1638. }
  1639. default:
  1640. {
  1641. Error( " Couldn't Find Async Request to Remove" );
  1642. break;
  1643. }
  1644. }
  1645. }
  1646. //-----------------------------------------------------------------------------
  1647. // CAsyncFileSystem::AsyncIOSuspendAll
  1648. // - will suspend the servicing of queued file requests
  1649. // - returns immediately unless bWaitForIOCompletion set, in which case
  1650. // returns after all jobs in the process of being serviced complete
  1651. //-----------------------------------------------------------------------------
  1652. void CAsyncFileSystem::SuspendAllAsyncIO( bool bWaitForIOCompletion )
  1653. {
  1654. m_nSuspendCount++;
  1655. if ( bWaitForIOCompletion && m_nSuspendCount > 0 )
  1656. {
  1657. WaitForServincingIOCompletion();
  1658. }
  1659. }
  1660. //-----------------------------------------------------------------------------
  1661. // CAsyncFileSystem::ResumeAllAsyncIO
  1662. // - Cancels a previous request to suspect all Async IO
  1663. // - resumes the servicing of async jobs that are queued
  1664. //-----------------------------------------------------------------------------
  1665. void CAsyncFileSystem::ResumeAllAsyncIO()
  1666. {
  1667. Assert ( m_nSuspendCount > 0 );
  1668. m_nSuspendCount--;
  1669. if ( m_nSuspendCount <= 0 )
  1670. {
  1671. Assert( m_nSuspendCount == 0 );
  1672. m_nSuspendCount = 0;
  1673. KickOffFileJobs();
  1674. }
  1675. }
  1676. //-----------------------------------------------------------------------------
  1677. // CAsyncFileSystem::AsyncIOAbortAll
  1678. // aborts all file requests submitted but not serviced
  1679. // requests that have been created, but not submitted are unaffected
  1680. //-----------------------------------------------------------------------------
  1681. AsyncRequestStatus_t CAsyncFileSystem::AbortAllAsyncIO( bool bWaitForIOCompletion )
  1682. {
  1683. {
  1684. AUTO_LOCK_FM( m_AsyncStateUpdateMutex );
  1685. if ( m_Submitted.GetSize() <= 0 )
  1686. {
  1687. // return immediately if we're not waiting on jobs to finish
  1688. if ( m_nJobsInflight == 0 || bWaitForIOCompletion == false )
  1689. {
  1690. return ASYNC_REQUEST_OK;
  1691. }
  1692. }
  1693. // Remove all jobs from the priority queue and discard
  1694. while ( m_Submitted.GetSize() > 0 )
  1695. {
  1696. CAsyncRequestBase* pRequest = m_Submitted.RemoveHead();
  1697. pRequest->DeleteOuter(); // Destroy the request
  1698. }
  1699. // Tell jobs currently being serviced to abort when finished
  1700. while ( m_InFlight.GetSize() > 0 )
  1701. {
  1702. CAsyncRequestBase* pRequest = m_InFlight.RemoveHead();
  1703. pRequest->m_bAbortRequest = true;
  1704. }
  1705. }
  1706. if ( bWaitForIOCompletion )
  1707. {
  1708. WaitForServincingIOCompletion();
  1709. }
  1710. return ASYNC_REQUEST_OK;
  1711. }
  1712. //-----------------------------------------------------------------------------
  1713. // CAsyncFileSystem::BlockUntilAsyncIOComplete
  1714. // Suspends the calling thread until a pending IO completes
  1715. //-----------------------------------------------------------------------------
  1716. bool CAsyncFileSystem::BlockUntilAsyncIOComplete( const IAsyncRequestBase* pRequest )
  1717. {
  1718. //CAsyncRequestBase* theRequest = reinterpret_cast<CAsyncRequestBase*>( const_cast<IAsyncRequestBase*>( pRequest ) );
  1719. CAsyncRequestBase* pRequestBase = ( (IAsyncRequestBase* ) pRequest)->GetBase();
  1720. // Validate the request from the user....
  1721. if ( !ValidateRequestPtr( pRequestBase ) )
  1722. {
  1723. return false;
  1724. }
  1725. // Can't block while all IO is turned off
  1726. if ( m_bIOSuspended )
  1727. {
  1728. return false;
  1729. }
  1730. // has to be submitted
  1731. if ( pRequestBase->GetRequestState() <= ASYNC_REQUEST_STATE_COMPOSING )
  1732. {
  1733. return false;
  1734. }
  1735. // Ok, we have to grab the mutex to safely check the request state
  1736. bool waitforIt = false;
  1737. CThreadEvent syncEvent;
  1738. m_AsyncStateUpdateMutex.Lock();
  1739. // Can we just add the signaling request?
  1740. if ( pRequestBase->GetRequestState() < ASYNC_REQUEST_STATE_AWATING_FINISH )
  1741. {
  1742. Assert( pRequestBase->m_pSyncThreadEvent);
  1743. pRequestBase->m_pSyncThreadEvent = &syncEvent;
  1744. waitforIt = true;
  1745. }
  1746. m_AsyncStateUpdateMutex.Unlock();
  1747. // ok, no matetr what the request has the event set before it was finished, so even if
  1748. // it finished in the meantime, the thred event will get signaled and it won't notify a completion queue
  1749. if ( waitforIt )
  1750. {
  1751. pRequestBase->m_pSyncThreadEvent->Wait();
  1752. NotifyMessageQueueOrCallback( pRequestBase );
  1753. }
  1754. return true;
  1755. }
  1756. //-----------------------------------------------------------------------------
  1757. // CAsyncFileSystem::WaitForServincingIOCompletion
  1758. // pauses the calling thread until all IO jobs being serviced
  1759. // by the old system are completed..
  1760. //-----------------------------------------------------------------------------
  1761. void CAsyncFileSystem::WaitForServincingIOCompletion()
  1762. {
  1763. while ( m_nJobsInflight > 0 )
  1764. {
  1765. m_CompletionSignal.Wait( 10 );
  1766. }
  1767. }
  1768. //-----------------------------------------------------------------------------
  1769. // CAsyncFileSystem::AllocateBuffer
  1770. //
  1771. //-----------------------------------------------------------------------------
  1772. void* CAsyncFileSystem::AllocateBuffer( size_t nBufferSize, int nAlignment)
  1773. {
  1774. Assert( nAlignment >= 0 );
  1775. Assert( ValueIsPowerOfTwo( nAlignment ) );
  1776. void* pMem = MemAlloc_AllocAligned( nBufferSize, nAlignment );
  1777. #if defined(_DEBUG)
  1778. // In debug mode we track allocations so we later can track down leaks, etc
  1779. m_MemoryTrackMutex.Lock();
  1780. m_AllocList.AddToTail( pMem );
  1781. m_MemoryTrackMutex.Unlock();
  1782. #endif
  1783. return pMem;
  1784. }
  1785. //-----------------------------------------------------------------------------
  1786. // CAsyncFileSystem::ReleaseBuffer
  1787. //
  1788. //-----------------------------------------------------------------------------
  1789. void CAsyncFileSystem::ReleaseBuffer( void* pBuffer )
  1790. {
  1791. Assert ( pBuffer != NULL );
  1792. #if defined(_DEBUG)
  1793. // In debug mode we verify that we had actually allocated this
  1794. m_MemoryTrackMutex.Lock();
  1795. Assert( m_AllocList.FindAndFastRemove( pBuffer ) == true );
  1796. m_MemoryTrackMutex.Unlock();
  1797. #endif
  1798. MemAlloc_FreeAligned( pBuffer );
  1799. }
  1800. //-----------------------------------------------------------------------------
  1801. // CAsyncFileSystem::ValidateRequestPtr
  1802. //
  1803. //-----------------------------------------------------------------------------
  1804. bool CAsyncFileSystem::ValidateRequestPtr( CAsyncRequestBase* pRequest )
  1805. {
  1806. // can't let it slip state between lines here...
  1807. AUTO_LOCK_FM( m_AsyncStateUpdateMutex );
  1808. switch ( pRequest->m_RequestState )
  1809. {
  1810. case ASYNC_REQUEST_STATE_COMPOSING:
  1811. {
  1812. if ( m_Composing.IsInQueue( pRequest ) )
  1813. {
  1814. return true;
  1815. }
  1816. }
  1817. case ASYNC_REQUEST_STATE_SUBMITTED:
  1818. {
  1819. if ( m_Submitted.IsInQueue( pRequest ) )
  1820. {
  1821. return true;
  1822. }
  1823. }
  1824. case ASYNC_REQUEST_STATE_SERVICING:
  1825. {
  1826. if ( m_InFlight.IsInQueue( pRequest ) )
  1827. {
  1828. return true;
  1829. }
  1830. }
  1831. case ASYNC_REQUEST_STATE_AWATING_FINISH:
  1832. case ASYNC_REQUEST_STATE_COMPLETED:
  1833. {
  1834. if ( m_Completed.IsInQueue( pRequest ) )
  1835. {
  1836. return true;
  1837. }
  1838. }
  1839. default:
  1840. {
  1841. return false;
  1842. }
  1843. }
  1844. }
  1845. //-----------------------------------------------------------------------------
  1846. // CAsyncFileSystem::ValidateRequest
  1847. //
  1848. //-----------------------------------------------------------------------------
  1849. AsyncRequestStatus_t CAsyncFileSystem::ValidateRequest( CAsyncRequestBase* pRequest, bool bPerformSync )
  1850. {
  1851. // Is this a request we know about and is awaiting submission?
  1852. if ( !m_Composing.IsInQueue( pRequest ) )
  1853. {
  1854. // Can we find it already being processed?
  1855. if ( m_Submitted.IsInQueue( pRequest ) ||
  1856. m_InFlight.IsInQueue( pRequest ) ||
  1857. m_Completed.IsInQueue( pRequest ) )
  1858. {
  1859. return ASYNC_REQUEST_ERROR_ALREADYSUBMITTED;
  1860. }
  1861. return ASYNC_REQUEST_ERROR_BADPTR; // We think the pointer is bad
  1862. }
  1863. // Now we check the contents of the request to make sure it makes sense...
  1864. // file operation must be set
  1865. if ( pRequest->GetAsyncOperationType() <= ASYNC_OP_UNDEFINED || pRequest->GetAsyncOperationType() >= ASYNC_OP_COUNT )
  1866. {
  1867. return ASYNC_REQUEST_ERROR_BADOPER;
  1868. }
  1869. // Are we doing synchronous IO?
  1870. if ( bPerformSync )
  1871. {
  1872. // No callback is allowable in sync mode
  1873. if ( pRequest->m_pCallback != NULL || pRequest->m_pResultQueue != NULL )
  1874. {
  1875. // return ASYNC_REQUEST_ERROR_NOTVALIDSYNCRONOUS;
  1876. // just ignore the callbacks and do the type specific validation
  1877. }
  1878. }
  1879. else
  1880. {
  1881. // We need a completion queue, a callback or both
  1882. if ( pRequest->m_pResultQueue == NULL && pRequest->m_pCallback == NULL )
  1883. {
  1884. return ASYNC_REQUEST_ERROR_NONOTIFICATION; // must have a notification or callback
  1885. }
  1886. }
  1887. // Do the request specific validation
  1888. return pRequest->ValidateSubmittedRequest( bPerformSync );
  1889. }
  1890. //-----------------------------------------------------------------------------
  1891. // s_FileNameCharMap - helper table for validating filenames and path processing
  1892. // The values are control vales for ASCII character 0 to 127. They are
  1893. //
  1894. // 0 - invalid character
  1895. // 1 - uppercase character (convert to lower and complain)
  1896. // 2 - valid anytime character
  1897. // 3 - path divider ( "\" or "/" )
  1898. // 4 - valid only in the middle of a name
  1899. // 5 - name extension character ( "." )
  1900. // 6 - drive specifier ":"
  1901. //
  1902. //-----------------------------------------------------------------------------
  1903. byte s_FileNameCharMap[128] = {
  1904. // 0-31 - control codes
  1905. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1906. // 32-63 sp ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
  1907. 4, 2, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 5, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 0, 0, 0, 0, 0,
  1908. // 64-95 @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _
  1909. 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 3, 0, 2, 2,
  1910. // 96-127 ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ del
  1911. 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 0 };
  1912. //-----------------------------------------------------------------------------
  1913. // CAsyncFileSystem::ValidateFileName
  1914. // - examines the filename for problems, fixes or rejects it if so.
  1915. //
  1916. //-----------------------------------------------------------------------------
  1917. AsyncRequestStatus_t ValidateFileName( const char* pFileName )
  1918. {
  1919. // todo - this code doesn't examine each filename or path as closely as could be done
  1920. // According to ChrisB, we shouldn't do all this validation as it's a time suck
  1921. // and our pack files won't care...
  1922. int32 theLength = Q_strlen( pFileName );
  1923. char* theFilename = const_cast<char*>( pFileName );
  1924. if ( theLength >= MAX_PATH )
  1925. {
  1926. return ASYNC_REQUEST_ERROR_PATHTOOLONG;
  1927. }
  1928. int32 lastPathSeparator = -1;
  1929. int32 i = 0;
  1930. bool bUpperCaseWarn = false;
  1931. while ( i < theLength )
  1932. {
  1933. char c = theFilename[i];
  1934. if ( c > 250 ) // allow western european file chars...
  1935. {
  1936. return ASYNC_REQUEST_ERROR_INVALIDFILENAME;
  1937. }
  1938. switch ((int32) s_FileNameCharMap[c])
  1939. {
  1940. case 0: // invalid character
  1941. {
  1942. return ASYNC_REQUEST_ERROR_INVALIDFILENAME;
  1943. }
  1944. case 1: // uppercase character
  1945. {
  1946. theFilename[i] = (char) (c + 0x20); // convert to lower case
  1947. bUpperCaseWarn = true;
  1948. break;
  1949. }
  1950. case 2: // valid character
  1951. {
  1952. break;
  1953. }
  1954. case 3: // path divider
  1955. {
  1956. if ( lastPathSeparator >= 0 )
  1957. {
  1958. if ( i-1 == lastPathSeparator || i == theLength-1 )
  1959. {
  1960. return ASYNC_REQUEST_ERROR_BADPATHSPEC;
  1961. }
  1962. }
  1963. lastPathSeparator = i;
  1964. break;
  1965. }
  1966. case 4: // valid only in the middle of a filename
  1967. {
  1968. if ( i-1 == lastPathSeparator ) // 1st character in this section?
  1969. {
  1970. return ASYNC_REQUEST_ERROR_INVALIDFILENAME;
  1971. }
  1972. break;
  1973. }
  1974. case 5: // extension separator
  1975. {
  1976. break;
  1977. }
  1978. case 6: // drive :
  1979. {
  1980. // Always needs to occur as the 2nd character in the name if at all
  1981. if ( i != 1 )
  1982. {
  1983. return ASYNC_REQUEST_ERROR_BADPATHSPEC;
  1984. }
  1985. break;
  1986. }
  1987. default:
  1988. {
  1989. break;
  1990. }
  1991. }
  1992. i++;
  1993. }
  1994. // check filename length
  1995. int32 nameLen;
  1996. if ( lastPathSeparator < 0 )
  1997. {
  1998. nameLen = i;
  1999. }
  2000. else
  2001. {
  2002. nameLen = i - lastPathSeparator -1;
  2003. }
  2004. if ( nameLen >= CAsyncFileSystem::s_MaxPlatformFileNameLength ) // 40 is maximum length for Xbox STFS
  2005. {
  2006. return ASYNC_REQUEST_ERROR_FILENAMETOOLONG;
  2007. }
  2008. // make sure the path characters are platform correct
  2009. if ( lastPathSeparator >= 0 )
  2010. {
  2011. Q_FixSlashes( theFilename ); // use the library to correct the path dividers for the OS
  2012. // Yes, I know.. not as efficient as we could make it...
  2013. }
  2014. if ( bUpperCaseWarn )
  2015. {
  2016. Warning( "Linux/platform issue - filename '%s' contains uppercase\n", theFilename );
  2017. }
  2018. return ASYNC_REQUEST_OK;
  2019. }