Source code of Windows XP (NT5)
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.

671 lines
16 KiB

  1. //Copyright (c) 1998 - 1999 Microsoft Corporation
  2. /*******************************************************************************
  3. *
  4. * threads.cpp
  5. *
  6. * implementation of WINCFG thread classes
  7. *
  8. * copyright notice: Copyright 1994, Citrix Systems Inc.
  9. *
  10. * $Author: butchd $ Butch Davis
  11. *
  12. * $Log: N:\NT\PRIVATE\UTILS\CITRIX\WINUTILS\WINCFG\VCS\THREADS.CPP $
  13. *
  14. * Rev 1.18 19 Sep 1996 15:58:52 butchd
  15. * update
  16. *
  17. * Rev 1.17 12 Sep 1996 16:16:44 butchd
  18. * update
  19. *
  20. *******************************************************************************/
  21. /*
  22. * include files
  23. */
  24. #include "stdafx.h"
  25. #include "wincfg.h"
  26. #ifdef _DEBUG
  27. #undef THIS_FILE
  28. static char BASED_CODE THIS_FILE[] = __FILE__;
  29. #endif
  30. extern CWincfgApp *pApp;
  31. ////////////////////////////////////////////////////////////////////////////////
  32. // CThread class construction / destruction, implementation
  33. /*******************************************************************************
  34. *
  35. * CThread - CThread constructor
  36. *
  37. * ENTRY:
  38. * EXIT:
  39. *
  40. ******************************************************************************/
  41. CThread::CThread()
  42. {
  43. m_hThread = NULL;
  44. m_dwThreadID = 0;
  45. } // end CThread::CThread
  46. /*******************************************************************************
  47. *
  48. * ~CThread - CThread destructor
  49. *
  50. * ENTRY:
  51. * EXIT:
  52. *
  53. ******************************************************************************/
  54. CThread::~CThread()
  55. {
  56. } // end CThread::~CThread
  57. /*******************************************************************************
  58. *
  59. * operator new - CThread operator override
  60. *
  61. * ENTRY:
  62. * EXIT:
  63. *
  64. ******************************************************************************/
  65. void *
  66. CThread::operator new(size_t nSize)
  67. {
  68. return( ::malloc(nSize) );
  69. } // end CThread::operator new
  70. /*******************************************************************************
  71. *
  72. * operator delete - CThread operator override
  73. *
  74. * ENTRY:
  75. * EXIT:
  76. *
  77. ******************************************************************************/
  78. void
  79. CThread::operator delete(void *p)
  80. {
  81. ::free(p);
  82. } // end CThread::operator delete
  83. ////////////////////////////////////////////////////////////////////////////////
  84. // CThread operations: primary thread
  85. /*******************************************************************************
  86. *
  87. * CreateThread - CThread implementation function
  88. *
  89. * Class wrapper for the Win32 CreateThread API.
  90. *
  91. * ENTRY:
  92. * EXIT:
  93. *
  94. ******************************************************************************/
  95. HANDLE
  96. CThread::CreateThread( DWORD cbStack,
  97. DWORD fdwCreate )
  98. {
  99. /*
  100. * Simple wrapper for Win32 CreateThread API.
  101. */
  102. return( m_hThread = ::CreateThread( NULL, cbStack, ThreadEntryPoint,
  103. (LPVOID)this, fdwCreate, &m_dwThreadID ) );
  104. } // end CThread::CreateThread
  105. ////////////////////////////////////////////////////////////////////////////////
  106. // CThread operations: secondary thread
  107. /*******************************************************************************
  108. *
  109. * ThreadEntryPoint - CThread implementation function
  110. * (SECONDARY THREAD)
  111. *
  112. * ENTRY:
  113. * EXIT:
  114. *
  115. ******************************************************************************/
  116. DWORD __stdcall
  117. CThread::ThreadEntryPoint(LPVOID lpParam)
  118. {
  119. CThread *pThread;
  120. DWORD dwResult;
  121. /*
  122. * (lpParam is actually the 'this' pointer)
  123. */
  124. pThread = (CThread*)lpParam;
  125. VERIFY(pThread != NULL);
  126. /*
  127. * Run the thread.
  128. */
  129. dwResult = pThread->RunThread();
  130. /*
  131. * Return the result.
  132. */
  133. return(dwResult);
  134. } // end CThread::ThreadEntryPoint
  135. ////////////////////////////////////////////////////////////////////////////////
  136. ////////////////////////////////////////////////////////////////////////////////
  137. // CATDlgInputThread class construction / destruction, implementation
  138. /*******************************************************************************
  139. *
  140. * CATDlgInputThread - CATDlgInputThread constructor
  141. *
  142. * ENTRY:
  143. * EXIT:
  144. *
  145. ******************************************************************************/
  146. CATDlgInputThread::CATDlgInputThread()
  147. {
  148. /*
  149. * Initialize member variables.
  150. */
  151. m_bExit = FALSE;
  152. m_ErrorStatus = ERROR_SUCCESS;
  153. m_hConsumed = m_OverlapSignal.hEvent = m_OverlapRead.hEvent = NULL;
  154. } // end CATDlgInputThread::CATDlgInputThread
  155. /*******************************************************************************
  156. *
  157. * ~CATDlgInputThread - CATDlgInputThread destructor
  158. *
  159. * ENTRY:
  160. * EXIT:
  161. *
  162. ******************************************************************************/
  163. CATDlgInputThread::~CATDlgInputThread()
  164. {
  165. /*
  166. * Close the semaphore and events when the CATDlgInputThread
  167. * object is destroyed.
  168. */
  169. if ( m_hConsumed )
  170. CloseHandle(m_hConsumed);
  171. if ( m_OverlapRead.hEvent )
  172. CloseHandle(m_OverlapRead.hEvent);
  173. if ( m_OverlapSignal.hEvent )
  174. CloseHandle(m_OverlapSignal.hEvent);
  175. } // end CATDlgInputThread::~CATDlgInputThread
  176. /*******************************************************************************
  177. *
  178. * RunThread - CATDlgInputThread secondary thread main function loop
  179. * (SECONDARY THREAD)
  180. *
  181. * ENTRY:
  182. * EXIT:
  183. * (DWORD) exit status for the secondary thread.
  184. *
  185. ******************************************************************************/
  186. DWORD
  187. CATDlgInputThread::RunThread()
  188. {
  189. HANDLE hWait[2];
  190. DWORD Status;
  191. int iStat;
  192. /*
  193. * Initialize for overlapped status and read input.
  194. */
  195. if ( !(m_hConsumed = CreateSemaphore( NULL, 0,
  196. MAX_STATUS_SEMAPHORE_COUNT,
  197. NULL )) ||
  198. !(m_OverlapRead.hEvent = CreateEvent( NULL, TRUE,
  199. FALSE, NULL )) ||
  200. !(m_OverlapSignal.hEvent = CreateEvent( NULL, TRUE,
  201. FALSE, NULL )) ||
  202. !SetCommMask( m_hDevice,
  203. EV_CTS | EV_DSR | EV_ERR | EV_RING | EV_RLSD | EV_BREAK ) ) {
  204. NotifyAbort(IDP_ERROR_CANT_INITIALIZE_INPUT_THREAD);
  205. return(1);
  206. }
  207. /*
  208. * Query initial comm status to initialize dialog with (return if error).
  209. */
  210. if ( (iStat = CommStatusAndNotify()) != -1 )
  211. return(iStat);
  212. /*
  213. * Post Read for input data.
  214. */
  215. if ( (iStat = PostInputRead()) != -1 )
  216. return(iStat);
  217. /*
  218. * Post Read for status.
  219. */
  220. if ( (iStat = PostStatusRead()) != -1 )
  221. return(iStat);
  222. /*
  223. * Loop till exit requested.
  224. */
  225. for ( ; ; ) {
  226. /*
  227. * Wait for either input data or an comm status event.
  228. */
  229. hWait[0] = m_OverlapRead.hEvent;
  230. hWait[1] = m_OverlapSignal.hEvent;
  231. Status = WaitForMultipleObjects(2, hWait, FALSE, INFINITE);
  232. /*
  233. * Check for exit.
  234. */
  235. if ( m_bExit )
  236. return(0);
  237. if ( Status == WAIT_OBJECT_0 ) {
  238. /*
  239. * Read event:
  240. * Get result of overlapped read.
  241. */
  242. if ( !GetOverlappedResult( m_hDevice,
  243. &m_OverlapRead,
  244. &m_BufferBytes,
  245. TRUE ) ) {
  246. NotifyAbort(IDP_ERROR_GET_OVERLAPPED_RESULT_READ);
  247. return(1);
  248. }
  249. /*
  250. * Notify dialog.
  251. */
  252. if ( (iStat = CommInputNotify()) != -1 )
  253. return(iStat);
  254. /*
  255. * Post Read for input data.
  256. */
  257. if ( (iStat = PostInputRead()) != -1 )
  258. return(iStat);
  259. } else if ( Status == WAIT_OBJECT_0+1 ) {
  260. /*
  261. * Comm status event:
  262. * Query comm status and notify dialog.
  263. */
  264. if ( (iStat = CommStatusAndNotify()) != -1 )
  265. return(iStat);
  266. /*
  267. * Post Read for status.
  268. */
  269. if ( (iStat = PostStatusRead()) != -1 )
  270. return(iStat);
  271. } else {
  272. /*
  273. * Unknown event: Abort.
  274. */
  275. NotifyAbort(IDP_ERROR_WAIT_FOR_MULTIPLE_OBJECTS);
  276. return(1);
  277. }
  278. }
  279. } // end CATDlgInputThread::RunThread
  280. ////////////////////////////////////////////////////////////////////////////////
  281. // CATDlgInputThread operations: primary thread
  282. /*******************************************************************************
  283. *
  284. * SignalConsumed - CATDlgInputThread member function: public operation
  285. *
  286. * Release the m_hConsumed semaphore to allow secondary thread to continue
  287. * running.
  288. *
  289. * ENTRY:
  290. * EXIT:
  291. *
  292. ******************************************************************************/
  293. void
  294. CATDlgInputThread::SignalConsumed()
  295. {
  296. ReleaseSemaphore( m_hConsumed, 1, NULL );
  297. } // end CATDlgInputThread::SignalConsumed
  298. /*******************************************************************************
  299. *
  300. * ExitThread - CATDlgInputThread member function: public operation
  301. *
  302. * Tell the secondary thread to exit and cleanup after.
  303. *
  304. * ENTRY:
  305. * EXIT:
  306. *
  307. ******************************************************************************/
  308. void
  309. CATDlgInputThread::ExitThread()
  310. {
  311. DWORD dwReturnCode;
  312. int i;
  313. CWaitCursor wait;
  314. /*
  315. * If the thread was not created properly, just delete object and return.
  316. */
  317. if ( !m_hThread ) {
  318. delete this;
  319. return;
  320. }
  321. /*
  322. * Set the m_bExit flag to TRUE, wake up the run thread's WaitCommEvent() by
  323. * resetting device's Comm mask, and bump the consumed semaphore to assure exit.
  324. */
  325. m_bExit = TRUE;
  326. SetCommMask(m_hDevice, 0);
  327. SignalConsumed();
  328. /*
  329. * Purge the recieve buffer and any pending read.
  330. */
  331. PurgeComm(m_hDevice, PURGE_RXABORT | PURGE_RXCLEAR);
  332. /*
  333. * Wait a while for the thread to exit.
  334. */
  335. for ( i = 0, GetExitCodeThread( m_hThread, &dwReturnCode );
  336. (i < MAX_SLEEP_COUNT) && (dwReturnCode == STILL_ACTIVE); i++ ) {
  337. Sleep(100);
  338. GetExitCodeThread( m_hThread, &dwReturnCode );
  339. }
  340. /*
  341. * If the thread has still not exited, terminate it.
  342. */
  343. if ( dwReturnCode == STILL_ACTIVE ) {
  344. TerminateThread( m_hThread, 1 );
  345. #ifdef _DEBUG
  346. TRACE( TEXT("WINCFG: Forced Terminate of Async Test Input thread after %u 100msec exit waits.\n"),
  347. MAX_SLEEP_COUNT );
  348. #endif
  349. }
  350. /*
  351. * Close the thread handle and delete this CATDlgInputThread object
  352. */
  353. VERIFY( CloseHandle(m_hThread) );
  354. delete this;
  355. } // end CATDlgInputThread::ExitThread
  356. ////////////////////////////////////////////////////////////////////////////////
  357. // CATDlgInputThread operations: secondary thread
  358. /*******************************************************************************
  359. *
  360. * NotifyAbort - CATDlgInputThread member function: private operation
  361. * (SECONDARY THREAD)
  362. *
  363. * Notify the dialog of thread abort and reason.
  364. *
  365. * ENTRY:
  366. * idError (input)
  367. * Resource id for error message.
  368. * EXIT:
  369. *
  370. ******************************************************************************/
  371. void
  372. CATDlgInputThread::NotifyAbort( UINT idError )
  373. {
  374. ::PostMessage(m_hDlg, WM_ASYNCTESTABORT, idError, GetLastError());
  375. } // end CATDlgInputThread::NotifyAbort
  376. /*******************************************************************************
  377. *
  378. * CommInputNotify - CATDlgInputThread member function: private operation
  379. * (SECONDARY THREAD)
  380. *
  381. * Notify the dialog of comm input.
  382. *
  383. * ENTRY:
  384. * EXIT:
  385. * -1 no error and continue thread
  386. * 0 if ExitThread was requested by parent
  387. *
  388. ******************************************************************************/
  389. int
  390. CATDlgInputThread::CommInputNotify()
  391. {
  392. /*
  393. * Tell the dialog that we've got some new input.
  394. */
  395. ::PostMessage(m_hDlg, WM_ASYNCTESTINPUTREADY, 0, 0);
  396. WaitForSingleObject(m_hConsumed, INFINITE);
  397. /*
  398. * Check for thread exit request.
  399. */
  400. if ( m_bExit )
  401. return(0);
  402. else
  403. return(-1);
  404. } // end CATDlgInputThread::CommInputNotify
  405. /*******************************************************************************
  406. *
  407. * CommStatusAndNotify - CATDlgInputThread member function: private operation
  408. * (SECONDARY THREAD)
  409. *
  410. * Read the comm port status and notify dialog.
  411. *
  412. * ENTRY:
  413. * EXIT:
  414. * -1 no error and continue thread
  415. * 0 if ExitThread was requested by parent
  416. * 1 error condition
  417. *
  418. ******************************************************************************/
  419. int
  420. CATDlgInputThread::CommStatusAndNotify()
  421. {
  422. PFLOWCONTROLCONFIG pFlow;
  423. DWORD ModemStatus, Error;
  424. if ( !GetCommModemStatus(m_hDevice, &ModemStatus) ) {
  425. /*
  426. * We can't query the comm information; tell the primary thread
  427. * that we've aborted, and return error (will exit thread).
  428. */
  429. NotifyAbort(IDP_ERROR_GET_COMM_MODEM_STATUS);
  430. return(1);
  431. }
  432. /*
  433. * Update modem status
  434. */
  435. m_Status.AsyncSignal = ModemStatus;
  436. /*
  437. * Or in status of DTR and RTS
  438. */
  439. pFlow = &m_PdConfig.Params.Async.FlowControl;
  440. if ( pFlow->fEnableDTR )
  441. m_Status.AsyncSignal |= MS_DTR_ON;
  442. if ( pFlow->fEnableRTS )
  443. m_Status.AsyncSignal |= MS_RTS_ON;
  444. /*
  445. * OR in new event mask
  446. */
  447. m_Status.AsyncSignalMask |= m_EventMask;
  448. /*
  449. * Update async error counters
  450. */
  451. if ( m_EventMask & EV_ERR ) {
  452. (VOID) ClearCommError( m_hDevice, &Error, NULL );
  453. if ( Error & CE_OVERRUN )
  454. m_Status.Output.AsyncOverrunError++;
  455. if ( Error & CE_FRAME )
  456. m_Status.Input.AsyncFramingError++;
  457. if ( Error & CE_RXOVER )
  458. m_Status.Input.AsyncOverflowError++;
  459. if ( Error & CE_RXPARITY )
  460. m_Status.Input.AsyncParityError++;
  461. }
  462. /*
  463. * Tell the dialog that we've got some new status information.
  464. */
  465. ::PostMessage(m_hDlg, WM_ASYNCTESTSTATUSREADY, 0, 0);
  466. WaitForSingleObject(m_hConsumed, INFINITE);
  467. /*
  468. * Check for thread exit request.
  469. */
  470. if ( m_bExit )
  471. return(0);
  472. else
  473. return(-1);
  474. } // end CATDlgInputThread::CommStatusAndNotify
  475. /*******************************************************************************
  476. *
  477. * PostInputRead - CATDlgInputThread member function: private operation
  478. * (SECONDARY THREAD)
  479. *
  480. * Post a ReadFile operation for the device, processing as long as data
  481. * is present.
  482. *
  483. * ENTRY:
  484. * EXIT:
  485. * -1 if read operation posted sucessfully
  486. * 0 if ExitThread was requested by parent
  487. * 1 if error condition
  488. *
  489. ******************************************************************************/
  490. int
  491. CATDlgInputThread::PostInputRead()
  492. {
  493. int iStat;
  494. /*
  495. * Post read for input data, processing immediataly if not 'pending'.
  496. */
  497. while ( ReadFile( m_hDevice, m_Buffer, MAX_COMMAND_LEN,
  498. &m_BufferBytes, &m_OverlapRead ) ) {
  499. if ( (iStat = CommInputNotify()) != -1 )
  500. return(iStat);
  501. }
  502. /*
  503. * Make sure read is pending (not some other error).
  504. */
  505. if ( GetLastError() != ERROR_IO_PENDING ) {
  506. NotifyAbort(IDP_ERROR_READ_FILE);
  507. return(1);
  508. }
  509. /*
  510. * Return 'posted sucessfully' status.
  511. */
  512. return(-1);
  513. } // end CATDlgInputThread::PostInputRead
  514. /*******************************************************************************
  515. *
  516. * PostStatusRead - CATDlgInputThread member function: private operation
  517. * (SECONDARY THREAD)
  518. *
  519. * Post a WaitCommStatus operation for the device.
  520. *
  521. * ENTRY:
  522. * EXIT:
  523. * -1 if status operation posted sucessfully
  524. * 1 if error condition
  525. *
  526. ******************************************************************************/
  527. int
  528. CATDlgInputThread::PostStatusRead()
  529. {
  530. /*
  531. * Post read for comm status.
  532. */
  533. if ( !WaitCommEvent(m_hDevice, &m_EventMask, &m_OverlapSignal) ) {
  534. /*
  535. * Make sure comm status read is pending (not some other error).
  536. */
  537. if ( GetLastError() != ERROR_IO_PENDING ) {
  538. NotifyAbort(IDP_ERROR_WAIT_COMM_EVENT);
  539. return(1);
  540. }
  541. }
  542. /*
  543. * Return 'posted sucessfully' status.
  544. */
  545. return(-1);
  546. } // end CATDlgInputThread::PostStatusRead
  547. ////////////////////////////////////////////////////////////////////////////////