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.

2664 lines
50 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. spcompat.cxx
  6. Abstract:
  7. porting the spool library code into printui
  8. Author:
  9. Lazar Ivanov (LazarI) Jul-05-2000
  10. Revision History:
  11. --*/
  12. #include "precomp.hxx"
  13. #pragma hdrstop
  14. ///////////////////////////////////////////////////
  15. // @@file@@ debug.cxx
  16. ///////////////////////////////////////////////////
  17. #if DBG
  18. /********************************************************************
  19. TStatus automated error logging and codepath testing.
  20. ********************************************************************/
  21. TStatusBase&
  22. TStatusBase::
  23. pNoChk(
  24. VOID
  25. )
  26. {
  27. _pszFileA = NULL;
  28. return (TStatusBase&)*this;
  29. }
  30. TStatusBase&
  31. TStatusBase::
  32. pSetInfo(
  33. UINT uDbg,
  34. UINT uLine,
  35. LPCSTR pszFileA,
  36. LPCSTR pszModuleA
  37. )
  38. {
  39. _uDbg = uDbg;
  40. _uLine = uLine;
  41. _pszFileA = pszFileA;
  42. SPLASSERT( pszFileA );
  43. _pszModuleA = pszModuleA;
  44. return (TStatusBase&)*this;
  45. }
  46. DWORD
  47. TStatus::
  48. dwGetStatus(
  49. VOID
  50. )
  51. {
  52. //
  53. // For now, return error code. Later it will return the actual
  54. // error code.
  55. //
  56. return _dwStatus;
  57. }
  58. DWORD
  59. TStatusBase::
  60. operator=(
  61. DWORD dwStatus
  62. )
  63. {
  64. //
  65. // Check if we have an error, and it's not one of the two
  66. // accepted "safe" errors.
  67. //
  68. // If pszFileA is not set, then we can safely ignore the
  69. // error as one the client intended.
  70. //
  71. if( _pszFileA &&
  72. dwStatus != ERROR_SUCCESS &&
  73. dwStatus != _dwStatusSafe1 &&
  74. dwStatus != _dwStatusSafe2 &&
  75. dwStatus != _dwStatusSafe3 ){
  76. DBGMSG( DBG_WARN,
  77. ( "TStatus set to %d\nLine %d, %hs\n",
  78. dwStatus,
  79. _uLine,
  80. _pszFileA ));
  81. }
  82. return _dwStatus = dwStatus;
  83. }
  84. /********************************************************************
  85. Same, but for HRESULTs.
  86. ********************************************************************/
  87. TStatusHBase&
  88. TStatusHBase::
  89. pNoChk(
  90. VOID
  91. )
  92. {
  93. _pszFileA = NULL;
  94. return (TStatusH&)*this;
  95. }
  96. TStatusHBase&
  97. TStatusHBase::
  98. pSetInfo(
  99. UINT uDbg,
  100. UINT uLine,
  101. LPCSTR pszFileA,
  102. LPCSTR pszModuleA
  103. )
  104. {
  105. _uDbg = uDbg;
  106. _uLine = uLine;
  107. _pszFileA = pszFileA;
  108. SPLASSERT( pszFileA );
  109. _pszModuleA = pszModuleA;
  110. return (TStatusH&)*this;
  111. }
  112. HRESULT
  113. TStatusHBase::
  114. operator=(
  115. HRESULT hrStatus
  116. )
  117. {
  118. //
  119. // Check if we have an error, and it's not one of the two
  120. // accepted "safe" errors.
  121. //
  122. // If pszFileA is not set, then we can safely ignore the
  123. // error as one the client intended.
  124. //
  125. if( _pszFileA &&
  126. FAILED(hrStatus) &&
  127. hrStatus != _hrStatusSafe1 &&
  128. hrStatus != _hrStatusSafe2 &&
  129. hrStatus != _hrStatusSafe3 ){
  130. DBGMSG( DBG_WARN,
  131. ( "TStatusH set to %x\nLine %d, %hs\n",
  132. hrStatus,
  133. _uLine,
  134. _pszFileA ));
  135. }
  136. return _hrStatus = hrStatus;
  137. }
  138. HRESULT
  139. TStatusH::
  140. hrGetStatus(
  141. VOID
  142. )
  143. {
  144. //
  145. // For now, return error code. Later it will return the actual
  146. // error code.
  147. //
  148. return _hrStatus;
  149. }
  150. /********************************************************************
  151. Same, but for BOOLs.
  152. ********************************************************************/
  153. TStatusBBase&
  154. TStatusBBase::
  155. pNoChk(
  156. VOID
  157. )
  158. {
  159. _pszFileA = NULL;
  160. return (TStatusBBase&)*this;
  161. }
  162. TStatusBBase&
  163. TStatusBBase::
  164. pSetInfo(
  165. UINT uDbg,
  166. UINT uLine,
  167. LPCSTR pszFileA,
  168. LPCSTR pszModuleA
  169. )
  170. {
  171. _uDbg = uDbg;
  172. _uLine = uLine;
  173. _pszFileA = pszFileA;
  174. SPLASSERT( pszFileA );
  175. _pszModuleA = pszModuleA;
  176. return (TStatusBBase&)*this;
  177. }
  178. BOOL
  179. TStatusB::
  180. bGetStatus(
  181. VOID
  182. )
  183. {
  184. //
  185. // For now, return error code. Later it will return the actual
  186. // error code.
  187. //
  188. return _bStatus;
  189. }
  190. BOOL
  191. TStatusBBase::
  192. operator=(
  193. BOOL bStatus
  194. )
  195. {
  196. //
  197. // Check if we have an error, and it's not one of the two
  198. // accepted "safe" errors.
  199. //
  200. // If pszFileA is not set, then we can safely ignore the
  201. // error as one the client intended.
  202. //
  203. if( _pszFileA && !bStatus ){
  204. DWORD dwLastError = GetLastError();
  205. if( dwLastError != _dwStatusSafe1 &&
  206. dwLastError != _dwStatusSafe2 &&
  207. dwLastError != _dwStatusSafe3 ){
  208. DBGMSG( DBG_WARN,
  209. ( "TStatusB set to FALSE, LastError = %d\nLine %d, %hs\n",
  210. GetLastError(),
  211. _uLine,
  212. _pszFileA ));
  213. }
  214. }
  215. return _bStatus = bStatus;
  216. }
  217. #endif // DBG
  218. ///////////////////////////////////////////////////
  219. // @@file@@ string.cxx
  220. ///////////////////////////////////////////////////
  221. //
  222. // Class specific NULL state.
  223. //
  224. TCHAR TString::gszNullState[2] = {0,0};
  225. //
  226. // Default construction.
  227. //
  228. TString::
  229. TString(
  230. VOID
  231. ) : _pszString( &TString::gszNullState[kValid] )
  232. {
  233. }
  234. //
  235. // Construction using an existing LPCTSTR string.
  236. //
  237. TString::
  238. TString(
  239. IN LPCTSTR psz
  240. ) : _pszString( &TString::gszNullState[kValid] )
  241. {
  242. bUpdate( psz );
  243. }
  244. //
  245. // Destruction, ensure we don't free our NULL state.
  246. //
  247. TString::
  248. ~TString(
  249. VOID
  250. )
  251. {
  252. vFree( _pszString );
  253. }
  254. //
  255. // Copy constructor.
  256. //
  257. TString::
  258. TString(
  259. const TString &String
  260. ) : _pszString( &TString::gszNullState[kValid] )
  261. {
  262. bUpdate( String._pszString );
  263. }
  264. //
  265. // Indicates if a string has any usable data.
  266. //
  267. BOOL
  268. TString::
  269. bEmpty(
  270. VOID
  271. ) const
  272. {
  273. return _pszString[0] == 0;
  274. }
  275. //
  276. // Indicates if a string object is valid.
  277. //
  278. BOOL
  279. TString::
  280. bValid(
  281. VOID
  282. ) const
  283. {
  284. return _pszString != &TString::gszNullState[kInValid];
  285. }
  286. //
  287. // Return the length of the string.
  288. //
  289. UINT
  290. TString::
  291. uLen(
  292. VOID
  293. ) const
  294. {
  295. return lstrlen( _pszString );
  296. }
  297. BOOL
  298. TString::
  299. bCat(
  300. IN LPCTSTR psz
  301. )
  302. /*++
  303. Routine Description:
  304. Safe concatenation of the specified string to the string
  305. object. If the allocation fails, return FALSE and the
  306. original string is not modified.
  307. Arguments:
  308. psz - Input string, may be NULL.
  309. Return Value:
  310. TRUE = update successful
  311. FALSE = update failed
  312. --*/
  313. {
  314. BOOL bStatus = FALSE;
  315. //
  316. // If a valid string was passed.
  317. //
  318. if( psz ){
  319. LPTSTR pszTmp = _pszString;
  320. //
  321. // Allocate the new buffer consisting of the size of the orginal
  322. // string plus the sizeof of the new string plus the null terminator.
  323. //
  324. _pszString = (LPTSTR)AllocMem(
  325. ( lstrlen( pszTmp ) +
  326. lstrlen( psz ) +
  327. 1 ) *
  328. sizeof ( pszTmp[0] ) );
  329. //
  330. // If memory was not available.
  331. //
  332. if( !_pszString ){
  333. //
  334. // Release the original buffer.
  335. //
  336. vFree( pszTmp );
  337. //
  338. // Mark the string object as invalid.
  339. //
  340. _pszString = &TString::gszNullState[kInValid];
  341. } else {
  342. //
  343. // Copy the string and concatenate the passed string.
  344. //
  345. lstrcpy( _pszString, pszTmp );
  346. lstrcat( _pszString, psz );
  347. //
  348. // Release the original buffer.
  349. //
  350. vFree( pszTmp );
  351. //
  352. // Indicate success.
  353. //
  354. bStatus = TRUE;
  355. }
  356. //
  357. // Skip null pointers, not an error.
  358. //
  359. } else {
  360. bStatus = TRUE;
  361. }
  362. return bStatus;
  363. }
  364. BOOL
  365. TString::
  366. bLimitBuffer(
  367. IN UINT nMaxLength
  368. )
  369. /*++
  370. Routine Description:
  371. Truncates th string if longer than nMaxLength
  372. including the terminating character
  373. Arguments:
  374. nMaxLength - the max length of the buffer
  375. Return Value:
  376. TRUE if the string is truncated and FALSE otherwise
  377. --*/
  378. {
  379. BOOL bRet = FALSE;
  380. if( lstrlen(_pszString) >= nMaxLength )
  381. {
  382. // truncate up to nMaxLength including the terminating character
  383. _pszString[nMaxLength-1] = 0;
  384. bRet = TRUE;
  385. }
  386. return bRet;
  387. }
  388. BOOL
  389. TString::
  390. bDeleteChar(
  391. IN UINT nPos
  392. )
  393. /*++
  394. Routine Description:
  395. Deletes the character at the specified pos
  396. Arguments:
  397. nPos - which char to delete
  398. Return Value:
  399. TRUE if on success and FALSE otherwise
  400. --*/
  401. {
  402. BOOL bRet = FALSE;
  403. UINT u, uLen = lstrlen(_pszString);
  404. ASSERT(nPos < uLen);
  405. if( nPos < uLen )
  406. {
  407. // the new length
  408. uLen--;
  409. // shift all the characters
  410. for( u=nPos; u<uLen; u++ )
  411. {
  412. _pszString[u] = _pszString[u+1];
  413. }
  414. // zero terminate
  415. _pszString[uLen] = 0;
  416. bRet = TRUE;
  417. }
  418. return bRet;
  419. }
  420. BOOL
  421. TString::
  422. bReplaceAll(
  423. IN TCHAR chFrom,
  424. IN TCHAR chTo
  425. )
  426. /*++
  427. Routine Description:
  428. replaces all chFrom characters to chTo
  429. Arguments:
  430. chFrom - character that needs to be replaced
  431. chTo - character to replace with
  432. Return Value:
  433. TRUE if on success and FALSE otherwise
  434. --*/
  435. {
  436. UINT u, uLen = lstrlen(_pszString);
  437. for( u=0; u<uLen; u++ )
  438. {
  439. if( chFrom == _pszString[u] )
  440. {
  441. // replace
  442. _pszString[u] = chTo;
  443. }
  444. }
  445. return TRUE;
  446. }
  447. VOID
  448. TString::
  449. vToUpper(
  450. VOID
  451. )
  452. /*++
  453. Routine Description:
  454. converts the string to upper case
  455. Arguments:
  456. None
  457. Return Value:
  458. None
  459. --*/
  460. {
  461. if( _pszString && _pszString[0] )
  462. {
  463. CharUpper(_pszString);
  464. }
  465. }
  466. VOID
  467. TString::
  468. vToLower(
  469. VOID
  470. )
  471. /*++
  472. Routine Description:
  473. converts the string to lower case
  474. Arguments:
  475. None
  476. Return Value:
  477. None
  478. --*/
  479. {
  480. if( _pszString && _pszString[0] )
  481. {
  482. CharLower(_pszString);
  483. }
  484. }
  485. BOOL
  486. TString::
  487. bUpdate(
  488. IN LPCTSTR psz
  489. )
  490. /*++
  491. Routine Description:
  492. Safe updating of string. If the allocation fails, return FALSE
  493. and leave the string as is.
  494. Arguments:
  495. psz - Input string, may be NULL.
  496. Return Value:
  497. TRUE = update successful
  498. FALSE = update failed
  499. --*/
  500. {
  501. //
  502. // Check if the null pointer is passed.
  503. //
  504. if( !psz ){
  505. //
  506. // If not pointing to the gszNullState
  507. //
  508. vFree( _pszString );
  509. //
  510. // Mark the object as valid.
  511. //
  512. _pszString = &TString::gszNullState[kValid];
  513. return TRUE;
  514. }
  515. //
  516. // Create temp pointer and allocate the new string.
  517. //
  518. LPTSTR pszTmp = _pszString;
  519. _pszString = (LPTSTR) AllocMem(( lstrlen(psz)+1 ) * sizeof( psz[0] ));
  520. //
  521. // If memory was not available.
  522. //
  523. if( !_pszString ){
  524. //
  525. // Ensure we free any previous string.
  526. //
  527. vFree( pszTmp );
  528. //
  529. // Mark the string object as invalid.
  530. //
  531. _pszString = &TString::gszNullState[kInValid];
  532. return FALSE;
  533. }
  534. //
  535. // Copy the string and
  536. //
  537. lstrcpy( _pszString, psz );
  538. //
  539. // If the old string object was not pointing to our
  540. // class specific gszNullStates then release the memory.
  541. //
  542. vFree( pszTmp );
  543. return TRUE;
  544. }
  545. BOOL
  546. TString::
  547. bLoadString(
  548. IN HINSTANCE hInst,
  549. IN UINT uID
  550. )
  551. /*++
  552. Routine Description:
  553. Safe load of a string from a resources file.
  554. Arguments:
  555. hInst - Instance handle of resource file.
  556. uId - Resource id to load.
  557. Return Value:
  558. TRUE = load successful
  559. FALSE = load failed
  560. --*/
  561. {
  562. LPTSTR pszString = NULL;
  563. BOOL bStatus = FALSE;
  564. INT iSize;
  565. INT iLen;
  566. //
  567. // Continue increasing the buffer until
  568. // the buffer is big enought to hold the entire string.
  569. //
  570. for( iSize = kStrMax; ; iSize += kStrMax ){
  571. //
  572. // Allocate string buffer.
  573. //
  574. pszString = (LPTSTR)AllocMem( iSize * sizeof( pszString[0] ) );
  575. if( pszString ){
  576. iLen = LoadString( hInst, uID, pszString, iSize );
  577. if( iLen == 0 ) {
  578. DBGMSG( DBG_ERROR, ( "String.vLoadString: failed to load IDS 0x%x, %d\n", uID, GetLastError() ));
  579. FreeMem( pszString );
  580. break;
  581. //
  582. // Since LoadString does not indicate if the string was truncated or it
  583. // just happened to fit. When we detect this ambiguous case we will
  584. // try one more time just to be sure.
  585. //
  586. } else if( iSize - iLen <= sizeof( pszString[0] ) ){
  587. FreeMem( pszString );
  588. //
  589. // LoadString was successful release original string buffer
  590. // and update new buffer pointer.
  591. //
  592. } else {
  593. vFree( _pszString );
  594. _pszString = pszString;
  595. bStatus = TRUE;
  596. break;
  597. }
  598. } else {
  599. DBGMSG( DBG_ERROR, ( "String.vLoadString: unable to allocate memory, %d\n", GetLastError() ));
  600. break;
  601. }
  602. }
  603. return bStatus;
  604. }
  605. VOID
  606. TString::
  607. vFree(
  608. IN LPTSTR pszString
  609. )
  610. /*++
  611. Routine Description:
  612. Safe free, frees the string memory. Ensures
  613. we do not try an free our global memory block.
  614. Arguments:
  615. pszString pointer to string meory to free.
  616. Return Value:
  617. Nothing.
  618. --*/
  619. {
  620. //
  621. // If this memory was not pointing to our
  622. // class specific gszNullStates then release the memory.
  623. //
  624. if( pszString != &TString::gszNullState[kValid] &&
  625. pszString != &TString::gszNullState[kInValid] ){
  626. FreeMem( pszString );
  627. }
  628. }
  629. BOOL
  630. TString::
  631. bFormat(
  632. IN LPCTSTR pszFmt,
  633. IN ...
  634. )
  635. {
  636. /*++
  637. Routine Description:
  638. Format the string opbject similar to sprintf.
  639. Arguments:
  640. pszFmt pointer format string.
  641. .. variable number of arguments similar to sprintf.
  642. Return Value:
  643. TRUE if string was format successfully. FALSE if error
  644. occurred creating the format string, string object will be
  645. invalid and the previous string lost.
  646. --*/
  647. BOOL bStatus = TRUE;
  648. va_list pArgs;
  649. va_start( pArgs, pszFmt );
  650. bStatus = bvFormat( pszFmt, pArgs );
  651. va_end( pArgs );
  652. return bStatus;
  653. }
  654. BOOL
  655. TString::
  656. bvFormat(
  657. IN LPCTSTR pszFmt,
  658. IN va_list avlist
  659. )
  660. /*++
  661. Routine Description:
  662. Format the string opbject similar to vsprintf.
  663. Arguments:
  664. pszFmt pointer format string.
  665. pointer to variable number of arguments similar to vsprintf.
  666. Return Value:
  667. TRUE if string was format successfully. FALSE if error
  668. occurred creating the format string, string object will be
  669. invalid and the previous string lost.
  670. --*/
  671. {
  672. BOOL bStatus;
  673. //
  674. // Save previous string value.
  675. //
  676. LPTSTR pszTemp = _pszString;
  677. //
  678. // Format the string.
  679. //
  680. _pszString = vsntprintf( pszFmt, avlist );
  681. //
  682. // If format failed mark object as invalid and
  683. // set the return value.
  684. //
  685. if( !_pszString )
  686. {
  687. _pszString = &TString::gszNullState[kInValid];
  688. bStatus = FALSE;
  689. }
  690. else
  691. {
  692. bStatus = TRUE;
  693. }
  694. //
  695. // Release near the end because the format string or arguments
  696. // may be referencing this string object.
  697. //
  698. vFree( pszTemp );
  699. return bStatus;
  700. }
  701. LPTSTR
  702. TString::
  703. vsntprintf(
  704. IN LPCTSTR szFmt,
  705. IN va_list pArgs
  706. )
  707. /*++
  708. Routine Description:
  709. //
  710. // Formats a string and returns a heap allocated string with the
  711. // formated data. This routine can be used to for extremely
  712. // long format strings. Note: If a valid pointer is returned
  713. // the callng functions must release the data with a call to delete.
  714. // Example:
  715. //
  716. // LPCTSTR p = vsntprintf("Test %s", pString );
  717. //
  718. // SetTitle( p );
  719. //
  720. // delete [] p;
  721. //
  722. Arguments:
  723. pszString pointer format string.
  724. pointer to a variable number of arguments.
  725. Return Value:
  726. Pointer to format string. NULL if error.
  727. --*/
  728. {
  729. LPTSTR pszBuff = NULL;
  730. INT iSize = kStrIncrement;
  731. for( ; ; )
  732. {
  733. //
  734. // Allocate the message buffer.
  735. //
  736. pszBuff = (LPTSTR)AllocMem( iSize * sizeof(TCHAR) );
  737. if( !pszBuff )
  738. {
  739. break;
  740. }
  741. //
  742. // Attempt to format the string. snprintf fails with a
  743. // negative number when the buffer is too small.
  744. //
  745. INT iReturn = _vsntprintf( pszBuff, iSize, szFmt, pArgs );
  746. //
  747. // If the return value positive and not equal to the buffer size
  748. // then the format succeeded. _vsntprintf will not null terminate
  749. // the string if the resultant string is exactly the lenght of the
  750. // provided buffer.
  751. //
  752. if( iReturn > 0 && iReturn != iSize )
  753. {
  754. break;
  755. }
  756. //
  757. // String did not fit release the current buffer.
  758. //
  759. if( pszBuff )
  760. {
  761. FreeMem( pszBuff );
  762. }
  763. //
  764. // Double the buffer size after each failure.
  765. //
  766. iSize *= 2;
  767. //
  768. // If the size is greater than 100k exit without formatting a string.
  769. //
  770. if( iSize > kStrMaxFormatSize )
  771. {
  772. DBGMSG( DBG_ERROR, ("TString::vsntprintf failed string too long.\n") );
  773. pszBuff = NULL;
  774. break;
  775. }
  776. }
  777. return pszBuff;
  778. }
  779. ///////////////////////////////////////////////////
  780. // @@file@@ state.cxx
  781. ///////////////////////////////////////////////////
  782. /********************************************************************
  783. Ref counting
  784. ********************************************************************/
  785. VOID
  786. MRefQuick::
  787. vIncRef(
  788. VOID
  789. )
  790. {
  791. ++_cRef;
  792. }
  793. LONG
  794. MRefQuick::
  795. cDecRef(
  796. VOID
  797. )
  798. {
  799. --_cRef;
  800. if( !_cRef ){
  801. vRefZeroed();
  802. return 0;
  803. }
  804. return _cRef;
  805. }
  806. VOID
  807. MRefQuick::
  808. vDecRefDelete(
  809. VOID
  810. )
  811. {
  812. --_cRef;
  813. if( !_cRef ){
  814. vRefZeroed();
  815. }
  816. }
  817. /********************************************************************
  818. MRefCom: Reference counting using interlocked references.
  819. This avoids creating a common critical section.
  820. vDeleteDecRef is the same as vDecRef, but it logs differently.
  821. ********************************************************************/
  822. VOID
  823. MRefCom::
  824. vIncRef(
  825. VOID
  826. )
  827. {
  828. InterlockedIncrement( &_cRef );
  829. }
  830. LONG
  831. MRefCom::
  832. cDecRef(
  833. VOID
  834. )
  835. {
  836. LONG cRefReturn = InterlockedDecrement( &_cRef );
  837. if( !cRefReturn ){
  838. vRefZeroed();
  839. }
  840. return cRefReturn;
  841. }
  842. VOID
  843. MRefCom::
  844. vDecRefDelete(
  845. VOID
  846. )
  847. {
  848. if( !InterlockedDecrement( &_cRef )){
  849. vRefZeroed();
  850. }
  851. }
  852. VOID
  853. MRefCom::
  854. vRefZeroed(
  855. VOID
  856. )
  857. {
  858. }
  859. /********************************************************************
  860. State
  861. ********************************************************************/
  862. #if DBG
  863. TState::
  864. TState(
  865. VOID
  866. ) : _StateVar(0)
  867. {
  868. }
  869. TState::
  870. TState(
  871. STATEVAR StateVar
  872. ) : _StateVar(StateVar)
  873. {
  874. }
  875. TState::
  876. ~TState(
  877. VOID
  878. )
  879. {
  880. }
  881. STATEVAR
  882. TState::
  883. operator|=(
  884. STATEVAR StateVarOn
  885. )
  886. {
  887. SPLASSERT( bValidateSet( StateVarOn ));
  888. _StateVar |= StateVarOn;
  889. return _StateVar;
  890. }
  891. STATEVAR
  892. TState::
  893. operator&=(
  894. STATEVAR StateVarMask
  895. )
  896. {
  897. SPLASSERT( bValidateMask( StateVarMask ));
  898. _StateVar &= StateVarMask;
  899. return _StateVar;
  900. }
  901. #endif
  902. ///////////////////////////////////////////////////
  903. // @@file@@ splutil.cxx
  904. ///////////////////////////////////////////////////
  905. MEntry*
  906. MEntry::
  907. pFindEntry(
  908. PDLINK pdlink,
  909. LPCTSTR pszName
  910. )
  911. {
  912. PDLINK pdlinkT;
  913. MEntry* pEntry;
  914. for( pdlinkT = pdlink->FLink;
  915. pdlinkT != pdlink;
  916. pdlinkT = pdlinkT->FLink ){
  917. pEntry = MEntry::Entry_pConvert( pdlinkT );
  918. if( pEntry->_strName == pszName ){
  919. return pEntry;
  920. }
  921. }
  922. return NULL;
  923. }
  924. ///////////////////////////////////////////////////
  925. // @@file@@ threadm.cxx
  926. ///////////////////////////////////////////////////
  927. /********************************************************************
  928. Public interfaces.
  929. ********************************************************************/
  930. TThreadM::
  931. TThreadM(
  932. UINT uMaxThreads,
  933. UINT uIdleLife,
  934. CCSLock* pCritSec OPTIONAL
  935. ) :
  936. _uMaxThreads(uMaxThreads), _uIdleLife(uIdleLife), _uActiveThreads(0),
  937. _uRunNowThreads(0), _iIdleThreads(0),
  938. _lLocks(1) // the one who calls 'new TThreadM' acquires the initial lock
  939. /*++
  940. Routine Description:
  941. Construct a Thread Manager object.
  942. Arguments:
  943. uMaxThreads - Upper limit of threads that will be created.
  944. uIdleLife - Maximum life once a thread goes idle (in ms).
  945. pCritSec - Use this crit sec for synchronization (if not specified,
  946. a private one will be created).
  947. Return Value:
  948. Notes:
  949. _hTrigger is our validity variable. When this value is NULL,
  950. instantiation failed. If it's non-NULL, the entire object is valid.
  951. --*/
  952. {
  953. _hTrigger = CreateEvent( NULL,
  954. FALSE,
  955. FALSE,
  956. NULL );
  957. if( !_hTrigger ){
  958. return;
  959. }
  960. //
  961. // If no critical section, create our own.
  962. //
  963. if (!pCritSec) {
  964. _pCritSec = new CCSLock();
  965. if( !_pCritSec ){
  966. //
  967. // _hTrigger is our valid variable. If we fail to create
  968. // the critical section, prepare to return failure.
  969. //
  970. CloseHandle( _hTrigger );
  971. _hTrigger = NULL;
  972. return;
  973. }
  974. _State |= kPrivateCritSec;
  975. } else {
  976. _pCritSec = pCritSec;
  977. }
  978. }
  979. VOID
  980. TThreadM::
  981. vDelete(
  982. VOID
  983. )
  984. /*++
  985. Routine Description:
  986. Indicates that the object is pending deletion. Any object that
  987. inherits from vDelete should _not_ call the destructor directly,
  988. since there may be pending jobs. Instead, they should call
  989. TThreadM::vDelete().
  990. Arguments:
  991. Return Value:
  992. --*/
  993. {
  994. CCSLock::Locker CSL( *_pCritSec );
  995. //
  996. // Mark as wanting to be destroyed.
  997. //
  998. _State |= kDestroyReq;
  999. }
  1000. BOOL
  1001. TThreadM::
  1002. bJobAdded(
  1003. BOOL bRunNow
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. Notify the thread manager that a new job has been added. This job
  1008. will be processed fifo.
  1009. Arguments:
  1010. bRunNow - Ignore the thread limits and run the job now.
  1011. Return Value:
  1012. TRUE - Job successfully added.
  1013. FALSE - Job could not be added.
  1014. --*/
  1015. {
  1016. DWORD dwThreadId;
  1017. HANDLE hThread;
  1018. BOOL rc = TRUE;
  1019. CCSLock::Locker CSL( *_pCritSec );
  1020. if( _State.bBit( kDestroyReq )){
  1021. DBGMSG( DBG_THREADM | DBG_ERROR,
  1022. ( "ThreadM.bJobAdded: add failed since DESTROY requested.\n" ));
  1023. SetLastError( ERROR_INVALID_PARAMETER );
  1024. rc = FALSE;
  1025. } else {
  1026. //
  1027. // We either: give it to an idle thread, create a new thread,
  1028. // or leave it in the queue.
  1029. //
  1030. if( _iIdleThreads > 0 ){
  1031. //
  1032. // There are some idle threads--trigger the event and it
  1033. // will be picked up.
  1034. //
  1035. --_iIdleThreads;
  1036. DBGMSG( DBG_THREADM,
  1037. ( "ThreadM.bJobAdded: Trigger: --iIdle %d, uActive %d\n",
  1038. _iIdleThreads, _uActiveThreads ));
  1039. //
  1040. // If we set the event, then the worker thread that receives
  1041. // this event should _not_ decrement _iIdleThreads, since
  1042. // we already did this.
  1043. //
  1044. SetEvent( _hTrigger );
  1045. } else if( _uActiveThreads < _uMaxThreads || bRunNow ){
  1046. //
  1047. // No idle threads, but we can create a new one since we
  1048. // haven't reached the limit, or the bRunNow flag is set.
  1049. //
  1050. Lock();
  1051. hThread = TSafeThread::Create( NULL,
  1052. 0,
  1053. xdwThreadProc,
  1054. this,
  1055. 0,
  1056. &dwThreadId );
  1057. if( hThread ){
  1058. CloseHandle( hThread );
  1059. //
  1060. // We have successfully created a thread; up the
  1061. // count.
  1062. //
  1063. ++_uActiveThreads;
  1064. //
  1065. // We have less active threads than the max; create a new one.
  1066. //
  1067. DBGMSG( DBG_THREADM,
  1068. ( "ThreadM.bJobAdded: ct: iIdle %d, ++uActive %d\n",
  1069. _iIdleThreads,
  1070. _uActiveThreads ));
  1071. } else {
  1072. Unlock();
  1073. rc = FALSE;
  1074. DBGMSG( DBG_THREADM | DBG_WARN,
  1075. ( "ThreadM.bJobAdded: unable to ct %d\n",
  1076. GetLastError( )));
  1077. }
  1078. } else {
  1079. //
  1080. // No idle threads, and we are already at the max so we
  1081. // can't create new threads. Dec iIdleThreads anyway
  1082. // (may go negative, but that's ok).
  1083. //
  1084. // iIdleThreads represents the number of threads that
  1085. // are currently not processing jobs. If the number is
  1086. // negative, this indicates that even if a thread suddenly
  1087. // completes a job and would go idle, there is a queued
  1088. // job that would immediately grab it, so the thread really
  1089. // didn't go into an idle state.
  1090. //
  1091. // The negative number indicates the number of outstanding
  1092. // jobs that are queued (e.g., -5 indicate 5 jobs queued).
  1093. //
  1094. // There is always an increment of iIdleThreads when a
  1095. // job is compeleted.
  1096. //
  1097. --_iIdleThreads;
  1098. //
  1099. // No threads idle, and at max threads.
  1100. //
  1101. DBGMSG( DBG_THREADM,
  1102. ( "ThreadM.bJobAdded: wait: --iIdle %d, uActive %d\n",
  1103. _iIdleThreads,
  1104. _uActiveThreads ));
  1105. }
  1106. //
  1107. // If we succeeded and bRunNow is set, this indicates that
  1108. // we were able to start a special thread, so we need to adjust
  1109. // the maximum number of threads. When a this special thread
  1110. // job completes, we will decrement it.
  1111. //
  1112. if( bRunNow && rc ){
  1113. ++_uMaxThreads;
  1114. ++_uRunNowThreads;
  1115. }
  1116. }
  1117. return rc;
  1118. }
  1119. /********************************************************************
  1120. Private routines.
  1121. ********************************************************************/
  1122. TThreadM::
  1123. ~TThreadM(
  1124. VOID
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. Destroy the thread manager object. This is private; to request
  1129. that the thread manager quit, call vDelete().
  1130. Arguments:
  1131. Return Value:
  1132. --*/
  1133. {
  1134. SPLASSERT( _State.bBit( kDestroyReq ));
  1135. if( _State.bBit( kPrivateCritSec )){
  1136. SPLASSERT( _pCritSec->bOutside( ));
  1137. delete _pCritSec;
  1138. }
  1139. if( _hTrigger )
  1140. CloseHandle( _hTrigger );
  1141. }
  1142. DWORD
  1143. TThreadM::
  1144. xdwThreadProc(
  1145. LPVOID pVoid
  1146. )
  1147. /*++
  1148. Routine Description:
  1149. Worker thread routine that calls the client to process the jobs.
  1150. Arguments:
  1151. pVoid - pTMStateVar
  1152. Return Value:
  1153. Ignored.
  1154. --*/
  1155. {
  1156. TThreadM* pThreadM = (TThreadM*)pVoid;
  1157. DWORD dwExitCode = pThreadM->dwThreadProc();
  1158. pThreadM->Unlock(); // release
  1159. return dwExitCode;
  1160. }
  1161. DWORD
  1162. TThreadM::
  1163. dwThreadProc(
  1164. VOID
  1165. )
  1166. {
  1167. CCSLock::Locker CSL( *_pCritSec );
  1168. DBGMSG( DBG_THREADM,
  1169. ( "ThreadM.dwThreadProc: ct: iIdle %d, uActive %d\n",
  1170. _iIdleThreads,
  1171. _uActiveThreads));
  1172. PJOB pJob = pThreadMJobNext();
  1173. while( TRUE ){
  1174. for( ; pJob; pJob=pThreadMJobNext( )){
  1175. //
  1176. // If bRunNow count is non-zero, this indicates that we just
  1177. // picked up a RunNow job. As soon as it completes, we
  1178. // can decrement the count.
  1179. //
  1180. BOOL bRunNowCompleted = _uRunNowThreads > 0;
  1181. {
  1182. _pCritSec->Unlock();
  1183. //
  1184. // Call back to client to process the job.
  1185. //
  1186. DBGMSG( DBG_THREADM,
  1187. ( "ThreadM.dwThreadProc: %x processing\n",
  1188. (ULONG_PTR)pJob ));
  1189. //
  1190. // Call through virtual function to process the
  1191. // user's job.
  1192. //
  1193. vThreadMJobProcess( pJob );
  1194. DBGMSG( DBG_THREADM,
  1195. ( "ThreadM.dwThreadProc: %x processing done\n",
  1196. (ULONG_PTR)pJob ));
  1197. // aquire the CS again
  1198. _pCritSec->Lock();
  1199. }
  1200. //
  1201. // If a RunNow job has been completed, then decrement both
  1202. // counts. uMaxThreads was increased by one when the job was
  1203. // accepted, so now it must be lowered.
  1204. //
  1205. if( bRunNowCompleted ){
  1206. --_uMaxThreads;
  1207. --_uRunNowThreads;
  1208. }
  1209. ++_iIdleThreads;
  1210. DBGMSG( DBG_THREADM,
  1211. ( "ThreadM.dwThreadProc: ++iIdle %d, uActive %d\n",
  1212. _iIdleThreads,
  1213. _uActiveThreads ));
  1214. }
  1215. DBGMSG( DBG_THREADM,
  1216. ( "ThreadM.dwThreadProc: Sleep: iIdle %d, uActive %d\n",
  1217. _iIdleThreads,
  1218. _uActiveThreads ));
  1219. {
  1220. _pCritSec->Unlock();
  1221. //
  1222. // Done, now relax and go idle for a bit. We don't
  1223. // care whether we timeout or get triggered; in either
  1224. // case we check for another job.
  1225. //
  1226. WaitForSingleObject( _hTrigger, _uIdleLife );
  1227. // aquire the CS again
  1228. _pCritSec->Lock();
  1229. }
  1230. //
  1231. // We must check here instead of relying on the return value
  1232. // of WaitForSingleObject since someone may see iIdleThreads!=0
  1233. // and set the trigger, but we timeout before it gets set.
  1234. //
  1235. pJob = pThreadMJobNext();
  1236. if( pJob ){
  1237. DBGMSG( DBG_THREADM,
  1238. ( "ThreadM.dwThreadProc: Woke and found job: iIdle %d, uActive %d\n",
  1239. _iIdleThreads,
  1240. _uActiveThreads ));
  1241. } else {
  1242. //
  1243. // No jobs found; break. Be sure to reset the hTrigger, since
  1244. // there are no waiting jobs, and the main thread might
  1245. // have set it in the following case:
  1246. //
  1247. // MainThread: WorkerThread:
  1248. // Sleeping
  1249. // Awoke, not yet in CS.
  1250. // GotJob
  1251. // SetEvent
  1252. // --iIdleThreads
  1253. // Enter CS, found job, process it.
  1254. //
  1255. // In this case, the event is set, but there is no thread
  1256. // to pick it up.
  1257. //
  1258. ResetEvent( _hTrigger );
  1259. break;
  1260. }
  1261. }
  1262. //
  1263. // Decrement ActiveThreads. This was incremented when the thread
  1264. // was successfully created, and should be decremented when the thread
  1265. // is about to exit.
  1266. //
  1267. --_uActiveThreads;
  1268. //
  1269. // The thread enters an idle state right before it goes to sleep.
  1270. //
  1271. // When a job is added, the idle count is decremented by the main
  1272. // thread, so the worker thread doesn't decrement it (avoids sync
  1273. // problems). If the worker thread timed out and there were no jobs,
  1274. // then we need to decrement the matching initial increment here.
  1275. //
  1276. --_iIdleThreads;
  1277. DBGMSG( DBG_THREADM,
  1278. ( "ThreadM.dwThreadProc: dt: --iIdle %d, --uActive %d\n",
  1279. _iIdleThreads,
  1280. _uActiveThreads));
  1281. return 0;
  1282. }
  1283. ///////////////////////////////////////////////////
  1284. // @@file@@ exec.cxx
  1285. ///////////////////////////////////////////////////
  1286. /*++
  1287. Copyright (c) 1994 Microsoft Corporation
  1288. All rights reserved.
  1289. Module Name:
  1290. exec.cxx
  1291. Abstract:
  1292. Handles async commands.
  1293. The client give TExec a worker object (MExecWork). At some later
  1294. time, the worker is given a thread (called via svExecute).
  1295. If the Job is already on the list but is waiting, we just return.
  1296. If it's not on the list but currently executing, we add it to the
  1297. list when it's done executing.
  1298. kExecActive -> currently executing (so it's not on the list)
  1299. kExecActiveReq -> kExecActive is on, and it needs to run again.
  1300. If kExecExit is added, we call vExecExitComplete() (virtual function)
  1301. when all jobs have been completed and assume the the client is cleaning
  1302. up after itself. In fact, the MExecWork object may be destroyed
  1303. in vExecExitComplete().
  1304. Author:
  1305. Albert Ting (AlbertT) 8-Nov-1994
  1306. Revision History:
  1307. --*/
  1308. BOOL
  1309. TExec::
  1310. bJobAdd(
  1311. MExecWork* pExecWork,
  1312. STATEVAR StateVar
  1313. )
  1314. /*++
  1315. Routine Description:
  1316. Adds a job request to move to a given state.
  1317. Arguments:
  1318. pExecWork - Work structure.
  1319. StateVar - StateVar that we want to move toward. If kExecExit
  1320. is set, then we will complete the currently executing job
  1321. then exit by calling vExecExitComplete().
  1322. Note that kExecExit should be added by itself; if it is added
  1323. with other commands, they will be ignored.
  1324. Return Value:
  1325. TRUE = Job added (or job already on wait list)
  1326. FALSE = failed, GLE.
  1327. Adding kExecExit is guarenteed to succeed here.
  1328. --*/
  1329. {
  1330. BOOL bReturn = TRUE;
  1331. BOOL bCallExecExitComplete = FALSE;
  1332. {
  1333. CCSLock::Locker CSL( *_pCritSec );
  1334. DBGMSG( DBG_EXEC,
  1335. ( "Exec.bJobAdd: %x StateVar = %x\n", pExecWork, StateVar ));
  1336. //
  1337. // Job bits must not have PRIVATE bits.
  1338. //
  1339. SPLASSERT( !( StateVar & kExecPrivate ));
  1340. //
  1341. // Don't allow adding a job after we are set to exit.
  1342. //
  1343. SPLASSERT( !( pExecWork->_State & kExecExit ));
  1344. //
  1345. // If it's active (currently executing in a thread), then it is
  1346. // not on the wait list and we mark it as ACTIVE_REQ so that
  1347. // when the job completes, it sees that more jobs have accumulated.
  1348. //
  1349. if( pExecWork->_State & kExecActive ){
  1350. DBGMSG( DBG_EXEC,
  1351. ( "\n ACTIVE, ++REQ _State %x _StatePending %x\n",
  1352. (STATEVAR)pExecWork->_State,
  1353. (STATEVAR)pExecWork->_StatePending ));
  1354. //
  1355. // Can't be an immediate request if executing already.
  1356. //
  1357. SPLASSERT( !( StateVar & kExecRunNow ));
  1358. pExecWork->_StatePending |= StateVar;
  1359. pExecWork->_State |= kExecActiveReq;
  1360. bReturn = TRUE;
  1361. } else {
  1362. //
  1363. // Store up the work requested since we aren't currently active.
  1364. //
  1365. pExecWork->_State |= StateVar;
  1366. //
  1367. // If we are not on the wait list, add it.
  1368. //
  1369. if( !pExecWork->Work_bLinked( )){
  1370. if( StateVar & kExecExit ){
  1371. bCallExecExitComplete = TRUE;
  1372. } else {
  1373. DBGMSG( DBG_EXEC, ( "not linked, added\n" ));
  1374. SPLASSERT( NULL == Work_pFind( pExecWork ));
  1375. bReturn = bJobAddWorker( pExecWork );
  1376. }
  1377. } else {
  1378. DBGMSG( DBG_EXEC, ( "linked, NOP\n" ));
  1379. }
  1380. }
  1381. }
  1382. if( bCallExecExitComplete ){
  1383. //
  1384. // Special case exit: we should exit. Once we call
  1385. // vExecExitComplete, we can't refer to *this anymore,
  1386. // since we may have deleted ourself.
  1387. //
  1388. pExecWork->vExecExitComplete();
  1389. bReturn = TRUE;
  1390. }
  1391. return bReturn;
  1392. }
  1393. VOID
  1394. TExec::
  1395. vJobDone(
  1396. MExecWork* pExecWork,
  1397. STATEVAR StateVar
  1398. )
  1399. /*++
  1400. Routine Description:
  1401. A job has compeleted execution, clean up.
  1402. Arguments:
  1403. pExecWork - Unit that just completed executing.
  1404. StateVar - New state that the object is in (requests that
  1405. successfully completed should be turned off--done by client).
  1406. Return Value:
  1407. --*/
  1408. {
  1409. BOOL bCallExecExitComplete = FALSE;
  1410. BOOL bCallExecFailedAddJob = FALSE;
  1411. {
  1412. CCSLock::Locker CSL( *_pCritSec );
  1413. DBGMSG( DBG_EXEC,
  1414. ( "Exec.vJobDone: %x completed -> %x +(new) %x = %x\n",
  1415. pExecWork, StateVar, (DWORD)pExecWork->_StatePending,
  1416. (DWORD)pExecWork->_State | pExecWork->_StatePending ));
  1417. //
  1418. // kExecRunNow can not be set when the object is working.
  1419. //
  1420. SPLASSERT( !( StateVar & kExecRunNow ));
  1421. //
  1422. // We have completed the work request, put in the new state.
  1423. // Keep the private bits, and add in the new state variable,
  1424. // plus any additional work that was pending.
  1425. //
  1426. // The ExecNow bit is not saved (it's not part of kExecPrivate)
  1427. // since it's good for one shot only.
  1428. //
  1429. pExecWork->_State = ( pExecWork->_State & kExecPrivate ) |
  1430. ( StateVar & ~kExecPrivate ) |
  1431. pExecWork->_StatePending;
  1432. pExecWork->_State &= ~kExecActive;
  1433. //
  1434. // If job is done, then quit.
  1435. //
  1436. if( pExecWork->_State & kExecExit ){
  1437. DBGMSG( DBG_EXEC,
  1438. ( "Exec.vJobDone: _State %x, calling vExecExitComplete\n",
  1439. (STATEVAR)pExecWork->_State ));
  1440. bCallExecExitComplete = TRUE;
  1441. } else {
  1442. //
  1443. // If we have more work to do, add ourselves back
  1444. // to the queue.
  1445. //
  1446. if( pExecWork->_State & kExecActiveReq &&
  1447. !bJobAddWorker( pExecWork )){
  1448. bCallExecFailedAddJob = TRUE;
  1449. }
  1450. }
  1451. }
  1452. if( bCallExecFailedAddJob ){
  1453. //
  1454. // Fail on delayed job add.
  1455. //
  1456. pExecWork->vExecFailedAddJob();
  1457. }
  1458. if( bCallExecExitComplete ){
  1459. //
  1460. // Once vExecExitComplete has been called, the current object
  1461. // pExecWork may be destroyed.
  1462. //
  1463. // Don't refer to it again since vExecExitComplete may delete
  1464. // this as part of cleanup.
  1465. //
  1466. pExecWork->vExecExitComplete();
  1467. }
  1468. }
  1469. STATEVAR
  1470. TExec::
  1471. svClearPendingWork(
  1472. MExecWork* pExecWork
  1473. )
  1474. /*++
  1475. Routine Description:
  1476. Queries what work is currently pending.
  1477. Arguments:
  1478. pExecWork -- Work item.
  1479. Return Value:
  1480. --*/
  1481. {
  1482. CCSLock::Locker CSL( *_pCritSec );
  1483. //
  1484. // Return pending work, minus the private and kExecRunNow
  1485. // bits.
  1486. //
  1487. STATEVAR svPendingWork = pExecWork->_StatePending & ~kExecNoOutput;
  1488. pExecWork->_StatePending = 0;
  1489. return svPendingWork;
  1490. }
  1491. /********************************************************************
  1492. Private
  1493. ********************************************************************/
  1494. TExec::
  1495. TExec(
  1496. CCSLock* pCritSec
  1497. ) : TThreadM( 10, 2000, pCritSec ), _pCritSec( pCritSec )
  1498. {
  1499. }
  1500. BOOL
  1501. TExec::
  1502. bJobAddWorker(
  1503. MExecWork* pExecWork
  1504. )
  1505. /*++
  1506. Routine Description:
  1507. Common code to add a job to our linked list.
  1508. Must be called inside the _pCritSec. It does leave it inside
  1509. this function, however.
  1510. Arguments:
  1511. Return Value:
  1512. --*/
  1513. {
  1514. SPLASSERT( _pCritSec->bInside( ));
  1515. BOOL bRunNow = FALSE;
  1516. //
  1517. // Check if the client wants the job to run right now.
  1518. //
  1519. if( pExecWork->_State & kExecRunNow ){
  1520. //
  1521. // Add the job to the head of the queue. Since we always pull
  1522. // jobs from the beginning, we'll get to this job first.
  1523. //
  1524. // If a non-RunNow job is added to the list before we execute,
  1525. // we'll still run, since the other job will be added to the
  1526. // end of the list.
  1527. //
  1528. // If another RunNow job is added, we'll spawn separate threads
  1529. // for each (unless an idle thread is available).
  1530. //
  1531. Work_vAdd( pExecWork );
  1532. bRunNow = TRUE;
  1533. } else {
  1534. Work_vAppend( pExecWork );
  1535. }
  1536. if( !bJobAdded( bRunNow ) ){
  1537. DBGMSG( DBG_INFO, ( "Exec.vJobProcess: unable to add job %x: %d\n",
  1538. pExecWork,
  1539. GetLastError( )));
  1540. Work_vDelink( pExecWork );
  1541. return FALSE;
  1542. }
  1543. return TRUE;
  1544. }
  1545. PJOB
  1546. TExec::
  1547. pThreadMJobNext(
  1548. VOID
  1549. )
  1550. /*++
  1551. Routine Description:
  1552. Gets the next job from the queue. This function is defined in
  1553. TThreadM.
  1554. Arguments:
  1555. Return Value:
  1556. --*/
  1557. {
  1558. CCSLock::Locker CSL( *_pCritSec );
  1559. MExecWork* pExecWork = Work_pHead();
  1560. if( !pExecWork ){
  1561. return NULL;
  1562. }
  1563. Work_vDelink( pExecWork );
  1564. //
  1565. // Job should never be active here.
  1566. //
  1567. SPLASSERT( !(pExecWork->_State & kExecActive) );
  1568. //
  1569. // We will handle all requests now, so clear kExecActiveReq.
  1570. // Also remove kExecRunNow, since it's one shot only, and mark us
  1571. // as currently active (kExecActive).
  1572. //
  1573. pExecWork->_State &= ~( kExecActiveReq | kExecRunNow );
  1574. pExecWork->_State |= kExecActive;
  1575. return (PJOB)pExecWork;
  1576. }
  1577. VOID
  1578. TExec::
  1579. vThreadMJobProcess(
  1580. PJOB pJob
  1581. )
  1582. /*++
  1583. Routine Description:
  1584. Process a job in the current thread. We call the virtual function
  1585. with the job object, then clear out the bits that it has completed.
  1586. (This is a member of TThreadM.)
  1587. If there is additional pending work (ACTIVE_REQ), then we re-add
  1588. the job.
  1589. If there is a failure in the re-add case, we must send an
  1590. asynchronous fail message.
  1591. Arguments:
  1592. pJob - MExecWork instance.
  1593. Return Value:
  1594. --*/
  1595. {
  1596. SPLASSERT( _pCritSec->bOutside( ));
  1597. STATEVAR StateVar;
  1598. MExecWork* pExecWork = (MExecWork*)pJob;
  1599. //
  1600. // Do the work.
  1601. //
  1602. StateVar = pExecWork->svExecute( pExecWork->State() & ~kExecNoOutput );
  1603. vJobDone( pExecWork, StateVar );
  1604. }
  1605. ///////////////////////////////////////////////////
  1606. // @@file@@ bitarray.cxx
  1607. ///////////////////////////////////////////////////
  1608. /********************************************************************
  1609. Bit Array class
  1610. ********************************************************************/
  1611. TBitArray::
  1612. TBitArray(
  1613. IN UINT nBits,
  1614. IN UINT uGrowSize
  1615. ) : _nBits( nBits ),
  1616. _pBits( NULL ),
  1617. _uGrowSize( uGrowSize )
  1618. {
  1619. DBGMSG( DBG_TRACE, ( "TBitArray::ctor\n" ) );
  1620. //
  1621. // If the initial number of bits is not specified then
  1622. // create a default bit array size.
  1623. //
  1624. if( !_nBits )
  1625. {
  1626. _nBits = kBitsInType;
  1627. }
  1628. //
  1629. // This could fail, thus leaving the bit array
  1630. // in an invalid state, Note _pBits being true is
  1631. // the bValid check.
  1632. //
  1633. _pBits = new Type [ nBitsToType( _nBits ) ];
  1634. if( _pBits )
  1635. {
  1636. //
  1637. // The grow size should be at least the
  1638. // number of bits in the type.
  1639. //
  1640. if( _uGrowSize < kBitsInType )
  1641. {
  1642. _uGrowSize = kBitsInType;
  1643. }
  1644. //
  1645. // Clear all the bits.
  1646. //
  1647. memset( _pBits, 0, nBitsToType( _nBits ) * sizeof( Type ) );
  1648. }
  1649. }
  1650. TBitArray::
  1651. TBitArray(
  1652. const TBitArray &rhs
  1653. ) : _nBits( kBitsInType ),
  1654. _pBits( NULL )
  1655. {
  1656. DBGMSG( DBG_TRACE, ( "TBitArray::copy_ctor\n" ) );
  1657. bClone( rhs );
  1658. }
  1659. const TBitArray &
  1660. TBitArray::
  1661. operator =(
  1662. const TBitArray &rhs
  1663. )
  1664. {
  1665. DBGMSG( DBG_TRACE, ( "TBitArray::operator =\n" ) );
  1666. bClone( rhs );
  1667. return *this;
  1668. }
  1669. TBitArray::
  1670. ~TBitArray(
  1671. VOID
  1672. )
  1673. {
  1674. DBGMSG( DBG_TRACE, ( "TBitArray::dtor\n" ) );
  1675. delete [] _pBits;
  1676. }
  1677. BOOL
  1678. TBitArray::
  1679. bValid(
  1680. VOID
  1681. ) const
  1682. {
  1683. return _pBits != NULL;
  1684. }
  1685. BOOL
  1686. TBitArray::
  1687. bToString(
  1688. IN TString &strBits
  1689. ) const
  1690. {
  1691. BOOL bStatus = bValid();
  1692. if( bStatus )
  1693. {
  1694. TString strString;
  1695. strBits.bUpdate( NULL );
  1696. //
  1697. // Get the upper bound bit.
  1698. //
  1699. UINT uIndex = _nBits - 1;
  1700. //
  1701. // Print the array in reverse order to make the bit array
  1702. // appear as one large binary number.
  1703. //
  1704. for( UINT i = 0; i < _nBits; i++, uIndex-- )
  1705. {
  1706. strString.bFormat( TEXT( "%d" ), bRead( uIndex ) );
  1707. strBits.bCat( strString );
  1708. }
  1709. bStatus = strBits.bValid();
  1710. }
  1711. return bStatus;
  1712. }
  1713. BOOL
  1714. TBitArray::
  1715. bRead(
  1716. IN UINT Bit
  1717. ) const
  1718. {
  1719. BOOL bStatus = bIsValidBit( Bit );
  1720. if( bStatus )
  1721. {
  1722. bStatus = _pBits[BitToIndex( Bit )] & BitToMask( Bit ) ? TRUE : FALSE;
  1723. }
  1724. return bStatus;
  1725. }
  1726. BOOL
  1727. TBitArray::
  1728. bSet(
  1729. IN UINT Bit
  1730. )
  1731. {
  1732. BOOL bStatus = bIsValidBit( Bit );
  1733. if( bStatus )
  1734. {
  1735. _pBits[BitToIndex( Bit )] |= BitToMask( Bit );
  1736. }
  1737. return bStatus;
  1738. }
  1739. BOOL
  1740. TBitArray::
  1741. bReset(
  1742. IN UINT Bit
  1743. )
  1744. {
  1745. BOOL bStatus = bIsValidBit( Bit );
  1746. if( bStatus )
  1747. {
  1748. _pBits[BitToIndex( Bit )] &= ~BitToMask( Bit );
  1749. }
  1750. return bStatus;
  1751. }
  1752. BOOL
  1753. TBitArray::
  1754. bToggle(
  1755. IN UINT Bit
  1756. )
  1757. {
  1758. BOOL bStatus = bIsValidBit( Bit );
  1759. if( bStatus )
  1760. {
  1761. _pBits[BitToIndex( Bit )] ^= BitToMask( Bit );
  1762. }
  1763. return bStatus;
  1764. }
  1765. //
  1766. // Add one new bit to the end of the bit array.
  1767. // If multiple bits need to be added the user of the
  1768. // class should call this routine repeatedly.
  1769. //
  1770. BOOL
  1771. TBitArray::
  1772. bAdd(
  1773. VOID
  1774. )
  1775. {
  1776. BOOL bStatus = FALSE;
  1777. UINT Bit = _nBits + 1;
  1778. //
  1779. // Check if there is room in the array for one more bit.
  1780. //
  1781. if( Bit <= nBitsToType( _nBits ) * kBitsInType )
  1782. {
  1783. //
  1784. // Update the current bit count and return true.
  1785. //
  1786. _nBits = Bit;
  1787. bStatus = TRUE;
  1788. }
  1789. else
  1790. {
  1791. //
  1792. // Grow the bit array.
  1793. //
  1794. bStatus = bGrow( Bit );
  1795. }
  1796. return bStatus;
  1797. }
  1798. VOID
  1799. TBitArray::
  1800. vSetAll(
  1801. VOID
  1802. )
  1803. {
  1804. for( UINT i = 0; i < _nBits; i++ )
  1805. {
  1806. bSet( i );
  1807. }
  1808. }
  1809. VOID
  1810. TBitArray::
  1811. vResetAll(
  1812. VOID
  1813. )
  1814. {
  1815. for( UINT i = 0; i < _nBits; i++ )
  1816. {
  1817. bReset( i );
  1818. }
  1819. }
  1820. UINT
  1821. TBitArray::
  1822. uNumBits(
  1823. VOID
  1824. ) const
  1825. {
  1826. return _nBits;
  1827. }
  1828. BOOL
  1829. TBitArray::
  1830. bFindNextResetBit(
  1831. IN UINT *puNextFreeBit
  1832. )
  1833. {
  1834. BOOL bStatus = bValid();
  1835. if( bStatus )
  1836. {
  1837. BOOL bFound = FALSE;
  1838. //
  1839. // Locate the first type that contains at least one cleared bit.
  1840. //
  1841. for( UINT i = 0; i < nBitsToType( _nBits ); i++ )
  1842. {
  1843. if( _pBits[i] != kBitsInTypeMask )
  1844. {
  1845. //
  1846. // Search for the bit that is cleared.
  1847. //
  1848. for( UINT j = 0; j < kBitsInType; j++ )
  1849. {
  1850. if( !( _pBits[i] & BitToMask( j ) ) )
  1851. {
  1852. *puNextFreeBit = i * kBitsInType + j;
  1853. bFound = TRUE;
  1854. break;
  1855. }
  1856. }
  1857. }
  1858. //
  1859. // Free bit found terminate the search.
  1860. //
  1861. if( bFound )
  1862. {
  1863. break;
  1864. }
  1865. }
  1866. //
  1867. // Free bit was not found then grow the bit array
  1868. //
  1869. if( !bFound )
  1870. {
  1871. //
  1872. // Assume a new bit will be added.
  1873. //
  1874. *puNextFreeBit = uNumBits();
  1875. //
  1876. // Add a new bit.
  1877. //
  1878. bStatus = bAdd();
  1879. }
  1880. }
  1881. return bStatus;
  1882. }
  1883. /********************************************************************
  1884. Bit Array - private member functions.
  1885. ********************************************************************/
  1886. BOOL
  1887. TBitArray::
  1888. bClone(
  1889. const TBitArray &rhs
  1890. )
  1891. {
  1892. BOOL bStatus = FALSE;
  1893. if( this == &rhs )
  1894. {
  1895. bStatus = TRUE;
  1896. }
  1897. else
  1898. {
  1899. Type *pTempBits = new Type [ nBitsToType( _nBits ) ];
  1900. if( pTempBits )
  1901. {
  1902. memcpy( pTempBits, rhs._pBits, nBitsToType( _nBits ) * sizeof( Type ) );
  1903. delete [] _pBits;
  1904. _pBits = pTempBits;
  1905. _nBits = rhs._nBits;
  1906. bStatus = TRUE;
  1907. }
  1908. }
  1909. return bStatus;
  1910. }
  1911. BOOL
  1912. TBitArray::
  1913. bGrow(
  1914. IN UINT uBits
  1915. )
  1916. {
  1917. DBGMSG( DBG_TRACE, ( "TBitArray::bGrow\n" ) );
  1918. BOOL bStatus = FALSE;
  1919. UINT uNewBits = uBits + _uGrowSize;
  1920. DBGMSG( DBG_TRACE, ( "Grow to size %d Original size %d Buffer pointer %x\n", uNewBits, _nBits, _pBits ) );
  1921. //
  1922. // We do support reducing the size of the bit array.
  1923. //
  1924. SPLASSERT( uNewBits > _nBits );
  1925. //
  1926. // Allocate the enlarged bit array.
  1927. //
  1928. Type *pNewBits = new Type [ nBitsToType( uNewBits ) ];
  1929. if( pNewBits )
  1930. {
  1931. //
  1932. // Clear the new bits.
  1933. //
  1934. memset( pNewBits, 0, nBitsToType( uNewBits ) * sizeof( Type ) );
  1935. //
  1936. // Copy the old bits to the new bit array.
  1937. //
  1938. memcpy( pNewBits, _pBits, nBitsToType( _nBits ) * sizeof( Type ) );
  1939. //
  1940. // Release the old bit array and save the new pointer and size.
  1941. //
  1942. delete [] _pBits;
  1943. _pBits = pNewBits;
  1944. _nBits = uBits;
  1945. //
  1946. // Success.
  1947. //
  1948. bStatus = TRUE;
  1949. }
  1950. DBGMSG( DBG_TRACE, ( "New size %d Buffer pointer %x\n", _nBits, _pBits ) );
  1951. return bStatus;
  1952. }
  1953. UINT
  1954. TBitArray::
  1955. nBitsToType(
  1956. IN UINT uBits
  1957. ) const
  1958. {
  1959. return ( uBits + kBitsInType - 1 ) / kBitsInType;
  1960. }
  1961. TBitArray::Type
  1962. TBitArray::
  1963. BitToMask(
  1964. IN UINT uBit
  1965. ) const
  1966. {
  1967. return 1 << ( uBit % kBitsInType );
  1968. }
  1969. UINT
  1970. TBitArray::
  1971. BitToIndex(
  1972. IN UINT uBit
  1973. ) const
  1974. {
  1975. return uBit / kBitsInType;
  1976. }
  1977. BOOL
  1978. TBitArray::
  1979. bIsValidBit(
  1980. IN UINT uBit
  1981. ) const
  1982. {
  1983. BOOL bStatus = ( uBit < _nBits ) && bValid();
  1984. if( !bStatus )
  1985. {
  1986. DBGMSG( DBG_TRACE, ( "Invalid bit value %d\n", uBit ) );
  1987. }
  1988. return bStatus;
  1989. }
  1990. ///////////////////////////////////////////////////
  1991. // @@file@@ loadlib.cxx
  1992. ///////////////////////////////////////////////////
  1993. TLibrary::
  1994. TLibrary(
  1995. LPCTSTR pszLibName
  1996. )
  1997. {
  1998. _hInst = LoadLibrary( pszLibName );
  1999. if( !_hInst )
  2000. {
  2001. DBGMSG( DBG_WARN, ( "Library.ctr: unable to load "TSTR"\n", pszLibName ));
  2002. }
  2003. }
  2004. TLibrary::
  2005. ~TLibrary(
  2006. )
  2007. {
  2008. if( bValid() )
  2009. {
  2010. FreeLibrary( _hInst );
  2011. }
  2012. }
  2013. BOOL
  2014. TLibrary::
  2015. bValid(
  2016. VOID
  2017. ) const
  2018. {
  2019. return _hInst != NULL;
  2020. }
  2021. FARPROC
  2022. TLibrary::
  2023. pfnGetProc(
  2024. IN LPCSTR pszProc
  2025. ) const
  2026. {
  2027. FARPROC fpProc = bValid() ? GetProcAddress( _hInst, pszProc ) : NULL;
  2028. if( !fpProc )
  2029. {
  2030. DBGMSG( DBG_WARN, ( "Library.pfnGetProc: failed %s\n", pszProc ));
  2031. }
  2032. return fpProc;
  2033. }
  2034. FARPROC
  2035. TLibrary::
  2036. pfnGetProc(
  2037. IN UINT uOrdinal
  2038. ) const
  2039. {
  2040. FARPROC fpProc = bValid() ? GetProcAddress( _hInst, (LPCSTR)MAKELPARAM( uOrdinal, 0 ) ) : NULL;
  2041. if( !fpProc )
  2042. {
  2043. DBGMSG( DBG_WARN, ( "Library.pfnGetProc: failed %d\n", uOrdinal ));
  2044. }
  2045. return fpProc;
  2046. }
  2047. HINSTANCE
  2048. TLibrary::
  2049. hInst(
  2050. VOID
  2051. ) const
  2052. {
  2053. return _hInst;
  2054. }