|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
rx_thrd.c
Abstract:
This module implements async. MR/MH page decoding in a separate thread.
Author:
Rafael Lisitsa (RafaelL) 14-Aug-1996
Revision History:
--*/ #define USE_DEBUG_CONTEXT DEBUG_CONTEXT_T30_MAIN
#include "prep.h"
#include "efaxcb.h"
#include "t30.h"
#include "hdlc.h"
#include "debug.h"
#include "tiff.h"
#include "..\..\..\tiff\src\fasttiff.h"
#include "glbproto.h"
#include "t30gl.h"
// 15 min.
#define WAIT_FOR_NEXT_STRIP_RX_TIMEOUT 900000
#define RET_NEXT_STRIP_RX_TIMEOUT 1
BOOL DecodeFaxPageAsync ( PThrdGlbl pTG, DWORD *RetFlags, char *InFileName );
DWORD PageAckThread(PThrdGlbl pTG) { DWORD RetCode = FALSE; DWORD RetFlags = 0; DWORD ThrdDoneRetCode; char InFileName[_MAX_FNAME];
DEBUG_FUNCTION_NAME(_T("PageAckThread")); //
// Set the appropriate PRTY for this thread
// I/O threads run at 15. TIFF - at 9...11
//
if (! SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_HIGHEST) ) { DebugPrintEx( DEBUG_ERR, "SetThreadPriority HIGHEST failed le=%x", GetLastError()); goto error_exit; }
// binary file has fixed name based on lineID; it is created and updated by T.30 RX I/O thread.
_fmemcpy (InFileName, gT30.TmpDirectory, gT30.dwLengthTmpDirectory); _fmemcpy (&InFileName[gT30.dwLengthTmpDirectory], pTG->TiffConvertThreadParams.lpszLineID, 8); sprintf (&InFileName[gT30.dwLengthTmpDirectory+8], ".RX");
do { RetFlags = 0;
ThrdDoneRetCode = DecodeFaxPageAsync ( pTG, &RetFlags, InFileName);
DebugPrintEx( DEBUG_MSG, "DecodeFaxPageAsync RetFlags=%d", RetFlags);
if ( RetFlags == RET_NEXT_STRIP_RX_TIMEOUT ) { DebugPrintEx( DEBUG_MSG, "TimeOut. Trying to delete file%s", InFileName); if (!DeleteFile(InFileName)) { DebugPrintEx( DEBUG_ERR, "Could not delete file %s, le = %x", InFileName, GetLastError()); } return (FALSE); }
// Signal that we finish process the page.
if (!SetEvent(pTG->ThrdDoneSignal)) { DebugPrintEx( DEBUG_ERR, "SetEvent(0x%lx) returns failure code: %ld", (ULONG_PTR)pTG->ThrdDoneSignal, (long) GetLastError()); RetCode = FALSE; goto error_exit; }
} while (! pTG->ReqTerminate); // Handle the next page
if (!DeleteFile(InFileName)) { DebugPrintEx( DEBUG_ERR, "Could not delete file %s, le = %x", InFileName, GetLastError()); } DebugPrintEx(DEBUG_MSG,"Terminated");
RetCode = TRUE;
error_exit:
pTG->AckTerminate = 1; pTG->fOkToResetAbortReqEvent = 1;
if (!SetEvent(pTG->ThrdAckTerminateSignal)) { DebugPrintEx( DEBUG_ERR, "SetEvent(0x%lx) returns failure code: %ld", (ULONG_PTR)pTG->ThrdAckTerminateSignal, (long) GetLastError()); RetCode = FALSE; }
DebugPrintEx(DEBUG_MSG,"PageAckThread EXITs");
return (RetCode); }
BOOL DecodeFaxPageAsync ( PThrdGlbl pTG, DWORD *RetFlags, char *InFileName ) { HANDLE InFileHandle; DWORD AllowedBadFaxLines = gT30.MaxErrorLinesPerPage; DWORD AllowedConsecBadLines = gT30.MaxConsecErrorLinesPerPage;
LPDWORD EndPtr; LPDWORD EndBuffer;
LPDWORD lpdwResPtr; LPDWORD lpdwRead; BYTE ResBit; BOOL fTestLength; BOOL fError;
BOOL fFirstRead;
LPDWORD lpBuffer=NULL; BOOL fLastReadBlockSync; // needs to be sync. fetched, updated by RX I/O thrd.
DWORD BytesReuse; DWORD BytesDelta; DWORD BytesToRead; DWORD BytesHaveRead;
BOOL f1D;
DWORD PageCount; DWORD NumHandles=2; HANDLE HandlesArray[2]; DWORD WaitResult; BOOL fRet=TRUE;
//
// At Start of Page
//
DEBUG_FUNCTION_NAME(_T("DecodeFaxPageAsync"));
HandlesArray[0] = pTG->AbortReqEvent; HandlesArray[1] = pTG->ThrdSignal;
pTG->fTiffThreadRunning = 0;
do { WaitResult = WaitForMultipleObjects(NumHandles, HandlesArray, FALSE, WAIT_FOR_NEXT_STRIP_RX_TIMEOUT);
if (WaitResult == WAIT_TIMEOUT) { *RetFlags = RET_NEXT_STRIP_RX_TIMEOUT; return FALSE; }
if (WaitResult == WAIT_FAILED) { DebugPrintEx( DEBUG_ERR, "WaitForMultipleObjects FAILED le=%lx", GetLastError()); }
if ( pTG->ReqTerminate || ( WaitResult == WAIT_OBJECT_0) ) { DebugPrintEx(DEBUG_MSG, "wait for next page ABORTED") ; pTG->fOkToResetAbortReqEvent = 1; return TRUE; }
} while (pTG->fPageIsBad); // pTG->fPageIsBad become FALSE when we call to RECV_STARTPAGE to get new page.
// The reason we wait for fPageIsBad: If the prev page was bad, we want to wait till clean-up was done.
pTG->fTiffThreadRunning = 1;
pTG->Lines = 0; pTG->BadFaxLines = 0; pTG->ConsecBadLines = 0; pTG->iResScan = 0;
PageCount = pTG->PageCount;
fLastReadBlockSync = pTG->fLastReadBlock;
DebugPrintEx( DEBUG_MSG, "waked up fLastReadBlockSync=%d", fLastReadBlockSync);
if ( ( InFileHandle = CreateFileA(InFileName, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL) ) == INVALID_HANDLE_VALUE ) { DebugPrintEx( DEBUG_ERR, "PAGE COULD NOT open %s", InFileName);
pTG->fPageIsBad = 1; return FALSE; }
fFirstRead = 1; pTG->BytesOut = 0;
lpBuffer = MemAlloc(DECODE_BUFFER_SIZE); if (!lpBuffer) { DebugPrintEx(DEBUG_ERR, "MemAlloc failed"); pTG->fPageIsBad = 1; goto bad_exit; }
// lpBuffer is DWORD aligned
lpdwResPtr = lpBuffer; ResBit = 0;
EndBuffer = lpBuffer + ( DECODE_BUFFER_SIZE / sizeof(DWORD) );
//
// loop thru all blocks
//
do { //
// Read the next RAW block prepared by main I/O thread
//
DWORD tiffCompression; BOOL HiRes; if (fFirstRead) { lpdwRead = lpBuffer; BytesReuse = 0; BytesToRead = DECODE_BUFFER_SIZE; fTestLength = DO_NOT_TEST_LENGTH; } else { BytesReuse = (DWORD)((EndBuffer - lpdwResPtr) * sizeof (DWORD)); CopyMemory( (char *) lpBuffer, (char *) lpdwResPtr, BytesReuse); lpdwRead = lpBuffer + (BytesReuse / sizeof (DWORD) ); BytesToRead = DECODE_BUFFER_SIZE - BytesReuse; fTestLength = DO_TEST_LENGTH; }
lpdwResPtr = lpBuffer;
BytesDelta = pTG->BytesIn - pTG->BytesOut;
if (BytesDelta < DECODE_BUFFER_SIZE) { if (! fLastReadBlockSync) { DebugPrintEx( DEBUG_ERR, "PAGE LOGIC. SYNC. file %s Bytes: IN:%d OUT:%d", InFileName, pTG->BytesIn, pTG->BytesOut);
pTG->fPageIsBad = 1; goto bad_exit; } }
if (fLastReadBlockSync) { if (BytesDelta < BytesToRead) { BytesToRead = BytesDelta; } }
if (! ReadFile(InFileHandle, lpdwRead, BytesToRead, &BytesHaveRead, NULL ) ) { DebugPrintEx( DEBUG_ERR, "PAGE COULD NOT READ file %s Bytes: IN:%d" " OUT:%d WANTED:%d LE=%x", InFileName, pTG->BytesIn, pTG->BytesOut, BytesToRead, GetLastError());
pTG->fPageIsBad = 1; goto bad_exit; }
if (BytesHaveRead != BytesToRead) { DebugPrintEx( DEBUG_ERR, "PAGE ReadFile count=%d WANTED=%d file %s" " Bytes: IN:%d OUT:%d", BytesHaveRead, BytesToRead, InFileName, pTG->BytesIn, pTG->BytesOut);
pTG->fPageIsBad = 1; goto bad_exit; }
if ( fLastReadBlockSync && (BytesToRead == BytesDelta) ) { EndPtr = lpBuffer + ( (BytesReuse + BytesToRead) / sizeof(DWORD) ); } else { //
// leave 1000*4 = 4000 bytes ahead if not final block to make sure
// we always have one full line ahead.
//
EndPtr = EndBuffer - 1000; }
pTG->BytesOut += BytesToRead;
DebugPrintEx( DEBUG_MSG, "BytesIn=%d Out=%d Read=%d ResBit=%d StartPtr=%lx" " EndPtr=%lx Reuse=%d", pTG->BytesIn, pTG->BytesOut, BytesToRead, ResBit, lpBuffer, EndPtr, BytesReuse);
//
// find first EOL
//
f1D = 1;
if (! FindNextEol (lpdwResPtr, ResBit, EndBuffer, &lpdwResPtr, &ResBit, fTestLength, &fError) ) { DebugPrintEx( DEBUG_ERR, "Couldn't find EOL fTestLength=%d fError=%d", fTestLength, fError); pTG->fPageIsBad = 1; goto bad_exit; }
//
// Scan the next segment
//
// if those settings change from one page to the other
// it has to be inside the loop, beause this thread
// gets all the pages and then dies
tiffCompression = pTG->TiffConvertThreadParams.tiffCompression; HiRes = pTG->TiffConvertThreadParams.HiRes; DebugPrintEx( DEBUG_MSG, "Calling %s with compression=%d and resolution=%d", (tiffCompression == TIFF_COMPRESSION_MR)?"ScanMrSegment":"ScanMhSegment", tiffCompression,HiRes); if (tiffCompression == TIFF_COMPRESSION_MR) { pTG->iResScan = ScanMrSegment(&lpdwResPtr, &ResBit, EndPtr, EndBuffer, &(pTG->Lines), &(pTG->BadFaxLines), &(pTG->ConsecBadLines), AllowedBadFaxLines, AllowedConsecBadLines, &f1D, pTG->TiffInfo.ImageWidth); } else { pTG->iResScan = ScanMhSegment(&lpdwResPtr, &ResBit, EndPtr, EndBuffer, &(pTG->Lines), &(pTG->BadFaxLines), &(pTG->ConsecBadLines), AllowedBadFaxLines, AllowedConsecBadLines, pTG->TiffInfo.ImageWidth); }
DebugPrintEx( DEBUG_MSG, "%s returned: ResScan=%d Lines=%d " "BadFaxLines=%d tAllowedBadFaxLines=%d " "ConsecBadLines=%d AllowedConsecBadLines=%d " "tpImageWidth=%d", (tiffCompression == TIFF_COMPRESSION_MR)?"ScanMrSegment":"ScanMhSegment", pTG->iResScan, pTG->Lines, pTG->BadFaxLines, AllowedBadFaxLines, pTG->ConsecBadLines, AllowedConsecBadLines, pTG->TiffInfo.ImageWidth);
if (pTG->iResScan == TIFF_SCAN_SUCCESS) { goto good_exit; } else if (pTG->iResScan == TIFF_SCAN_FAILURE) { DebugPrintEx( DEBUG_ERR, "ScanSegment returns TIFF_SCAN_FAILURE"); pTG->fPageIsBad = 1; goto bad_exit; } else if (pTG->iResScan != TIFF_SCAN_SEG_END) { DebugPrintEx( DEBUG_ERR, "ScanSegment returns INVALID %d", pTG->iResScan); pTG->fPageIsBad = 1; goto bad_exit; }
//lNextBlock:
// here we make decision as to whether to do the next segment OR to block (not enough data avail).
if (fLastReadBlockSync && (pTG->BytesOut == pTG->BytesIn) ) { //
// The class 2/2.0 standards say the modem is not supposed to include the RTC in the page data.
// So, for 2/2.0, finishing the page without finding RTC marks the page as good.
//
if ((pTG->ModemClass==MODEM_CLASS2) || (pTG->ModemClass==MODEM_CLASS2_0)) { DebugPrintEx(DEBUG_MSG, "Didn't find RTC, but we're on class 2/2.0, so page is good"); goto good_exit; }
DebugPrintEx( DEBUG_ERR, "Didn't find RTC Bad=%d ConsecBad=%d Good=%d", pTG->BadFaxLines, pTG->ConsecBadLines, pTG->Lines); pTG->fPageIsBad = 1; goto bad_exit; }
DebugPrintEx( DEBUG_MSG, "Done with next strip BytesIn=%d Out=%d" " Lines=%d Bad=%d ConsecBad=%d Processed %d bytes \n", pTG->BytesIn, pTG->BytesOut, pTG->Lines, pTG->BadFaxLines, pTG->ConsecBadLines, (lpdwResPtr - lpBuffer) * sizeof(DWORD));
fLastReadBlockSync = pTG->fLastReadBlock;
if ( (pTG->BytesIn - pTG->BytesOut < DECODE_BUFFER_SIZE) && (! fLastReadBlockSync) ) { DebugPrintEx(DEBUG_MSG,"Waiting for next strip to be avail.");
pTG->fTiffThreadRunning = 0;
WaitResult = WaitForMultipleObjects(NumHandles, HandlesArray, FALSE, WAIT_FOR_NEXT_STRIP_RX_TIMEOUT);
if (WaitResult == WAIT_TIMEOUT) { *RetFlags = RET_NEXT_STRIP_RX_TIMEOUT; goto bad_exit; }
if (WaitResult == WAIT_FAILED) { DebugPrintEx( DEBUG_ERR, "WaitForMultipleObjects FAILED le=%lx", GetLastError()); }
if ( pTG->ReqTerminate || ( WaitResult == WAIT_OBJECT_0) ) { DebugPrintEx(DEBUG_MSG,"wait for next page ABORTED") ; goto bad_exit; }
pTG->fTiffThreadRunning = 1;
fLastReadBlockSync = pTG->fLastReadBlock;
DebugPrintEx( DEBUG_MSG, "Waked up with next strip. fLastReadBlockSync=%d" " BytesIn=%d Out=%d", fLastReadBlockSync, pTG->BytesIn, pTG->BytesOut);
}
fFirstRead = 0;
} while ( ! pTG->ReqTerminate );
DebugPrintEx(DEBUG_ERR, "Got Terminate request"); pTG->fPageIsBad = 1; // fall through
bad_exit: fRet=FALSE; goto exit;
good_exit: fRet=TRUE; // fall through
exit: CloseHandle(InFileHandle); if (lpBuffer) { MemFree(lpBuffer); lpBuffer=NULL; } return fRet;
}
|