Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

578 lines
18 KiB

/*++
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;
}