Ejemplo n.º 1
0
// perform a synchronous read request on this thread.
// may not be aligned - so we will have to buffer.
HRESULT
CAsyncIo::SyncRead(
                LONGLONG llPos,
                LONG lLength,
                BYTE * pBuffer)
{
    if(IsAligned(llPos) &&
        IsAligned(lLength) &&
        IsAligned((LONG_PTR) pBuffer))
    {
        LONG cbUnused;
        return SyncReadAligned(llPos, lLength, pBuffer, &cbUnused, NULL);
    }

    // not aligned with requirements - use buffered file handle.
    //!!! might want to fix this to buffer the data ourselves?

    CAsyncRequest request;

    HRESULT hr = request.Request(this,
                                m_pStream,
                                llPos,
                                lLength,
                                FALSE,
                                pBuffer,
                                NULL,
                                0);

    if(FAILED(hr))
    {
        return hr;
    }

    return request.Complete();
}
Ejemplo n.º 2
0
HRESULT
CAsyncIo::SyncRead(
            LONGLONG llPos,
            LONG lLength,
            BYTE* pBuffer)
{
    if (IsAligned(llPos) &&
	IsAligned(lLength) &&
	IsAligned((LONG) pBuffer)) {
            LONG cbUnused;
	    return SyncReadAligned(llPos, lLength, pBuffer, &cbUnused, NULL);
    }

    
    

    CAsyncRequest request;

    HRESULT hr = request.Request(
                    this,
                    m_pStream,
                    llPos,
                    lLength,
                    FALSE,
                    pBuffer,
                    NULL,
                    0);

    if (FAILED(hr)) {
        return hr;
    }

    return request.Complete();
}
Ejemplo n.º 3
0
// add a request to the queue.
HRESULT
  CAsyncIo::Request(
  LONGLONG llPos,
  LONG lLength,
  BOOL bAligned,
  BYTE * pBuffer,
  LPVOID pContext,
  DWORD_PTR dwUser)
{
  if(bAligned)
  {
    if(!IsAligned(llPos) ||
      !IsAligned(lLength) ||
      !IsAligned((LONG_PTR) pBuffer))
    {
      return VFW_E_BADALIGN;
    }
  }

  CAsyncRequest* pRequest = new CAsyncRequest;
  if (!pRequest)
    return E_OUTOFMEMORY;

  HRESULT hr = pRequest->Request(this,
    m_pStream,
    llPos,
    lLength,
    bAligned,
    pBuffer,
    pContext,
    dwUser);
  if(SUCCEEDED(hr))
  {
    // might fail if flushing
    hr = PutWorkItem(pRequest);
  }

  if(FAILED(hr))
  {
    delete pRequest;
  }

  return hr;
}
Ejemplo n.º 4
0
// called on thread to process any active requests
void
  CAsyncIo::ProcessRequests(void)
{
  // lock to get the item and increment the outstanding count
  CAsyncRequest * preq = NULL;

  for(;;)
  {
    {
      CAutoLock lock(&m_csLists);

      preq = GetWorkItem();
      if(preq == NULL)
      {
        // done
        return;
      }

      // one more item not on the done or work list
      m_cItemsOut++;

      // release critsec
    }

    preq->Complete();

    // regain critsec to replace on done list
    {
      CAutoLock l(&m_csLists);

      PutDoneItem(preq);

      if(--m_cItemsOut == 0)
      {
        if(m_bWaiting)
          m_evAllDone.Set();
      }
    }
  }
}
Ejemplo n.º 5
0
// perform a synchronous read request on this thread.
// Need to hold m_csFile while doing this (done in request object)
HRESULT
  CAsyncIo::SyncReadAligned(
  LONGLONG llPos,
  LONG lLength,
  BYTE * pBuffer,
  LONG * pcbActual,
  PVOID pvContext)
{
  CheckPointer(pcbActual,E_POINTER);

  if(!IsAligned(llPos) ||
    !IsAligned(lLength) ||
    !IsAligned((LONG_PTR) pBuffer))
  {
    return VFW_E_BADALIGN;
  }

  CAsyncRequest request;

  m_pStream->Lock();

  HRESULT hr = request.Request(this,
    m_pStream,
    llPos,
    lLength,
    TRUE,
    pBuffer,
    pvContext,
    0);
  if(SUCCEEDED(hr))
  {
    hr = request.Complete();
  }

  m_pStream->Unlock();

  // return actual data length
  *pcbActual = request.GetActualLength();
  return hr;
}
Ejemplo n.º 6
0
void
CAsyncIo::ProcessRequests(void)
{
    
    CAsyncRequest * preq = NULL;
    for (;;) {
        {
            CAutoLock lock(&m_csLists);

            preq = GetWorkItem();
            if (preq == NULL) {
                
                return;
            }

            
            m_cItemsOut++;

            
        }

        preq->Complete();

        
        {
            CAutoLock l(&m_csLists);

            PutDoneItem(preq);

            if (--m_cItemsOut == 0) {
                if (m_bWaiting) {
                    m_evAllDone.Set();
                }
            }
        }
    }
}
Ejemplo n.º 7
0
HRESULT
CAsyncIo::SyncReadAligned(
            LONGLONG llPos,
            LONG lLength,
            BYTE* pBuffer,
            LONG* pcbActual,
            PVOID pvContext
            )
{
    if (!IsAligned(llPos) ||
	!IsAligned(lLength) ||
	!IsAligned((LONG) pBuffer)) {
            return VFW_E_BADALIGN;
    }

    CAsyncRequest request;

    HRESULT hr = request.Request(
                    this,
                    m_pStream,
                    llPos,
                    lLength,
                    TRUE,
                    pBuffer,
                    pvContext,
                    0);

    if (FAILED(hr)) {
        return hr;
    }

    hr = request.Complete();

    
    *pcbActual = request.GetActualLength();
    return hr;
}
Ejemplo n.º 8
0
HRESULT
CAsyncIo::BeginFlush()
{
    
    {
        CAutoLock lock(&m_csLists);

        
        
        
        
        m_bFlushing = TRUE;

        CAsyncRequest * preq;
        while(preq = GetWorkItem()) {
            preq->Cancel();
            PutDoneItem(preq);
        }

        
        if (m_cItemsOut > 0) {

            
            ASSERT(!m_bWaiting);

            
            
            
            m_bWaiting = TRUE;
        } else {
            

            
            
            
            
            m_evDone.Set();
            return S_OK;
        }
    }

    ASSERT(m_bWaiting);

    
    for (;;) {
        m_evAllDone.Wait();
        {
            
            CAutoLock lock(&m_csLists);

            if (m_cItemsOut == 0) {

                
                
                m_bWaiting = FALSE;

                
                
                
                
                m_evDone.Set();

                return S_OK;
            }
        }
    }
}
Ejemplo n.º 9
0
HRESULT
CAsyncIo::WaitForNext(
    DWORD dwTimeout,
    LPVOID *ppContext,
    DWORD * pdwUser,
    LONG* pcbActual)
{
    
    
    *ppContext = NULL;

    
    
    for (;;) {

        if (!m_evDone.Wait(dwTimeout)) {
            
            return VFW_E_TIMEOUT;
        }

        
        CAsyncRequest* pRequest = GetDoneItem();
        if (pRequest) {
            

            
            HRESULT hr = pRequest->GetHResult();
            if (hr == S_FALSE) {

                
                
                if ((pRequest->GetActualLength() +
                     pRequest->GetStart()) == Size()) {
                        hr = S_OK;
                } else {
                    
                    hr = E_FAIL;
                }
            }

            
            *pcbActual = pRequest->GetActualLength();

            
            *ppContext = pRequest->GetContext();
            *pdwUser = pRequest->GetUser();
            delete pRequest;
            return hr;
        } else {
            
            
            CAutoLock lck(&m_csLists);
            if (m_bFlushing && !m_bWaiting) {

                

                
                

                return VFW_E_WRONG_STATE;
            }
        }

        
        
    }
}
Ejemplo n.º 10
0
// cancel all items on the worklist onto the done list
// and refuse further requests or further WaitForNext calls
// until the end flush
//
// WaitForNext must return with NULL only if there are no successful requests.
// So Flush does the following:
// 1. set m_bFlushing ensures no more requests succeed
// 2. move all items from work list to the done list.
// 3. If there are any outstanding requests, then we need to release the
//    critsec to allow them to complete. The m_bWaiting as well as ensuring
//    that we are signalled when they are all done is also used to indicate
//    to WaitForNext that it should continue to block.
// 4. Once all outstanding requests are complete, we force m_evDone set and
//    m_bFlushing set and m_bWaiting false. This ensures that WaitForNext will
//    not block when the done list is empty.
HRESULT
  CAsyncIo::BeginFlush()
{
  // hold the lock while emptying the work list
  {
    CAutoLock lock(&m_csLists);

    // prevent further requests being queued.
    // Also WaitForNext will refuse to block if this is set
    // unless m_bWaiting is also set which it will be when we release
    // the critsec if there are any outstanding).
    m_bFlushing = TRUE;

    CAsyncRequest * preq;
    while((preq = GetWorkItem()) != 0)
    {
      preq->Cancel();
      PutDoneItem(preq);
    }

    // now wait for any outstanding requests to complete
    if(m_cItemsOut > 0)
    {
      // can be only one person waiting
      ASSERT(!m_bWaiting);

      // this tells the completion routine that we need to be
      // signalled via m_evAllDone when all outstanding items are
      // done. It also tells WaitForNext to continue blocking.
      m_bWaiting = TRUE;
    }
    else
    {
      // all done

      // force m_evDone set so that even if list is empty,
      // WaitForNext will not block
      // don't do this until we are sure that all
      // requests are on the done list.
      m_evDone.Set();
      return S_OK;
    }
  }

  ASSERT(m_bWaiting);

  // wait without holding critsec
  for(;;)
  {
    m_evAllDone.Wait();
    {
      // hold critsec to check
      CAutoLock lock(&m_csLists);

      if(m_cItemsOut == 0)
      {
        // now we are sure that all outstanding requests are on
        // the done list and no more will be accepted
        m_bWaiting = FALSE;

        // force m_evDone set so that even if list is empty,
        // WaitForNext will not block
        // don't do this until we are sure that all
        // requests are on the done list.
        m_evDone.Set();

        return S_OK;
      }
    }
  }
}
Ejemplo n.º 11
0
// wait for the next request to complete
HRESULT
  CAsyncIo::WaitForNext(
  DWORD dwTimeout,
  LPVOID     * ppContext,
  DWORD_PTR  * pdwUser,
  LONG       * pcbActual)
{
  CheckPointer(ppContext,E_POINTER);
  CheckPointer(pdwUser,E_POINTER);
  CheckPointer(pcbActual,E_POINTER);

  // some errors find a sample, others don't. Ensure that
  // *ppContext is NULL if no sample found
  *ppContext = NULL;

  // wait until the event is set, but since we are not
  // holding the critsec when waiting, we may need to re-wait
  for(;;)
  {
    if(!m_evDone.Wait(dwTimeout))
    {
      // timeout occurred
      return VFW_E_TIMEOUT;
    }

    // get next event from list
    CAsyncRequest* pRequest = GetDoneItem();
    if(pRequest)
    {
      // found a completed request

      // check if ok
      HRESULT hr = pRequest->GetHResult();
      if(hr == S_FALSE)
      {
        LONGLONG llBytesToRead = 0, llAvailable = 0;

        hr = m_pStream->Length(&llBytesToRead, &llAvailable);

        if (SUCCEEDED(hr) &&
          (pRequest->GetActualLength() + pRequest->GetStart() == llBytesToRead))
        {
          // this means the actual length was less than
          // requested - may be ok if he aligned the end of file
          hr = S_OK;
        }
        else
        {
          // it was an actual read error
          hr = E_FAIL;
        }
      }

      // return actual bytes read
      *pcbActual = pRequest->GetActualLength();

      // return his context
      *ppContext = pRequest->GetContext();
      *pdwUser = pRequest->GetUser();

      delete pRequest;
      return hr;
    }
    else
    {
      //  Hold the critical section while checking the list state
      CAutoLock lck(&m_csLists);
      if(m_bFlushing && !m_bWaiting)
      {
        // can't block as we are between BeginFlush and EndFlush

        // but note that if m_bWaiting is set, then there are some
        // items not yet complete that we should block for.

        return VFW_E_WRONG_STATE;
      }
    }

    // done item was grabbed between completion and
    // us locking m_csLists.
  }
}