www.pudn.com > VideoMonitor.rar > asyncio.h


//==========================================================================; 
// 
//  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
//  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
//  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR 
//  PURPOSE. 
// 
//  Copyright (c) 1992 - 1997  Microsoft Corporation.  All Rights Reserved. 
// 
//--------------------------------------------------------------------------; 
 
#ifndef __ASYNCIO_H__ 
#define __ASYNCIO_H__ 
// 
// definition of CAsyncFile object that performs file access. It provides 
// asynchronous, unbuffered, aligned reads from a file, using a worker thread 
// on win95 and potentially overlapped i/o if available. 
 
// !!! Need to use real overlapped i/o if available 
// currently only uses worker thread, not overlapped i/o 
 
 
class CAsyncIo; 
class CAsyncStream; 
 
// 
//  Model the stream we read from based on a file-like interface 
// 
class CAsyncStream 
{ 
public: 
    virtual ~CAsyncStream() {}; 
    virtual HRESULT SetPointer(LONGLONG llPos) = 0; 
    virtual HRESULT Read(PBYTE pbBuffer, 
                         DWORD dwBytesToRead, 
                         BOOL bAlign, 
                         LPDWORD pdwBytesRead) = 0; 
    virtual LONGLONG Size(LONGLONG *pSizeAvailable = NULL) = 0; 
    virtual DWORD Alignment() = 0; 
    virtual void Lock() = 0; 
    virtual void Unlock() = 0; 
}; 
 
// represents a single request and performs the i/o. Can be called on either 
// worker thread or app thread, but must hold pcsFile across file accesses. 
// (ie across SetFilePointer/ReadFile pairs) 
class CAsyncRequest 
{ 
    CAsyncIo *m_pIo; 
    CAsyncStream *m_pStream; 
    LONGLONG      m_llPos; 
    BOOL        m_bAligned; 
    LONG 	m_lLength; 
    BYTE* 	m_pBuffer; 
    LPVOID 	m_pContext; 
    DWORD	m_dwUser; 
    HRESULT     m_hr; 
 
public: 
    // init the params for this request. Issue the i/o 
    // if overlapped i/o is possible. 
    HRESULT Request( 
    	CAsyncIo *pIo, 
        CAsyncStream *pStream, 
    	LONGLONG llPos, 
	LONG lLength, 
        BOOL bAligned, 
	BYTE* pBuffer, 
	LPVOID pContext,	// filter's context 
	DWORD dwUser);		// downstream filter's context 
 
    // issue the i/o if not overlapped, and block until i/o complete. 
    // returns error code of file i/o 
    HRESULT Complete(); 
 
    // cancels the i/o. blocks until i/o is no longer pending 
    HRESULT Cancel() 
    { 
	return S_OK; 
    }; 
 
    // accessor functions 
    LPVOID GetContext() 
    { 
    	return m_pContext; 
    }; 
 
    DWORD GetUser() 
    { 
	return m_dwUser; 
    }; 
 
    HRESULT GetHResult() { 
        return m_hr; 
    }; 
 
    // we set m_lLength to the actual length 
    LONG GetActualLength() { 
        return m_lLength; 
    }; 
 
    LONGLONG GetStart() { 
        return m_llPos; 
    }; 
}; 
 
 
typedef CGenericList CRequestList; 
 
// this class needs a worker thread, but the ones defined in classes\base 
// are not suitable (they assume you have one message sent or posted per 
// request, whereas here for efficiency we want just to set an event when 
// there is work on the queue). 
// 
// we create CAsyncRequest objects and queue them on m_listWork. The worker 
// thread pulls them off, completes them and puts them on m_listDone. 
// The events m_evWork and m_evDone are set when the corresponding lists are 
// not empty. 
// 
// Synchronous requests are done on the caller thread. These should be 
// synchronised by the caller, but to make sure we hold m_csFile across 
// the SetFilePointer/ReadFile code. 
// 
// Flush by calling BeginFlush. This rejects all further requests (by 
// setting m_bFlushing within m_csLists), cancels all requests and moves them 
// to the done list, and sets m_evDone to ensure that no WaitForNext operations 
// will block. Call EndFlush to cancel this state. 
// 
// we support unaligned calls to SyncRead. This is done by opening the file 
// twice if we are using unbuffered i/o (m_dwAlign > 1). 
// !!!fix this to buffer on top of existing file handle? 
class CAsyncIo 
{ 
 
