windows-nt/Source/XPSP1/NT/termsrv/admtools/winutils/tscfg/threads.cpp

672 lines
16 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//Copyright (c) 1998 - 1999 Microsoft Corporation
/*******************************************************************************
*
* threads.cpp
*
* implementation of WINCFG thread classes
*
* copyright notice: Copyright 1994, Citrix Systems Inc.
*
* $Author: butchd $ Butch Davis
*
* $Log: N:\NT\PRIVATE\UTILS\CITRIX\WINUTILS\WINCFG\VCS\THREADS.CPP $
*
* Rev 1.18 19 Sep 1996 15:58:52 butchd
* update
*
* Rev 1.17 12 Sep 1996 16:16:44 butchd
* update
*
*******************************************************************************/
/*
* include files
*/
#include "stdafx.h"
#include "wincfg.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
extern CWincfgApp *pApp;
////////////////////////////////////////////////////////////////////////////////
// CThread class construction / destruction, implementation
/*******************************************************************************
*
* CThread - CThread constructor
*
* ENTRY:
* EXIT:
*
******************************************************************************/
CThread::CThread()
{
m_hThread = NULL;
m_dwThreadID = 0;
} // end CThread::CThread
/*******************************************************************************
*
* ~CThread - CThread destructor
*
* ENTRY:
* EXIT:
*
******************************************************************************/
CThread::~CThread()
{
} // end CThread::~CThread
/*******************************************************************************
*
* operator new - CThread operator override
*
* ENTRY:
* EXIT:
*
******************************************************************************/
void *
CThread::operator new(size_t nSize)
{
return( ::malloc(nSize) );
} // end CThread::operator new
/*******************************************************************************
*
* operator delete - CThread operator override
*
* ENTRY:
* EXIT:
*
******************************************************************************/
void
CThread::operator delete(void *p)
{
::free(p);
} // end CThread::operator delete
////////////////////////////////////////////////////////////////////////////////
// CThread operations: primary thread
/*******************************************************************************
*
* CreateThread - CThread implementation function
*
* Class wrapper for the Win32 CreateThread API.
*
* ENTRY:
* EXIT:
*
******************************************************************************/
HANDLE
CThread::CreateThread( DWORD cbStack,
DWORD fdwCreate )
{
/*
* Simple wrapper for Win32 CreateThread API.
*/
return( m_hThread = ::CreateThread( NULL, cbStack, ThreadEntryPoint,
(LPVOID)this, fdwCreate, &m_dwThreadID ) );
} // end CThread::CreateThread
////////////////////////////////////////////////////////////////////////////////
// CThread operations: secondary thread
/*******************************************************************************
*
* ThreadEntryPoint - CThread implementation function
* (SECONDARY THREAD)
*
* ENTRY:
* EXIT:
*
******************************************************************************/
DWORD __stdcall
CThread::ThreadEntryPoint(LPVOID lpParam)
{
CThread *pThread;
DWORD dwResult;
/*
* (lpParam is actually the 'this' pointer)
*/
pThread = (CThread*)lpParam;
VERIFY(pThread != NULL);
/*
* Run the thread.
*/
dwResult = pThread->RunThread();
/*
* Return the result.
*/
return(dwResult);
} // end CThread::ThreadEntryPoint
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// CATDlgInputThread class construction / destruction, implementation
/*******************************************************************************
*
* CATDlgInputThread - CATDlgInputThread constructor
*
* ENTRY:
* EXIT:
*
******************************************************************************/
CATDlgInputThread::CATDlgInputThread()
{
/*
* Initialize member variables.
*/
m_bExit = FALSE;
m_ErrorStatus = ERROR_SUCCESS;
m_hConsumed = m_OverlapSignal.hEvent = m_OverlapRead.hEvent = NULL;
} // end CATDlgInputThread::CATDlgInputThread
/*******************************************************************************
*
* ~CATDlgInputThread - CATDlgInputThread destructor
*
* ENTRY:
* EXIT:
*
******************************************************************************/
CATDlgInputThread::~CATDlgInputThread()
{
/*
* Close the semaphore and events when the CATDlgInputThread
* object is destroyed.
*/
if ( m_hConsumed )
CloseHandle(m_hConsumed);
if ( m_OverlapRead.hEvent )
CloseHandle(m_OverlapRead.hEvent);
if ( m_OverlapSignal.hEvent )
CloseHandle(m_OverlapSignal.hEvent);
} // end CATDlgInputThread::~CATDlgInputThread
/*******************************************************************************
*
* RunThread - CATDlgInputThread secondary thread main function loop
* (SECONDARY THREAD)
*
* ENTRY:
* EXIT:
* (DWORD) exit status for the secondary thread.
*
******************************************************************************/
DWORD
CATDlgInputThread::RunThread()
{
HANDLE hWait[2];
DWORD Status;
int iStat;
/*
* Initialize for overlapped status and read input.
*/
if ( !(m_hConsumed = CreateSemaphore( NULL, 0,
MAX_STATUS_SEMAPHORE_COUNT,
NULL )) ||
!(m_OverlapRead.hEvent = CreateEvent( NULL, TRUE,
FALSE, NULL )) ||
!(m_OverlapSignal.hEvent = CreateEvent( NULL, TRUE,
FALSE, NULL )) ||
!SetCommMask( m_hDevice,
EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD | EV_BREAK ) ) {
NotifyAbort(IDP_ERROR_CANT_INITIALIZE_INPUT_THREAD);
return(1);
}
/*
* Query initial comm status to initialize dialog with (return if error).
*/
if ( (iStat = CommStatusAndNotify()) != -1 )
return(iStat);
/*
* Post Read for input data.
*/
if ( (iStat = PostInputRead()) != -1 )
return(iStat);
/*
* Post Read for status.
*/
if ( (iStat = PostStatusRead()) != -1 )
return(iStat);
/*
* Loop till exit requested.
*/
for ( ; ; ) {
/*
* Wait for either input data or an comm status event.
*/
hWait[0] = m_OverlapRead.hEvent;
hWait[1] = m_OverlapSignal.hEvent;
Status = WaitForMultipleObjects(2, hWait, FALSE, INFINITE);
/*
* Check for exit.
*/
if ( m_bExit )
return(0);
if ( Status == WAIT_OBJECT_0 ) {
/*
* Read event:
* Get result of overlapped read.
*/
if ( !GetOverlappedResult( m_hDevice,
&m_OverlapRead,
&m_BufferBytes,
TRUE ) ) {
NotifyAbort(IDP_ERROR_GET_OVERLAPPED_RESULT_READ);
return(1);
}
/*
* Notify dialog.
*/
if ( (iStat = CommInputNotify()) != -1 )
return(iStat);
/*
* Post Read for input data.
*/
if ( (iStat = PostInputRead()) != -1 )
return(iStat);
} else if ( Status == WAIT_OBJECT_0+1 ) {
/*
* Comm status event:
* Query comm status and notify dialog.
*/
if ( (iStat = CommStatusAndNotify()) != -1 )
return(iStat);
/*
* Post Read for status.
*/
if ( (iStat = PostStatusRead()) != -1 )
return(iStat);
} else {
/*
* Unknown event: Abort.
*/
NotifyAbort(IDP_ERROR_WAIT_FOR_MULTIPLE_OBJECTS);
return(1);
}
}
} // end CATDlgInputThread::RunThread
////////////////////////////////////////////////////////////////////////////////
// CATDlgInputThread operations: primary thread
/*******************************************************************************
*
* SignalConsumed - CATDlgInputThread member function: public operation
*
* Release the m_hConsumed semaphore to allow secondary thread to continue
* running.
*
* ENTRY:
* EXIT:
*
******************************************************************************/
void
CATDlgInputThread::SignalConsumed()
{
ReleaseSemaphore( m_hConsumed, 1, NULL );
} // end CATDlgInputThread::SignalConsumed
/*******************************************************************************
*
* ExitThread - CATDlgInputThread member function: public operation
*
* Tell the secondary thread to exit and cleanup after.
*
* ENTRY:
* EXIT:
*
******************************************************************************/
void
CATDlgInputThread::ExitThread()
{
DWORD dwReturnCode;
int i;
CWaitCursor wait;
/*
* If the thread was not created properly, just delete object and return.
*/
if ( !m_hThread ) {
delete this;
return;
}
/*
* Set the m_bExit flag to TRUE, wake up the run thread's WaitCommEvent() by
* resetting device's Comm mask, and bump the consumed semaphore to assure exit.
*/
m_bExit = TRUE;
SetCommMask(m_hDevice, 0);
SignalConsumed();
/*
* Purge the recieve buffer and any pending read.
*/
PurgeComm(m_hDevice, PURGE_RXABORT | PURGE_RXCLEAR);
/*
* Wait a while for the thread to exit.
*/
for ( i = 0, GetExitCodeThread( m_hThread, &dwReturnCode );
(i < MAX_SLEEP_COUNT) && (dwReturnCode == STILL_ACTIVE); i++ ) {
Sleep(100);
GetExitCodeThread( m_hThread, &dwReturnCode );
}
/*
* If the thread has still not exited, terminate it.
*/
if ( dwReturnCode == STILL_ACTIVE ) {
TerminateThread( m_hThread, 1 );
#ifdef _DEBUG
TRACE( TEXT("WINCFG: Forced Terminate of Async Test Input thread after %u 100msec exit waits.\n"),
MAX_SLEEP_COUNT );
#endif
}
/*
* Close the thread handle and delete this CATDlgInputThread object
*/
VERIFY( CloseHandle(m_hThread) );
delete this;
} // end CATDlgInputThread::ExitThread
////////////////////////////////////////////////////////////////////////////////
// CATDlgInputThread operations: secondary thread
/*******************************************************************************
*
* NotifyAbort - CATDlgInputThread member function: private operation
* (SECONDARY THREAD)
*
* Notify the dialog of thread abort and reason.
*
* ENTRY:
* idError (input)
* Resource id for error message.
* EXIT:
*
******************************************************************************/
void
CATDlgInputThread::NotifyAbort( UINT idError )
{
::PostMessage(m_hDlg, WM_ASYNCTESTABORT, idError, GetLastError());
} // end CATDlgInputThread::NotifyAbort
/*******************************************************************************
*
* CommInputNotify - CATDlgInputThread member function: private operation
* (SECONDARY THREAD)
*
* Notify the dialog of comm input.
*
* ENTRY:
* EXIT:
* -1 no error and continue thread
* 0 if ExitThread was requested by parent
*
******************************************************************************/
int
CATDlgInputThread::CommInputNotify()
{
/*
* Tell the dialog that we've got some new input.
*/
::PostMessage(m_hDlg, WM_ASYNCTESTINPUTREADY, 0, 0);
WaitForSingleObject(m_hConsumed, INFINITE);
/*
* Check for thread exit request.
*/
if ( m_bExit )
return(0);
else
return(-1);
} // end CATDlgInputThread::CommInputNotify
/*******************************************************************************
*
* CommStatusAndNotify - CATDlgInputThread member function: private operation
* (SECONDARY THREAD)
*
* Read the comm port status and notify dialog.
*
* ENTRY:
* EXIT:
* -1 no error and continue thread
* 0 if ExitThread was requested by parent
* 1 error condition
*
******************************************************************************/
int
CATDlgInputThread::CommStatusAndNotify()
{
PFLOWCONTROLCONFIG pFlow;
DWORD ModemStatus, Error;
if ( !GetCommModemStatus(m_hDevice, &ModemStatus) ) {
/*
* We can't query the comm information; tell the primary thread
* that we've aborted, and return error (will exit thread).
*/
NotifyAbort(IDP_ERROR_GET_COMM_MODEM_STATUS);
return(1);
}
/*
* Update modem status
*/
m_Status.AsyncSignal = ModemStatus;
/*
* Or in status of DTR and RTS
*/
pFlow = &m_PdConfig.Params.Async.FlowControl;
if ( pFlow->fEnableDTR )
m_Status.AsyncSignal |= MS_DTR_ON;
if ( pFlow->fEnableRTS )
m_Status.AsyncSignal |= MS_RTS_ON;
/*
* OR in new event mask
*/
m_Status.AsyncSignalMask |= m_EventMask;
/*
* Update async error counters
*/
if ( m_EventMask & EV_ERR ) {
(VOID) ClearCommError( m_hDevice, &Error, NULL );
if ( Error & CE_OVERRUN )
m_Status.Output.AsyncOverrunError++;
if ( Error & CE_FRAME )
m_Status.Input.AsyncFramingError++;
if ( Error & CE_RXOVER )
m_Status.Input.AsyncOverflowError++;
if ( Error & CE_RXPARITY )
m_Status.Input.AsyncParityError++;
}
/*
* Tell the dialog that we've got some new status information.
*/
::PostMessage(m_hDlg, WM_ASYNCTESTSTATUSREADY, 0, 0);
WaitForSingleObject(m_hConsumed, INFINITE);
/*
* Check for thread exit request.
*/
if ( m_bExit )
return(0);
else
return(-1);
} // end CATDlgInputThread::CommStatusAndNotify
/*******************************************************************************
*
* PostInputRead - CATDlgInputThread member function: private operation
* (SECONDARY THREAD)
*
* Post a ReadFile operation for the device, processing as long as data
* is present.
*
* ENTRY:
* EXIT:
* -1 if read operation posted sucessfully
* 0 if ExitThread was requested by parent
* 1 if error condition
*
******************************************************************************/
int
CATDlgInputThread::PostInputRead()
{
int iStat;
/*
* Post read for input data, processing immediataly if not 'pending'.
*/
while ( ReadFile( m_hDevice, m_Buffer, MAX_COMMAND_LEN,
&m_BufferBytes, &m_OverlapRead ) ) {
if ( (iStat = CommInputNotify()) != -1 )
return(iStat);
}
/*
* Make sure read is pending (not some other error).
*/
if ( GetLastError() != ERROR_IO_PENDING ) {
NotifyAbort(IDP_ERROR_READ_FILE);
return(1);
}
/*
* Return 'posted sucessfully' status.
*/
return(-1);
} // end CATDlgInputThread::PostInputRead
/*******************************************************************************
*
* PostStatusRead - CATDlgInputThread member function: private operation
* (SECONDARY THREAD)
*
* Post a WaitCommStatus operation for the device.
*
* ENTRY:
* EXIT:
* -1 if status operation posted sucessfully
* 1 if error condition
*
******************************************************************************/
int
CATDlgInputThread::PostStatusRead()
{
/*
* Post read for comm status.
*/
if ( !WaitCommEvent(m_hDevice, &m_EventMask, &m_OverlapSignal) ) {
/*
* Make sure comm status read is pending (not some other error).
*/
if ( GetLastError() != ERROR_IO_PENDING ) {
NotifyAbort(IDP_ERROR_WAIT_COMM_EVENT);
return(1);
}
}
/*
* Return 'posted sucessfully' status.
*/
return(-1);
} // end CATDlgInputThread::PostStatusRead
////////////////////////////////////////////////////////////////////////////////