macasyncfile.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:35k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. /*
  36.    Macintosh File buffer
  37.    This is a class which pretends to be a file, yet that reads from the file asynchronously.
  38.    It makes the file async calls which read the file, the callback of which spews into a 
  39.    buffer. This is done by using a timer callback which gets called every 1/2 second to 
  40.    spew more data into the buffer. 
  41.    The global list is meant to be used for storage of all the different file objects
  42.    which will get processed each time through the loop.  
  43.    This will significantly enhance the Macintosh when it comes to local playback of files. 
  44.  */
  45. #include "macasyncfile.h"
  46. #include "hxmm.h"
  47. #include "hxslist.h"
  48. #include "hxcore.h"
  49. #include "hxbuffer.h"
  50. #include "hxstrutl.h"
  51. //#include "../dcondev/dcon.h"
  52. //#define _LOG_DATA 1
  53. // ULONG32 HXAsyncQueueBuffer::msAllocatedBufferCount = 0;
  54. //#define LOG_MULTIPLE_DEFERRED_TASKS 1
  55. #if defined(_DEBUG) && defined (_LOG_DATA)
  56. #define DEBUGSTR(x) DebugStr(x)
  57. #else
  58. #define DEBUGSTR(x)
  59. #endif
  60. CMacAsyncFile::CMacAsyncFile() :
  61.      mReadQueue(NULL)
  62.     ,mSeekFromWhere(0)
  63.     ,mSeekPos(0)
  64.     ,mFilePos(0)
  65.     ,m_ulReadPositionInFile(0)
  66.     ,m_pResponse(NULL)
  67.     ,m_bFileDone(FALSE)
  68.     ,m_bReadPending(FALSE)
  69.     ,m_bSeekPending(FALSE)
  70.     ,m_ulPendingReadCount(FALSE)
  71.     ,mAsyncQueue(NULL)
  72.     ,mOutStandingCallbacks(0)
  73.     ,m_bSettingSeekState(FALSE)    
  74.     ,m_bCheckFromPQ(FALSE)
  75.     ,m_bInternalSeekNeeded(FALSE)
  76.     ,m_pPendingCallbackList(NULL)
  77.     ,m_pTimedPQList(NULL)
  78.     ,m_pLocationPQList(NULL)
  79.     ,m_ulTotalPQSize(0)
  80.     ,m_bDeferredTaskPending(FALSE)
  81.     ,m_bIsQuitting(FALSE)
  82.     ,m_bInEnqueueAsyncBuffers(FALSE)
  83.     ,m_bPendingAsyncSeekCompleted(FALSE)
  84.     ,m_bAllCallbacksCompleted(FALSE)
  85.     ,m_bInProcessPendingCallbacks(FALSE)
  86.     ,m_pMutex(NULL)
  87.     ,m_lRefCount(0)
  88. {
  89.     mAsyncQueue = new CHXSimpleList();
  90.     m_pPendingCallbackList = new CHXSimpleList;
  91.     m_pTimedPQList       = new CHXSimpleList;
  92.     m_pLocationPQList       = new CHXSimpleList;
  93.     mReadQueue = new CBigByteQueue(kMacAsyncBuffer, 1);
  94.     
  95.     m_DeferredTaskStruct.dtReserved = 0;
  96.     m_DeferredTaskStruct.dtFlags = 0;
  97. #ifdef _CARBON
  98.     m_DeferredTaskStruct.dtAddr = NewDeferredTaskUPP(CMacAsyncFile::DeferredTaskProc);
  99. #else
  100.     m_DeferredTaskStruct.dtAddr = NewDeferredTaskProc(CMacAsyncFile::DeferredTaskProc);
  101. #endif
  102.     m_DeferredTaskStruct.dtParam = (long) this; 
  103.     m_DeferredTaskStruct.qType = dtQType;
  104.     
  105.     m_uNumDeferredTask = 0;
  106. #if defined(THREADS_SUPPORTED)
  107.     HXMutex::MakeMutex(m_pMutex);
  108. #else
  109.     HXMutex::MakeStubMutex(m_pMutex);
  110.     
  111.     HX_ASSERT(m_pMutex);
  112. #endif // defined(THREADS_SUPPORTED) 
  113. }
  114. CMacAsyncFile::~CMacAsyncFile()
  115. {
  116.     if (m_DeferredTaskStruct.dtAddr != NULL)
  117.     {
  118. #ifdef _CARBON
  119. DisposeDeferredTaskUPP(m_DeferredTaskStruct.dtAddr);
  120. #else
  121. DisposeRoutineDescriptor(m_DeferredTaskStruct.dtAddr);
  122. #endif
  123. m_DeferredTaskStruct.dtAddr = NULL;
  124.     }    
  125.     Close();
  126.     HX_DELETE(mAsyncQueue);
  127.     HX_DELETE(m_pPendingCallbackList);
  128.     HX_DELETE(m_pTimedPQList);
  129.     HX_DELETE(m_pLocationPQList);
  130.     HX_DELETE(mReadQueue);
  131. #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  132.     BOOL bWaitedForDeferred = FALSE;
  133.     if ( m_bDeferredTaskPending )
  134.     {
  135. bWaitedForDeferred = TRUE;
  136. DebugStr("pCMacAsyncFile dtor -- a deferred task is pending!;g");
  137.     }
  138. #endif
  139.     
  140.     UINT32 timeout = TickCount() + 300L;
  141.     m_bIsQuitting = TRUE;
  142.     while ( m_bDeferredTaskPending && timeout - TickCount() > 0 )
  143.     {
  144. // sit-n-spin, awaiting completion of callbacks.
  145.     }
  146.     
  147. #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  148.     if ( bWaitedForDeferred )
  149.     {
  150. if ( m_bDeferredTaskPending )
  151. {
  152.     DebugStr("pdeferred task STILL pending! This is gonna hurt;g");
  153. }
  154. else
  155. {
  156.     DebugStr( "pDeferred tasks were successfully purged;g" );
  157. }
  158.     }
  159. #endif
  160.     HX_DELETE(m_pMutex);
  161. }
  162. STDMETHODIMP_(ULONG32) CMacAsyncFile::AddRef()
  163. {
  164.     return InterlockedIncrement(&m_lRefCount);
  165. }
  166. STDMETHODIMP_(ULONG32) CMacAsyncFile::Release()
  167. {
  168.     if (InterlockedDecrement(&m_lRefCount) > 0)
  169.     {
  170. return m_lRefCount;
  171.     }
  172.     
  173.     delete this;
  174.     return 0;
  175. }
  176. void CMacAsyncFile::EmptyAsyncQueue()
  177. {    
  178.     m_pMutex->Lock();
  179.     while(mAsyncQueue && mAsyncQueue->GetCount() > 0)
  180.     {
  181.         HXAsyncQueueBuffer* x = (HXAsyncQueueBuffer*) mAsyncQueue->RemoveHead();
  182.         
  183.         HX_DELETE(x);
  184.     }
  185.     
  186.     while(m_pTimedPQList && m_pTimedPQList->GetCount() > 0)
  187.     {
  188.         HXAsyncQueueBuffer* x = (HXAsyncQueueBuffer*) m_pTimedPQList->RemoveHead();
  189.         
  190.         HX_DELETE(x);
  191.     }  
  192.     
  193.     if (m_pLocationPQList)
  194.     {
  195.         m_pLocationPQList->RemoveAll();
  196.     }
  197.     
  198.     m_ulTotalPQSize = 0;
  199.     
  200.     while(m_pPendingCallbackList && m_pPendingCallbackList->GetCount() > 0)
  201.     {
  202.         HXParamBlockRec* pb = (HXParamBlockRec*) m_pPendingCallbackList->RemoveHead();
  203.         
  204.         HX_DELETE(pb);
  205.     }
  206.     m_pMutex->Unlock();
  207. }
  208. void
  209. CMacAsyncFile::DeleteAsyncQueueBuffer(HXAsyncQueueBuffer* x, LISTPOSITION pos)
  210. {
  211.     m_pMutex->Lock();
  212.     BOOL bInserted;
  213.     
  214.     mAsyncQueue->RemoveAt(pos);
  215.     
  216.     /* we only keep full buffers around*/
  217.     if (x->state != AB_STATE_FULL)
  218.     {
  219.         goto discard;
  220.     }
  221.     
  222.     x->current_size    = x->size;
  223.     x->current_buf_ptr = x->buffer;
  224.     // insert in location list
  225.     pos = m_pLocationPQList->GetTailPosition();
  226.     bInserted = FALSE;
  227.     while (pos)
  228.     {
  229.          HXAsyncQueueBuffer* pNode  = (HXAsyncQueueBuffer*) m_pLocationPQList->GetAt(pos);
  230.          if (x->position_in_file >= pNode->position_in_file+pNode->size)
  231.          {
  232.              m_pLocationPQList->InsertAfter(pos, x);
  233.              bInserted = TRUE;
  234.              break;
  235.          }
  236.          
  237.          m_pLocationPQList->GetPrev(pos);
  238.     }
  239.     
  240.     if (!bInserted)
  241.     {
  242.         m_pLocationPQList->AddHead(x);
  243.     }
  244.     
  245.     m_pTimedPQList->AddTail(x);
  246.     m_ulTotalPQSize += x->size;
  247.     
  248.     //dfprintf("mem","PQ Add: %p %lu, %lu, %lun", this, x->position_in_file, x->size, m_ulTotalPQSize);
  249.     // time to expire some -- keep a max of 4*48K in memory?
  250.     if (m_ulTotalPQSize > 4*kMacAsyncBuffer)
  251.     {
  252.         x = (HXAsyncQueueBuffer*) m_pTimedPQList->RemoveHead();
  253.         
  254.         // remove from location list
  255.         pos = m_pLocationPQList->Find((void*)x);
  256.         HX_ASSERT(pos != NULL);
  257.         m_pLocationPQList->RemoveAt(pos);
  258.         
  259.         m_ulTotalPQSize -= x->size;
  260.         //dfprintf("mem", "PQ Remove: %lu, %lu, %lun", x->position_in_file, x->size, m_ulTotalPQSize);
  261.     }
  262.     else
  263.     {
  264.         // early exit
  265.         m_pMutex->Unlock();
  266.         return;
  267.     }
  268. discard:    
  269.     delete x;
  270.     m_pMutex->Unlock();
  271. }
  272. BOOL
  273. CMacAsyncFile::FillBufferFromPQ(UINT32 ulFillPosition)
  274. {
  275.     m_pMutex->Lock();
  276.     BOOL bFilled = FALSE;
  277.     
  278.     LISTPOSITION pos = m_pLocationPQList->GetHeadPosition();
  279.     UINT32 ulEmptyCount = mReadQueue->GetAvailableElements();
  280.     UINT32 ulOrigFillPosition = ulFillPosition;
  281.     while(pos && ulEmptyCount > 0)
  282.     {
  283.         HXAsyncQueueBuffer* x = (HXAsyncQueueBuffer*) m_pLocationPQList->GetAt(pos);
  284.         
  285.         // find the starting byte
  286.         if (x->position_in_file <= ulFillPosition && 
  287.             x->position_in_file+x->size > ulFillPosition)
  288.         {
  289.             UINT32 ulBytesToCopy = x->position_in_file+x->size - ulFillPosition;
  290.             if (ulBytesToCopy > ulEmptyCount)
  291.             {
  292.                 ulBytesToCopy = ulEmptyCount;
  293.             }
  294.             
  295.             HX_ASSERT(ulBytesToCopy > 0);
  296.             HX_VERIFY(mReadQueue->EnQueue(x->buffer+ulFillPosition-x->position_in_file, 
  297.              ulBytesToCopy) == ulBytesToCopy);
  298.             ulEmptyCount -= ulBytesToCopy;
  299.             bFilled = TRUE;
  300.             ulFillPosition += ulBytesToCopy;
  301.             LISTPOSITION timedPos = m_pTimedPQList->Find((void*) x);
  302.             HX_ASSERT(timedPos != NULL);
  303.             m_pTimedPQList->RemoveAt(timedPos);
  304.             m_pTimedPQList->AddTail(x);
  305.             
  306.             m_ulReadPositionInFile = ulFillPosition;
  307.             
  308.     //dfprintf("mem","FillNoSeek: %lu, %lu, %lu %lun", x->position_in_file, x->size, ulOrigFillPosition, ulEmptyCount);
  309.         }
  310.         else if (x->position_in_file > ulFillPosition)
  311.         {
  312.             break;
  313.         }
  314.         
  315.         (void) m_pLocationPQList->GetNext(pos);
  316.     }
  317.     
  318.     // continue to read data form stores buffers if we were succesfully able
  319.     // to fill buffers this time
  320.     m_bCheckFromPQ = bFilled;
  321.     m_pMutex->Unlock();
  322.     return bFilled;
  323. }
  324. //
  325. //      Pump as many of the Asynchronous buffers into the mReadQueue
  326. //      as is possible.
  327. //
  328. void CMacAsyncFile::EnqueueAsyncBuffers()
  329. {
  330.     LISTPOSITION pos = NULL;
  331.     
  332.     m_pMutex->Lock();
  333.     if (m_bInEnqueueAsyncBuffers)
  334.     {
  335.         m_pMutex->Unlock();
  336.         return;
  337.     }
  338.     
  339.     m_bInEnqueueAsyncBuffers = TRUE;
  340.     /* See if there are any pending callbacks */
  341.     ProcessPendingCallbacks();
  342.     
  343.     pos = mAsyncQueue->GetHeadPosition();
  344.     while(pos)
  345.     {
  346. HXAsyncQueueBuffer *x =(HXAsyncQueueBuffer *) mAsyncQueue->GetAt(pos);
  347. if(x)
  348. {
  349.     if(x->state == AB_STATE_IGNORED)
  350.     {
  351. //
  352. //      Due to a seek this buffer has now become out of context
  353. //      So dispose of it and then check the next buffer.
  354. //
  355. DeleteAsyncQueueBuffer(x, pos);
  356. pos = mAsyncQueue->GetHeadPosition();
  357. continue;
  358.     }
  359.     if(x->state == AB_STATE_FULL)
  360.     {
  361.         UINT32 ulEmptyCount = mReadQueue->GetAvailableElements();
  362.         
  363.         /* This assumes that the pending count can NEVER be greater than
  364.          * the total size of the byte queue i.e. the size of the
  365.          * byte queue is the max read size we allow
  366.          * currently it is set to 48K (odd number eh?)
  367.          */
  368.         
  369.         if (m_bReadPending && ulEmptyCount > 0)
  370.         {
  371.             if (ulEmptyCount > x->current_size)
  372.             {
  373.                 ulEmptyCount = x->current_size;
  374.             }
  375.             
  376.             HX_ASSERT(ulEmptyCount > 0);
  377.             // This used to have a HX_VERIFY on the result. After the
  378.             // most recent change, though, where the "m_bReadPending"
  379.             // if statement was changed, the assert started yelling.
  380.             // Nobody's very comfortable about forcibly ignoring the
  381.             // verify, but it seems to function.
  382.             HX_VERIFY(mReadQueue->EnQueue(x->current_buf_ptr, ulEmptyCount) == ulEmptyCount);
  383.             
  384.             x->current_size    -= ulEmptyCount;
  385.             x->current_buf_ptr += ulEmptyCount;
  386.             
  387.             if (x->current_size == 0)
  388.             {
  389. //dfprintf("mem","Done with buffern");
  390. DeleteAsyncQueueBuffer(x, pos);
  391.     }
  392.     else
  393.     {
  394.         break;
  395.     }
  396. }
  397. else
  398. {
  399.     break;
  400. }
  401.     }
  402.     else
  403.     {
  404. //
  405. //      In this case we have to break, because there isn't a buffer available.
  406. //
  407. break;
  408.     }
  409. }
  410. pos = mAsyncQueue->GetHeadPosition();
  411.     }
  412.     m_bInEnqueueAsyncBuffers = FALSE;
  413.     m_pMutex->Unlock();
  414. }
  415. CHXDataFile *CMacAsyncFile::Construct()
  416. {
  417.     CMacAsyncFile *result = new CMacAsyncFile();
  418.     
  419.     result->AddRef();
  420.     return result;
  421. }
  422. HX_RESULT CMacAsyncFile::Open(const char *filename, UINT16 mode, BOOL textflag)
  423. {
  424.     return HXR_NOTIMPL;
  425. }
  426. HX_RESULT CMacAsyncFile::SafeOpen (const char *filename, UINT16 mode, BOOL textflag, BOOL bAtInterrupt)
  427. {
  428. #if defined(_DEBUG) && defined (_LOG_DATA)
  429.     char str[255]; /* Flawfinder: ignore */
  430.    ::sprintf(str, "SafeOpen %d;g", (int) bAtInterrupt); /* Flawfinder: ignore */
  431.     DEBUGSTR(c2pstr(str));
  432. #endif
  433.  
  434.    m_pMutex->Lock();
  435.    HX_RESULT result = CMacFile::Open(filename, mode, textflag);
  436.    ULONG32 count = 0;
  437.     mFilePos = 0;
  438.     m_ulReadPositionInFile = 0;
  439.     if(result == HXR_OK)
  440.     {
  441.     ReadAsyncData(bAtInterrupt);
  442.     }
  443.     //
  444.     //   Set it to null.
  445.     //
  446.     mFilePos = 0;
  447.     
  448.     m_pMutex->Unlock();
  449.     return result;
  450. }
  451.  
  452. HX_RESULT CMacAsyncFile::Close(void)
  453. {
  454.     m_pMutex->Lock();
  455.     HX_RESULT result = CMacFile::Close();
  456.     EmptyAsyncQueue();
  457.     mReadQueue->FlushQueue();
  458.     m_pMutex->Unlock();
  459.     return result;
  460. }
  461. HX_RESULT CMacAsyncFile::Seek(ULONG32 offset, UINT16 fromWhere)
  462. {
  463.     return HXR_NOTIMPL;
  464. }
  465. void
  466. CMacAsyncFile::PerformInternalSeek(BOOL ASYNC)
  467. {
  468.     m_pMutex->Lock();
  469.     mSeekFromWhere = fsFromStart;
  470.     mSeekPos = m_ulReadPositionInFile;
  471.     UpdateFilePos(ASYNC, TRUE);
  472.     m_pMutex->Unlock();
  473. }
  474. HX_RESULT
  475. CMacAsyncFile::SafeSeek(ULONG32 offset, UINT16 fromWhere, BOOL bAtInterrupt)
  476. {
  477. #if defined(_DEBUG) && defined (_LOG_DATA)
  478.     char str[255]; /* Flawfinder: ignore */
  479.    ::sprintf(str, "SafeSeek: %lu %u %d;g", offset, fromWhere, (int) bAtInterrupt); /* Flawfinder: ignore */
  480.     DEBUGSTR(c2pstr(str));
  481. #endif
  482.     if (m_pMutex) m_pMutex->Lock();
  483.     //dfprintf("mem","SafeSeek: %lu, %u, %dn", offset, fromWhere, (int) bAtInterrupt);
  484.     m_bFileDone  = FALSE;
  485.     m_bReadPending = FALSE;
  486.      
  487.     LISTPOSITION pos = NULL;
  488.     /* If we get a read deferred callback while setting the state for buffers in
  489.      * async queue, ignore it
  490.      */
  491.     m_bSettingSeekState = TRUE;
  492.     pos = mAsyncQueue->GetHeadPosition();
  493.     while(pos)
  494.     {
  495. HXAsyncQueueBuffer *x =(HXAsyncQueueBuffer *) mAsyncQueue->GetAt(pos);
  496. if(x->state == AB_STATE_FULL)
  497. {
  498.     DeleteAsyncQueueBuffer(x, pos);
  499.     pos = mAsyncQueue->GetHeadPosition();
  500.     continue;
  501.     //x->state = AB_STATE_IGNORED;
  502. }
  503. /* All other states are pending states and result in AB_STATE_OUTOFCONTEXT */
  504. else if(x->state != AB_STATE_IGNORED)
  505. {
  506.     x->state = AB_STATE_OUTOFCONTEXT;
  507. }
  508. mAsyncQueue->GetNext(pos);
  509.     }
  510.     m_bSettingSeekState = FALSE;
  511.     mReadQueue->FlushQueue();
  512.     m_bSeekPending = TRUE;
  513.     if(BufferedWrite())
  514.     {
  515. CMacFile::Seek(offset, fromWhere);
  516. PendingAsyncSeekDone();
  517.     }
  518.     else
  519.     {
  520.         UINT32 ulSeekPosition = 0;
  521.         BOOL bSeekNeeded = FALSE;
  522.         
  523. switch(fromWhere)
  524. {
  525. case SEEK_SET:
  526.     fromWhere = fsFromStart;
  527.     mSeekFromWhere = fromWhere;
  528.     mSeekPos = offset;
  529.     ulSeekPosition = m_ulReadPositionInFile = offset;
  530.     break;
  531. case SEEK_CUR:
  532.     fromWhere = fsFromMark;
  533.     mSeekFromWhere = fromWhere;
  534.     mSeekPos = offset;
  535.     ulSeekPosition = m_ulReadPositionInFile = mFilePos+offset;
  536.     break;
  537. case SEEK_END:
  538.     //HX_ASSERT(!"Need to add support for seek from end -- XXXRA");
  539.     fromWhere = fsFromLEOF;
  540.     mSeekFromWhere = fromWhere;
  541.     mSeekPos = offset;
  542.     bSeekNeeded = TRUE;
  543.     break;
  544. }
  545.         if (!bSeekNeeded)
  546.         {
  547.             bSeekNeeded = !(FillBufferFromPQ(ulSeekPosition));
  548.         }
  549.         
  550.         if (bSeekNeeded)
  551.         {
  552.     UpdateFilePos(bAtInterrupt);
  553. }
  554. else
  555. {
  556.     mFilePos     = ulSeekPosition;
  557.     mSeekFromWhere = 0;
  558.             m_bInternalSeekNeeded = TRUE;
  559.     PendingAsyncSeekDone();
  560. }
  561.     }
  562.     DEBUGSTR("p EXIT SafeSeek;g");
  563.     
  564.     if (m_pMutex) m_pMutex->Unlock();
  565.     return HXR_OK;
  566. }
  567. HX_RESULT
  568. CMacAsyncFile::SafeRead(ULONG32 count, BOOL bAtInterrupt)
  569. {
  570.     AddRef();
  571.     m_pMutex->Lock();
  572.     HX_ASSERT(m_bReadPending == FALSE);
  573.     if(!mReadQueue || m_bReadPending)
  574.     {
  575.         DEBUGSTR("p SafeRead UNEXPECTED;g");
  576.         //dfprintf("mem", "SafeRead UNEXPECTEDn");
  577.         m_pMutex->Unlock();
  578.         Release();
  579. return HXR_UNEXPECTED;
  580.     }
  581. #if defined(_DEBUG) && defined (_LOG_DATA)
  582.     char str[255]; /* Flawfinder: ignore */
  583.    ::sprintf(str, "SafeRead: %lu %d;g", count, (int) bAtInterrupt); /* Flawfinder: ignore */
  584.     DEBUGSTR(c2pstr(str));
  585. #endif
  586.     
  587.     //dfprintf("mem","SafeRead: %lu, %dn", count, (int) bAtInterrupt);
  588.     m_bReadPending  = TRUE;
  589.     m_ulPendingReadCount = count;
  590.     EnqueueAsyncBuffers();
  591.     ReadAsyncData(bAtInterrupt);
  592.     EnqueueAsyncBuffers();
  593.     
  594.     ProcessPendingRead();
  595.     
  596.    DEBUGSTR("p EXIT SafeRead;g");
  597.    
  598.    m_pMutex->Unlock();
  599.    Release();
  600.    return HXR_OK;
  601. }
  602. ULONG32
  603. CMacAsyncFile::SafeWrite(IHXBuffer* pBuffer, BOOL bAtInterrupt)
  604. {
  605.     m_pMutex->Lock();
  606.     HX_ASSERT(m_bReadPending == FALSE);
  607.     ULONG32 outWrittenSize = 0;
  608.     if(m_bReadPending)
  609.     {
  610.         DEBUGSTR("p SafeWrite UNEXPECTED;g");
  611.         m_pMutex->Unlock();
  612. return outWrittenSize;
  613.     }
  614. #if defined(_DEBUG) && defined (_LOG_DATA)
  615.     char str[255]; /* Flawfinder: ignore */
  616.    ::sprintf(str, "SafeWrite: %d;g", (int) bAtInterrupt); /* Flawfinder: ignore */
  617.     DEBUGSTR(c2pstr(str));
  618. #endif
  619.     
  620.     outWrittenSize = WriteAsyncData(pBuffer, bAtInterrupt);
  621.     DEBUGSTR("p EXIT SafeWrite;g");
  622.     m_pMutex->Unlock();
  623.     return outWrittenSize;
  624. }
  625. ULONG32 CMacAsyncFile::Read(char *buf, ULONG32 count)
  626. {
  627.     return HXR_NOTIMPL;
  628. }
  629. //
  630. //      Static Initializers
  631. //
  632. #ifdef _CARBON
  633. IOCompletionUPP CMacAsyncFile::zmIOCallbackUPP = NewIOCompletionUPP((IOCompletionProcPtr)CMacAsyncFile::zmIOCallback);
  634. #else
  635. IOCompletionUPP CMacAsyncFile::zmIOCallbackUPP = NewIOCompletionProc(CMacAsyncFile::zmIOCallback);
  636. #endif
  637. //
  638. //      Tell
  639. //
  640. ULONG32 CMacAsyncFile::Tell(void)
  641. {
  642.     return mFilePos;
  643. }
  644. //
  645. //       This is the zmIOCompletion callback.
  646. //       When this is done, the data is then pumped into the buffer for this file.
  647. //
  648. pascal void CMacAsyncFile::zmIOCallback(HXParamBlockRec * pb)
  649. {
  650.     HXMM_INTERRUPTON();
  651.     /*
  652.      * Setup and then install a deferred task 
  653.      */
  654.     if (pb != NULL &&  pb->param != NULL)
  655.     {
  656.     
  657. CMacAsyncFile* fileobj = (CMacAsyncFile*) pb->param;
  658. fileobj->m_pMutex->Lock();
  659. if (fileobj->m_DeferredTaskStruct.dtAddr != NULL)
  660. {
  661. #if defined(_DEBUG) && defined (_LOG_DATA)
  662.      char tmpStr1[255]; /* Flawfinder: ignore */
  663.      ::sprintf(tmpStr1, "ENTER INterrupt Callback %p ;g", fileobj); /* Flawfinder: ignore */
  664.      DEBUGSTR(c2pstr(tmpStr1));
  665. #endif
  666.     fileobj->AddToThePendingList((void*) pb);
  667.     
  668.     fileobj->m_uNumDeferredTask++;
  669. #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  670.     /*
  671.     if (fileobj->m_uNumDeferredTask > 1)
  672.     {
  673.         char tmpStr[255];
  674.         ::sprintf(tmpStr, "More than one pending DeferredTask: %u;g", fileobj->m_uNumDeferredTask);
  675.         DebugStr(c2pstr(tmpStr));
  676.     }
  677.     */
  678. #endif
  679.     
  680.     if (!fileobj->m_bDeferredTaskPending)
  681.     {
  682.         if ( !fileobj->m_bIsQuitting )
  683.         {
  684.     fileobj->m_bDeferredTaskPending = TRUE;
  685. #ifdef _CARBON
  686.     DeferredTaskProc(fileobj->m_DeferredTaskStruct.dtParam);
  687. #else
  688.     DTInstall(&fileobj->m_DeferredTaskStruct);
  689. #endif
  690.         }
  691.     }
  692. }
  693. fileobj->m_pMutex->Unlock();
  694.     }
  695.     
  696.     HXMM_INTERRUPTOFF();
  697. }
  698. pascal void CMacAsyncFile::DeferredTaskProc(long inParam)
  699. {
  700.     HXMM_INTERRUPTON();
  701.     DEBUGSTR("pENTER CMacAsyncFile::DeferredTaskProc;g");
  702.     CMacAsyncFile*   fileobj = (CMacAsyncFile*) inParam;;
  703.     if(fileobj)
  704.     {
  705. #if defined(_DEBUG) && defined (_LOG_DATA)
  706.         char tmpStr[255]; /* Flawfinder: ignore */
  707.         sprintf(tmpStr, " This pointer: %p;g", fileobj); /* Flawfinder: ignore */
  708.         DEBUGSTR(c2pstr(tmpStr));
  709. #endif
  710. #if defined(_DEBUG) && defined(LOG_MULTIPLE_DEFERRED_TASKS)
  711.     /*
  712.     if (fileobj->m_uNumDeferredTask != 1)
  713.     {
  714.         char tmpStr[255];
  715.         ::sprintf(tmpStr, "(In DeferredTaskProc) m_uNumDeferredTask != 1: %u;g", fileobj->m_uNumDeferredTask);
  716.         DebugStr(c2pstr(tmpStr));
  717.     }
  718.     */
  719.     if ( !fileobj->m_bDeferredTaskPending )
  720.     {
  721.      DebugStr( "p(In DeferredTaskProc) m_bDeferredTaskPending is false!;g" );
  722.     }
  723. #endif
  724. if ( !fileobj->m_bIsQuitting )
  725. {
  726.     fileobj->ProcessPendingCallbacks();
  727. }
  728.         fileobj->m_bDeferredTaskPending = FALSE;
  729.     }
  730.     
  731.     DEBUGSTR("pLEAVE CMacAsyncFile::DeferredTaskProc;g");
  732.     HXMM_INTERRUPTOFF();
  733. }
  734. void CMacAsyncFile::ProcessPendingCallbacks()
  735. {
  736.     m_pMutex->Lock();
  737.     if (m_bInProcessPendingCallbacks)
  738.     {
  739.         m_pMutex->Unlock();
  740.         return;
  741.     }
  742.  
  743.  start:   
  744.     m_bInProcessPendingCallbacks = TRUE;
  745.     
  746.     while (m_pPendingCallbackList && m_pPendingCallbackList->GetCount() > 0)
  747.     {
  748.         m_uNumDeferredTask--;
  749.         HXParamBlockRec* pb = (HXParamBlockRec*) m_pPendingCallbackList->RemoveHead();
  750.         if (pb && pb->param)
  751.         {
  752.             ProcessBlock(pb);
  753.         }
  754.         HX_DELETE(pb);
  755.     }
  756.     
  757.     EnqueueAsyncBuffers();
  758.     if (m_bPendingAsyncSeekCompleted)
  759.     {
  760.         m_bPendingAsyncSeekCompleted = FALSE;
  761. PendingAsyncSeekDone();
  762.     }
  763.     
  764.     if (mOutStandingCallbacks == 0 && m_bAllCallbacksCompleted)
  765.     {
  766.         m_bAllCallbacksCompleted = FALSE;
  767.         AllPendingCallbacksDone();
  768.     }    
  769.     
  770.     m_bInProcessPendingCallbacks = FALSE;
  771.     
  772.     /* Do we still have more pending callbacks to process? */
  773.     if (m_pPendingCallbackList && m_pPendingCallbackList->GetCount() > 0)
  774.     {
  775.         goto start;
  776.     }
  777.     m_pMutex->Unlock();
  778. }        
  779. void CMacAsyncFile::ProcessBlock(HXParamBlockRec* pb)
  780. {
  781. m_pMutex->Lock();
  782. if (mOutStandingCallbacks > 0)
  783. {
  784.     mOutStandingCallbacks--;
  785. }
  786. if(pb->entry->state == AB_STATE_OUTOFCONTEXT ||
  787.    m_bSettingSeekState)
  788. {
  789.     //
  790.     //      Don't need to do anything with this data
  791.     //      just ignore it. 
  792.     //              
  793.     pb->entry->state = AB_STATE_IGNORED;
  794. }
  795. else if (pb->entry->state == AB_STATE_ASYNC_INTERNAL_SEEK)
  796. {
  797.     m_ulReadPositionInFile = pb->io.ioParam.ioPosOffset;
  798.     pb->entry->state = AB_STATE_IGNORED;
  799. }
  800. else if (pb->entry->state == AB_STATE_ASYNC_SEEK)
  801. {
  802.     mFilePos = pb->io.ioParam.ioPosOffset;
  803.     m_ulReadPositionInFile = mFilePos;
  804.     pb->entry->state = AB_STATE_IGNORED;
  805.     m_bPendingAsyncSeekCompleted = TRUE;     
  806. }
  807. else if (pb->entry->state == AB_STATE_WRITE)
  808. {
  809.     HX_VECTOR_DELETE(pb->entry->buffer);
  810.     pb->entry->state = AB_STATE_IGNORED;
  811. }
  812. else
  813. {
  814.     /* Are we at the end of the file? */
  815.     if (pb->io.ioParam.ioActCount < pb->entry->size)
  816.     {
  817.         m_bFileDone = TRUE;
  818. #if defined(_DEBUG) && defined (_LOG_DATA)
  819.         char tmpStr[255]; /* Flawfinder: ignore */
  820.         sprintf(tmpStr, "ProcessBlock %d %d;g", pb->io.ioParam.ioActCount, pb->entry->size); /* Flawfinder: ignore */
  821.         DEBUGSTR(c2pstr(tmpStr));
  822. #endif
  823.     }
  824.     pb->entry->size = pb->io.ioParam.ioActCount;
  825.     pb->entry->current_size = pb->io.ioParam.ioActCount;
  826.     if(pb->io.ioParam.ioBuffer && pb->entry->size > 0)
  827.     {
  828.         pb->entry->state = AB_STATE_FULL;
  829.         m_ulReadPositionInFile += pb->entry->size;
  830.     }
  831.     else
  832.     {
  833.         pb->entry->state = AB_STATE_IGNORED;
  834.     }
  835. }
  836. if (mOutStandingCallbacks == 0)
  837. {
  838.             m_bAllCallbacksCompleted = TRUE;
  839. }
  840. m_pMutex->Unlock();
  841. }
  842. void CMacAsyncFile::AddToThePendingList(void* pNode)
  843. {
  844.     m_pMutex->Lock();
  845.     /* Atleast one of the list MUST be free to operate on */
  846.     HX_ASSERT(m_pPendingCallbackList != NULL);
  847.     if (m_pPendingCallbackList)
  848.     {
  849.         m_pPendingCallbackList->AddTail(pNode);
  850.     }
  851.     m_pMutex->Unlock();
  852. }
  853. //
  854. //
  855. //      Start the Async file IO call which physically reads the data into the buffer.
  856. //
  857. //
  858. void CMacAsyncFile::ReadAsyncData(BOOL ASYNC)
  859. {
  860.     m_pMutex->Lock();
  861.     OSErr e = noErr;
  862. #if defined(_DEBUG) && defined (_LOG_DATA)
  863.     char str[255]; /* Flawfinder: ignore */
  864.    ::sprintf(str, "ReadAsyncData: %d;g", (int) ASYNC); /* Flawfinder: ignore */
  865.     DEBUGSTR(c2pstr(str));
  866. #endif
  867.  
  868.     // mOutStandingCallbacks: if there are any, then we bail right
  869.     // now 'cause we don't want scads of pending callbacks... the math
  870.     // will work out in the end because subsequent calls will have us
  871.     // read more bytes.
  872.     
  873.     if(!mRefNum || m_bFileDone || mOutStandingCallbacks > 0)
  874.     {
  875.         m_pMutex->Unlock();
  876. return;
  877.     }
  878.     ULONG32 emptysize = mReadQueue->GetAvailableElements();
  879.     if(emptysize < kNeedToReadThreshhold)
  880.     {
  881.         m_pMutex->Unlock();
  882.         DEBUGSTR("p ReadAsyncData: emptysize < kNeedToReadThreshhold ;g");
  883.   return;
  884.     }
  885.     
  886.     if (m_bCheckFromPQ)
  887.     {
  888.         BOOL bFilled = FillBufferFromPQ(m_ulReadPositionInFile);
  889.         if (bFilled)
  890.         {
  891.             emptysize = mReadQueue->GetAvailableElements();
  892.             if(emptysize < kNeedToReadThreshhold)
  893.             {
  894.                 m_pMutex->Unlock();
  895.                 return;
  896.             }
  897.         }
  898.     }
  899.     
  900.     if (emptysize > kMacMaxChunkToRead)
  901.     {
  902. emptysize = kMacMaxChunkToRead;
  903.     }
  904.     
  905.     if (m_bInternalSeekNeeded)
  906.     {
  907.         m_bInternalSeekNeeded = FALSE;
  908.         PerformInternalSeek(ASYNC);
  909.         // more stuff will be done once we get async callback for internal seek
  910.         if (ASYNC)
  911.         {
  912.             m_pMutex->Unlock();
  913.             return;
  914.         }
  915.     }
  916.     HXParamBlockRec *pb = new HXParamBlockRec;
  917.     memset(pb, 0, sizeof(HXParamBlockRec));
  918.     pb->param = this;
  919.     pb->io.ioParam.ioCompletion = zmIOCallbackUPP;
  920.     pb->io.ioParam.ioRefNum = mRefNum;
  921.     pb->entry = new HXAsyncQueueBuffer;
  922.     memset(pb->entry, 0, sizeof(HXAsyncQueueBuffer));
  923.     pb->entry->size = emptysize;
  924.     pb->entry->current_size = emptysize;
  925.     
  926.     pb->entry->position_in_file = m_ulReadPositionInFile;
  927.     char* tempbuffer = new char[emptysize];
  928.     pb->entry->buffer  = tempbuffer;
  929.     pb->entry->current_buf_ptr  = tempbuffer;
  930.     pb->entry->state = AB_STATE_EMPTY;
  931.     pb->io.ioParam.ioBuffer = tempbuffer;
  932.     pb->io.ioParam.ioReqCount = emptysize;
  933.     HX_ASSERT(mSeekFromWhere == 0);
  934.     e = ReadData(pb, ASYNC);
  935.     if (!ASYNC)
  936.     {
  937.          if (e == noErr)
  938.          {
  939.      pb->entry->state = AB_STATE_FULL;
  940.      pb->entry->size = pb->io.ioParam.ioActCount;
  941.      pb->entry->current_size = pb->io.ioParam.ioActCount;
  942.      m_ulReadPositionInFile += pb->entry->size;
  943.      mAsyncQueue->AddTail(pb->entry);
  944.  }
  945.  else
  946.  {
  947.      HX_DELETE(pb->entry);
  948.  }
  949.        
  950.  HX_DELETE(pb);
  951.     }
  952.     else
  953.     {
  954.         if (e != noErr)
  955.         {
  956.     HX_DELETE(pb->entry);
  957.     HX_DELETE(pb);
  958.         }
  959.     }    
  960.     DEBUGSTR("p ReadAsyncData EXIT; g");
  961.     m_pMutex->Unlock();
  962.     return;
  963. }
  964. ULONG32 CMacAsyncFile::WriteAsyncData(IHXBuffer* pBuffer, BOOL ASYNC)
  965. {
  966.     ULONG32 outWrittenSize = 0;
  967.     OSErr e = noErr;
  968. #if defined(_DEBUG) && defined (_LOG_DATA)
  969.     char str[255]; /* Flawfinder: ignore */
  970.    ::sprintf(str, "WriteAsyncData: %d;g", (int) ASYNC); /* Flawfinder: ignore */
  971.     DEBUGSTR(c2pstr(str));
  972. #endif
  973.  
  974.     if(!mRefNum)
  975.     {
  976. return outWrittenSize;
  977.     }
  978.     pBuffer->AddRef();
  979.     HXParamBlockRec *pb = new HXParamBlockRec;
  980.     memset(pb, 0, sizeof(HXParamBlockRec));
  981.     pb->param = this;
  982.     pb->io.ioParam.ioCompletion = zmIOCallbackUPP;
  983.     pb->io.ioParam.ioRefNum = mRefNum;
  984.     pb->entry = new HXAsyncQueueBuffer;
  985.     memset(pb->entry, 0, sizeof(HXAsyncQueueBuffer));
  986.     
  987.     outWrittenSize = pBuffer->GetSize();
  988.     pb->entry->size = outWrittenSize;
  989.     pb->entry->current_size = outWrittenSize;
  990.     pb->entry->state = AB_STATE_WRITE;
  991.     char* tempbuffer = NULL;
  992.     if (ASYNC)
  993.     {
  994.      tempbuffer = new char[outWrittenSize];
  995.      BlockMoveData(pBuffer->GetBuffer(), tempbuffer, outWrittenSize);
  996.      pb->entry->buffer = tempbuffer;
  997.      pb->entry->current_buf_ptr = tempbuffer;
  998. pb->io.ioParam.ioBuffer = tempbuffer;
  999.     }
  1000.     else
  1001.     {
  1002. pb->io.ioParam.ioBuffer = ( char* ) pBuffer->GetBuffer();
  1003.     }
  1004.     pb->io.ioParam.ioReqCount = outWrittenSize;
  1005.     HX_ASSERT(mSeekFromWhere == 0);
  1006.     e = WriteData(pb, ASYNC);
  1007.     if (!ASYNC)
  1008.     {
  1009.  HX_DELETE(pb->entry);
  1010.  HX_DELETE(pb);
  1011.     }
  1012.     else
  1013.     {
  1014.         if (e != noErr)
  1015.         {
  1016.     HX_DELETE(pb->entry);
  1017.     HX_DELETE(pb);
  1018.         }
  1019.     }    
  1020.     DEBUGSTR("p WriteAsyncData EXIT; g");
  1021.     pBuffer->Release();
  1022.     return outWrittenSize;
  1023. }
  1024. void CMacAsyncFile::UpdateFilePos(BOOL bASync, BOOL bInternal)
  1025. {
  1026.     AddRef();
  1027.     m_pMutex->Lock();
  1028.      DEBUGSTR("p UpdateFilePos;g");
  1029.    OSErr e = noErr;
  1030.     if(!mRefNum)
  1031.     {
  1032. m_pMutex->Unlock();
  1033. Release();
  1034. return;
  1035.     }
  1036.     HXParamBlockRec *pb = new HXParamBlockRec;
  1037.     memset(pb, 0, sizeof(HXParamBlockRec));
  1038.     pb->param = this;
  1039.     pb->io.ioParam.ioRefNum = mRefNum;
  1040.     pb->io.ioParam.ioReqCount = 0;
  1041.     pb->io.ioParam.ioCompletion = zmIOCallbackUPP;
  1042.     pb->entry = new HXAsyncQueueBuffer;
  1043.     memset(pb->entry, 0, sizeof(HXAsyncQueueBuffer));
  1044.     HX_ASSERT(mSeekFromWhere > 0);
  1045.     if(mSeekFromWhere)
  1046.     {
  1047. pb->io.ioParam.ioPosMode = mSeekFromWhere;
  1048. pb->io.ioParam.ioPosOffset = mSeekPos;
  1049. mSeekFromWhere = 0;
  1050. mSeekPos = 0;
  1051. if (bInternal)
  1052. {
  1053.             pb->entry->state = AB_STATE_ASYNC_INTERNAL_SEEK;
  1054.         }
  1055.         else
  1056.         {
  1057.             pb->entry->state = AB_STATE_ASYNC_SEEK;
  1058.         }
  1059.     }
  1060.     e = SeekData(pb, bASync);
  1061.     if (!bASync)
  1062.     {
  1063.          if (e == noErr)
  1064.          {
  1065.      m_ulReadPositionInFile = pb->io.ioParam.ioPosOffset;
  1066.              if (!bInternal)
  1067.              {
  1068.          mFilePos = pb->io.ioParam.ioPosOffset;
  1069.      }
  1070.  }
  1071.      
  1072.  HX_DELETE(pb->entry);
  1073.  HX_DELETE(pb);
  1074.     }
  1075.     else
  1076.     {
  1077.         if (e != noErr)
  1078.         {
  1079.     HX_DELETE(pb->entry);
  1080.     HX_DELETE(pb);
  1081.         }
  1082.     }    
  1083.     if (!bASync && !bInternal)
  1084.     {
  1085. PendingAsyncSeekDone();
  1086.     }
  1087.     m_pMutex->Unlock();
  1088.     Release();
  1089.     return;
  1090. }
  1091. OSErr
  1092. CMacAsyncFile::ReadData(HXParamBlockRec* pb, BOOL ASYNC)
  1093. {
  1094.     m_pMutex->Lock();
  1095.     OSErr e = noErr;
  1096.     if(ASYNC)
  1097.     {
  1098. mAsyncQueue->AddTail(pb->entry);
  1099. mOutStandingCallbacks++;
  1100.     }
  1101.     
  1102.     // xxxbobclark large PBRead's on SMB-mounted volumes are failing here.
  1103.     // That's why we reduced the constants in the .h file for carbon builds.
  1104.     e = PBRead((ParmBlkPtr) pb, ASYNC);
  1105.     if (e == eofErr)
  1106.     {
  1107.     m_bFileDone = TRUE;
  1108.     
  1109.         DEBUGSTR("pFIle Done in ReadData;g");
  1110.     /* Mask this error if this is the last read */
  1111.     /* If either we are in aysnc mode OR we actually read some data */
  1112.     if (ASYNC ||  pb->io.ioParam.ioActCount > 0)
  1113.     {
  1114.      e = noErr;
  1115.     }
  1116.     }
  1117.     if(e != noErr && ASYNC && mOutStandingCallbacks > 0)
  1118.     {
  1119.         mAsyncQueue->RemoveTail();
  1120.         mOutStandingCallbacks--;
  1121.     }
  1122.     m_pMutex->Unlock();
  1123.     return e;
  1124. }
  1125. OSErr
  1126. CMacAsyncFile::WriteData(HXParamBlockRec* pb, BOOL ASYNC)
  1127. {
  1128.     m_pMutex->Lock();
  1129.     OSErr e = noErr;
  1130.     if(ASYNC)
  1131.     {
  1132. mAsyncQueue->AddTail(pb->entry);
  1133. mOutStandingCallbacks++;
  1134.     }
  1135.     e = PBWrite((ParmBlkPtr) pb, ASYNC);
  1136.     if(e != noErr && ASYNC && mOutStandingCallbacks > 0)
  1137.     {
  1138.         mAsyncQueue->RemoveTail();
  1139.         mOutStandingCallbacks--;
  1140.     }
  1141.     m_pMutex->Unlock();
  1142.     return e;
  1143. }
  1144. OSErr
  1145. CMacAsyncFile::SeekData(HXParamBlockRec* pb, BOOL ASYNC)
  1146. {
  1147.     m_pMutex->Lock();
  1148.     OSErr e = noErr;
  1149.     if(ASYNC)
  1150.     {
  1151.     mAsyncQueue->AddTail(pb->entry);
  1152.     mOutStandingCallbacks++;
  1153.     }
  1154.     e = PBSetFPos((ParmBlkPtr) pb, ASYNC);
  1155.     if (e == eofErr)
  1156.     {
  1157. DEBUGSTR("p File done in SeekData");
  1158. m_bFileDone = TRUE;
  1159. e = noErr;
  1160.     }
  1161.     if(e != noErr && ASYNC && mOutStandingCallbacks > 0)
  1162.     {
  1163.         mAsyncQueue->RemoveTail();
  1164. mOutStandingCallbacks--;
  1165.     }
  1166.     m_pMutex->Unlock();
  1167.     return e;
  1168. }
  1169. void
  1170. CMacAsyncFile::PendingAsyncSeekDone()
  1171. {
  1172.     AddRef();
  1173.     m_pMutex->Lock();
  1174.     HX_ASSERT(m_bSeekPending == TRUE);
  1175.     m_bSeekPending = FALSE;
  1176.      DEBUGSTR("p PendingAsyncSeekDone;g");
  1177.    // ? should check status
  1178.     m_pResponse->AsyncSeekDone(HXR_OK);
  1179.     m_pMutex->Unlock();
  1180.     Release();
  1181. }
  1182. void
  1183. CMacAsyncFile::AllPendingCallbacksDone()
  1184. {   
  1185.     DEBUGSTR("p AllPendingCallbacksDone;g");
  1186.     m_pMutex->Lock();
  1187.     
  1188.     HX_ASSERT(m_pPendingCallbackList->GetCount() == 0);
  1189.             
  1190.     if(m_bReadPending)
  1191.     {
  1192.         EnqueueAsyncBuffers();
  1193. ProcessPendingRead();
  1194.     }
  1195.     /* If there is still a pending read and no outstanding reads
  1196.      * issue one more read
  1197.      */
  1198.     if(m_bReadPending && mOutStandingCallbacks == 0)
  1199.     {
  1200.         DEBUGSTR("pm_bReadPending && mOutStandingCallbacks == 0;g");
  1201. ReadAsyncData(TRUE);
  1202.     }
  1203.     m_pMutex->Unlock();
  1204. }
  1205. void
  1206. CMacAsyncFile::ProcessPendingRead()
  1207. {
  1208.     AddRef();
  1209.     m_pMutex->Lock();
  1210.     
  1211.     ULONG32 totalinqueue = mReadQueue->GetQueuedItemCount();
  1212.     ULONG32 numberInPendingCallbackList = m_pPendingCallbackList->GetCount();
  1213.     if(m_bReadPending &&
  1214.        ((m_bFileDone && numberInPendingCallbackList == 0) ||
  1215.        (totalinqueue >= m_ulPendingReadCount)))
  1216.     {
  1217. m_bReadPending = FALSE;
  1218. if (totalinqueue == 0)
  1219. {
  1220.        DEBUGSTR("p AsyncReadDone FAIL;g");
  1221.       m_pResponse->AsyncReadDone(HXR_FAIL, NULL);
  1222. }
  1223. else
  1224. {
  1225.         UINT32 count = m_ulPendingReadCount;
  1226.     if (count > totalinqueue)
  1227.     {
  1228. count = totalinqueue;
  1229.     }
  1230.     IHXBuffer *pBuffer = new CHXBuffer;
  1231.     pBuffer->AddRef();
  1232.     pBuffer->SetSize(count);
  1233.     char *buf = (char*) pBuffer->GetBuffer();
  1234.     mFilePos += mReadQueue->DeQueue(buf, count);
  1235.     
  1236. #if defined(_DEBUG) && defined (_LOG_DATA)
  1237.        char str[255]; /* Flawfinder: ignore */
  1238.        ::sprintf(str, "AsyncReadDone: HXR_OK: %d;g", (int) count); /* Flawfinder: ignore */
  1239.         DEBUGSTR(c2pstr(str));
  1240. #endif     
  1241.     m_pResponse->AsyncReadDone(HXR_OK, pBuffer);
  1242.     pBuffer->Release();
  1243. }
  1244.     }
  1245.     m_pMutex->Unlock();
  1246.     Release();
  1247. }
  1248. HX_RESULT
  1249. CMacAsyncFile::SetAsyncResponse(CMacAsyncFileResponse * pResponse)
  1250. {
  1251.     if(!pResponse)
  1252.     {
  1253. return HXR_UNEXPECTED;
  1254.     }
  1255.     m_pMutex->Lock();
  1256.     m_pResponse = pResponse;
  1257.     m_pMutex->Unlock();
  1258.     return HXR_OK;
  1259. }