    CCritSec m_csReader; 
    CAsyncStream *m_pStream; 
 
    CCritSec m_csLists;      // locks access to the list and events 
    BOOL m_bFlushing;        // true if between BeginFlush/EndFlush 
    CRequestList m_listWork; 
    CRequestList m_listDone; 
    CAMEvent m_evWork;         // set when list is not empty 
    CAMEvent m_evDone; 
 
    // for correct flush behaviour: all protected by m_csLists 
    LONG    m_cItemsOut;    // nr of items not on listDone or listWork 
    BOOL    m_bWaiting;     // TRUE if someone waiting for m_evAllDone 
    CAMEvent m_evAllDone;   // signal when m_cItemsOut goes to 0 if m_cWaiting 
 
 
    CAMEvent m_evStop;         // set when thread should exit 
    HANDLE m_hThread; 
 
    LONGLONG Size() { 
        ASSERT(m_pStream != NULL); 
        return m_pStream->Size(); 
    }; 
 
    // start the thread 
    HRESULT StartThread(void); 
 
    // stop the thread and close the handle 
    HRESULT CloseThread(void); 
 
    // manage the list of requests. hold m_csLists and ensure 
    // that the (manual reset) event hevList is set when things on 
    // the list but reset when the list is empty. 
    // returns null if list empty 
    CAsyncRequest* GetWorkItem(); 
 
    // get an item from the done list 
    CAsyncRequest* GetDoneItem(); 
 
    // put an item on the work list 
    HRESULT PutWorkItem(CAsyncRequest* pRequest); 
 
    // put an item on the done list 
    HRESULT PutDoneItem(CAsyncRequest* pRequest); 
 
    // called on thread to process any active requests 
    void ProcessRequests(void); 
 
    // initial static thread proc calls ThreadProc with DWORD 
    // param as this 
    static DWORD InitialThreadProc(LPVOID pv) { 
	CAsyncIo * pThis = (CAsyncIo*) pv; 
	return pThis->ThreadProc(); 
    }; 
 
    DWORD ThreadProc(void); 
 
public: 
 
    CAsyncIo(CAsyncStream *pStream); 
    ~CAsyncIo(); 
 
    // open the file 
    HRESULT Open(LPCTSTR pName); 
 
    // ready for async activity - call this before 
    // calling Request 
    HRESULT AsyncActive(void); 
 
    // call this when no more async activity will happen before 
    // the next AsyncActive call 
    HRESULT AsyncInactive(void); 
 
    // queue a requested read. must be aligned. 
    HRESULT Request( 
	    	LONGLONG llPos, 
		LONG lLength, 
                BOOL bAligned, 
		BYTE* pBuffer, 
		LPVOID pContext, 
		DWORD dwUser); 
 
    // wait for the next read to complete 
    HRESULT WaitForNext( 
	    	DWORD dwTimeout, 
		LPVOID *ppContext, 
		DWORD * pdwUser, 
                LONG * pcbActual 
                ); 
 
    // perform a read of an already aligned buffer 
    HRESULT SyncReadAligned( 
	    	LONGLONG llPos, 
		LONG lLength, 
		BYTE* pBuffer, 
                LONG* pcbActual 
                ); 
 
    // perform a synchronous read. will be buffered 
    // if not aligned. 
    HRESULT SyncRead( 
                LONGLONG llPos, 
                LONG lLength, 
                BYTE* pBuffer); 
 
    // return length 
    HRESULT Length(LONGLONG *pllTotal, LONGLONG* pllAvailable); 
 
    // all Reader positions, read lengths and memory locations must 
    // be aligned to this. 
    HRESULT Alignment(LONG* pl); 
 
    HRESULT BeginFlush(); 
    HRESULT EndFlush(); 
 
    LONG Alignment() 
    { 
        return m_pStream->Alignment(); 
    }; 
 
    BOOL IsAligned(LONG l) { 
	if ((l & (Alignment() -1)) == 0) { 
	    return TRUE; 
	} else { 
	    return FALSE; 
	} 
    }; 
 
    BOOL IsAligned(LONGLONG ll) { 
	return IsAligned( (LONG) (ll & 0xffffffff)); 
    }; 
}; 
 
#endif // __ASYNCIO_H__