- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# asyncio.h

    00001 //------------------------------------------------------------------------------
    00002 // File: AsyncIo.h
    00003 //
    00004 // Desc: DirectShow sample code - base library for I/O functionality.
    00005 //
    00006 // Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
    00007 //------------------------------------------------------------------------------
    00008
    00009 #pragma once
    00010
    00011 //
    00012 // definition of CAsyncFile object that performs file access. It provides
    00013 // asynchronous, unbuffered, aligned reads from a file, using a worker thread
    00014 // on win95 and potentially overlapped i/o if available.
    00015
    00016 // !!! Need to use real overlapped i/o if available
    00017 // currently only uses worker thread, not overlapped i/o
    00018
    00019 class CAsyncIo;
    00020 class CAsyncStream;
    00021
    00022 //
    00023 //  Model the stream we read from based on a file-like interface
    00024 //
    00025 class CAsyncStream
    00026 {
    00027 public:
    00028     virtual ~CAsyncStream() {};
    00029     virtual HRESULT SetPointer(LONGLONG llPos) = 0;
    00030     virtual HRESULT Read(PBYTE pbBuffer,
    00031                          DWORD dwBytesToRead,
    00032                          BOOL bAlign,
    00033                          LPDWORD pdwBytesRead) = 0;
    00034     virtual LONGLONG Size(LONGLONG *pSizeAvailable = NULL) = 0;
    00035     virtual DWORD Alignment() = 0;
    00036     virtual void Lock() = 0;
    00037     virtual void Unlock() = 0;
    00038     //virtual void SetStopHandle(HANDLE hevStop) {}
    00039 };
    00040
    00041 // represents a single request and performs the i/o. Can be called on either
    00042 // worker thread or app thread, but must hold pcsFile across file accesses.
    00043 // (ie across SetFilePointer/ReadFile pairs)
    00044 class CAsyncRequest
    00045 {
    00046     CAsyncIo *m_pIo;
    00047     CAsyncStream *m_pStream;
    00048     LONGLONG      m_llPos;
    00049     BOOL        m_bAligned;
    00050     LONG        m_lLength;
    00051     BYTE*       m_pBuffer;
    00052     LPVOID      m_pContext;
    00053     DWORD       m_dwUser;
    00054     HRESULT     m_hr;
    00055
    00056 public:
    00057     // init the params for this request. Issue the i/o
    00058     // if overlapped i/o is possible.
    00059     HRESULT Request(
    00060         CAsyncIo *pIo,
    00061         CAsyncStream *pStream,
    00062         LONGLONG llPos,
    00063         LONG lLength,
    00064         BOOL bAligned,
    00065         BYTE* pBuffer,
    00066         LPVOID pContext,        // filter's context
    00067         DWORD dwUser);          // downstream filter's context
    00068
    00069     // issue the i/o if not overlapped, and block until i/o complete.
    00070     // returns error code of file i/o
    00071     HRESULT Complete();
    00072
    00073     // cancels the i/o. blocks until i/o is no longer pending
    00074     HRESULT Cancel()
    00075     {
    00076         return S_OK;
    00077     };
    00078
    00079     // accessor functions
    00080     LPVOID GetContext()
    00081     {
    00082         return m_pContext;
    00083     };
    00084
    00085     DWORD GetUser()
    00086     {
    00087         return m_dwUser;
    00088     };
    00089
    00090     HRESULT GetHResult() {
    00091         return m_hr;
    00092     };
    00093
    00094     // we set m_lLength to the actual length
    00095     LONG GetActualLength() {
    00096         return m_lLength;
    00097     };
    00098
    00099     LONGLONG GetStart() {
    00100         return m_llPos;
    00101     };
    00102 };
    00103
    00104
    00105 typedef CGenericList<CAsyncRequest> CRequestList;
    00106
    00107 // this class needs a worker thread, but the ones defined in classes\base
    00108 // are not suitable (they assume you have one message sent or posted per
    00109 // request, whereas here for efficiency we want just to set an event when
    00110 // there is work on the queue).
    00111 //
    00112 // we create CAsyncRequest objects and queue them on m_listWork. The worker
    00113 // thread pulls them off, completes them and puts them on m_listDone.
    00114 // The events m_evWork and m_evDone are set when the corresponding lists are
    00115 // not empty.
    00116 //
    00117 // Synchronous requests are done on the caller thread. These should be
    00118 // synchronised by the caller, but to make sure we hold m_csFile across
    00119 // the SetFilePointer/ReadFile code.
    00120 //
    00121 // Flush by calling BeginFlush. This rejects all further requests (by
    00122 // setting m_bFlushing within m_csLists), cancels all requests and moves them
    00123 // to the done list, and sets m_evDone to ensure that no WaitForNext operations
    00124 // will block. Call EndFlush to cancel this state.
    00125 //
    00126 // we support unaligned calls to SyncRead. This is done by opening the file
    00127 // twice if we are using unbuffered i/o (m_dwAlign > 1).
    00128 // !!!fix this to buffer on top of existing file handle?
    00129 class CAsyncIo
    00130 {
    00131
    00132     CCritSec m_csReader;
    00133     CAsyncStream *m_pStream;
    00134
    00135     CCritSec m_csLists;      // locks access to the list and events
    00136     BOOL m_bFlushing;        // true if between BeginFlush/EndFlush
    00137     CRequestList m_listWork;
    00138     CRequestList m_listDone;
    00139     CAMEvent m_evWork;         // set when list is not empty
    00140     CAMEvent m_evDone;
    00141
    00142     // for correct flush behaviour: all protected by m_csLists
    00143     LONG    m_cItemsOut;    // nr of items not on listDone or listWork
    00144     BOOL    m_bWaiting;     // TRUE if someone waiting for m_evAllDone
    00145     CAMEvent m_evAllDone;   // signal when m_cItemsOut goes to 0 if m_cWaiting
    00146
    00147
    00148     CAMEvent m_evStop;         // set when thread should exit
    00149     HANDLE m_hThread;
    00150
    00151     LONGLONG Size() {
    00152         ASSERT(m_pStream != NULL);
    00153         return m_pStream->Size();
    00154     };
    00155
    00156     // start the thread
    00157     HRESULT StartThread(void);
    00158
    00159     // stop the thread and close the handle
    00160     HRESULT CloseThread(void);
    00161
    00162     // manage the list of requests. hold m_csLists and ensure
    00163     // that the (manual reset) event hevList is set when things on
    00164     // the list but reset when the list is empty.
    00165     // returns null if list empty
    00166     CAsyncRequest* GetWorkItem();
    00167
    00168     // get an item from the done list
    00169     CAsyncRequest* GetDoneItem();
    00170
    00171     // put an item on the work list
    00172     HRESULT PutWorkItem(CAsyncRequest* pRequest);
    00173
    00174     // put an item on the done list
    00175     HRESULT PutDoneItem(CAsyncRequest* pRequest);
    00176
    00177     // called on thread to process any active requests
    00178     void ProcessRequests(void);
    00179
    00180     // initial static thread proc calls ThreadProc with DWORD
    00181     // param as this
    00182     static DWORD WINAPI InitialThreadProc(LPVOID pv) {
    00183         CAsyncIo * pThis = (CAsyncIo*) pv;
    00184         return pThis->ThreadProc();
    00185     };
    00186
    00187     DWORD ThreadProc(void);
    00188
    00189 public:
    00190
    00191     CAsyncIo(CAsyncStream *pStream);
    00192     ~CAsyncIo();
    00193
    00194     // open the file
    00195     HRESULT Open(LPCTSTR pName);
    00196
    00197     // ready for async activity - call this before
    00198     // calling Request
    00199     HRESULT AsyncActive(void);
    00200
    00201     // call this when no more async activity will happen before
    00202     // the next AsyncActive call
    00203     HRESULT AsyncInactive(void);
    00204
    00205     // queue a requested read. must be aligned.
    00206     HRESULT Request(
    00207                 LONGLONG llPos,
    00208                 LONG lLength,
    00209                 BOOL bAligned,
    00210                 BYTE* pBuffer,
    00211                 LPVOID pContext,
    00212                 DWORD dwUser);
    00213
    00214     // wait for the next read to complete
    00215     HRESULT WaitForNext(
    00216                 DWORD dwTimeout,
    00217                 LPVOID *ppContext,
    00218                 DWORD * pdwUser,
    00219                 LONG * pcbActual
    00220                 );
    00221
    00222     // perform a read of an already aligned buffer
    00223     HRESULT SyncReadAligned(
    00224                 LONGLONG llPos,
    00225                 LONG lLength,
    00226                 BYTE* pBuffer,
    00227                 LONG* pcbActual,
    00228                 PVOID pvContext
    00229                 );
    00230
    00231     // perform a synchronous read. will be buffered
    00232     // if not aligned.
    00233     HRESULT SyncRead(
    00234                 LONGLONG llPos,
    00235                 LONG lLength,
    00236                 BYTE* pBuffer);
    00237
    00238     // return length
    00239     HRESULT Length(LONGLONG *pllTotal, LONGLONG* pllAvailable);
    00240
    00241     // all Reader positions, read lengths and memory locations must
    00242     // be aligned to this.
    00243     HRESULT Alignment(LONG* pl);
    00244
    00245     HRESULT BeginFlush();
    00246     HRESULT EndFlush();
    00247
    00248     LONG Alignment()
    00249     {
    00250         return m_pStream->Alignment();
    00251     };
    00252
    00253     BOOL IsAligned(LONG l) {
    00254         if ((l & (Alignment() -1)) == 0) {
    00255             return TRUE;
    00256         } else {
    00257             return FALSE;
    00258         }
    00259     };
    00260
    00261     BOOL IsAligned(LONGLONG ll) {
    00262         return IsAligned( (LONG) (ll & 0xffffffff));
    00263     };
    00264
    00265     //  Accessor
    00266     HANDLE StopEvent() const { return m_evDone; }
    00267 };