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.

398 lines
9.6 KiB

  1. //=================================================================
  2. //
  3. // ResourceManager.cpp
  4. //
  5. // Copyright (c) 1998-2002 Microsoft Corporation, All Rights Reserved
  6. //
  7. //=================================================================
  8. /*
  9. * Currently the implementations of std::_Lockit::_Lockit() are in framedyn.dll
  10. * If this class is being used outside the scope of win32providers then an implementation of std::_Lockit::_Lockit() has to be provided
  11. * by the client ( I think!) .
  12. */
  13. #include "precomp.h"
  14. #include <assertbreak.h>
  15. #include "ResourceManager.h"
  16. #include "ProvExce.h"
  17. #include <comdef.h>
  18. #include "TimerQueue.h"
  19. // automatic crit sec
  20. #include "cautolock.h"
  21. //
  22. // resource management failures
  23. //
  24. BOOL bAddInstanceCreatorFailure = FALSE ;
  25. //initialize statics
  26. /*
  27. * All the resources not released by clients or cached in the ResourceManager are forcibly freed in the ResourceManager destructor.
  28. * When a resource is freed , the resource tries to deregister the timeout rule from the TimerQueue, which means that the TimerQueue
  29. * has to be present when the ResourceManager destructor is fired,else we'll have a crash on Win9x. --RAID 50454
  30. */
  31. //CTimerQueue CTimerQueue :: s_TimerQueue ;
  32. //CResourceManager CResourceManager::sm_TheResourceManager ;
  33. CResourceManager :: CResourceManager ()
  34. {
  35. }
  36. CResourceManager :: ~CResourceManager ()
  37. {
  38. std::list < CResourceList* >::iterator pInstanceList ;
  39. /*
  40. * Ideally, at this point of time when the global destructors get fired there should not be any resources in the resource manager,
  41. * but if there are any , we've to forcibly delete them. We're safe in doing this becuase the scheduler thread would've exited already
  42. * in DllCanUnloadNow & no other thread would be calling into the resource manager
  43. */
  44. LogMessage ( L"Entering ~CResourceManager" ) ;
  45. CAutoLock cs ( m_csResourceManager ) ;
  46. while ( !m_Resources.empty () )
  47. {
  48. delete m_Resources.front() ;
  49. m_Resources.pop_front() ;
  50. }
  51. cs.Exec () ;
  52. LogMessage ( L"Leaving ~CResourceManager" ) ;
  53. }
  54. /*
  55. * This method checks if we've any resource leak
  56. */
  57. void CResourceManager :: ForcibleCleanUp ()
  58. {
  59. LogMessage ( L"Entering CResourceManager :: ForcibleCleanUp" ) ;
  60. std::list < CResourceList* >::iterator pInstanceList ;
  61. CAutoLock cs ( m_csResourceManager ) ;
  62. for ( pInstanceList = m_Resources.begin () ; pInstanceList != m_Resources.end () ; pInstanceList++ )
  63. {
  64. ( *pInstanceList )->ShutDown () ;
  65. }
  66. cs.Exec () ;
  67. LogMessage ( L"Leaving CResourceManager :: ForcibleCleanUp" ) ;
  68. }
  69. CResource* CResourceManager :: GetResource ( GUID ResourceId, PVOID pData )
  70. {
  71. std::list < CResourceList* >::iterator pInstanceList ;
  72. for ( pInstanceList = m_Resources.begin () ; pInstanceList != m_Resources.end () ; pInstanceList++ )
  73. {
  74. if ( IsEqualGUID ( (*pInstanceList)->guidResourceId, ResourceId ) )
  75. {
  76. return (*pInstanceList)->GetResource ( pData ) ;
  77. }
  78. }
  79. return NULL ;
  80. }
  81. ULONG CResourceManager :: ReleaseResource ( GUID ResourceId, CResource* pResource )
  82. {
  83. std::list < CResourceList* >::iterator pInstanceList ;
  84. for ( pInstanceList = m_Resources.begin () ; pInstanceList != m_Resources.end () ; pInstanceList++ )
  85. {
  86. if ( IsEqualGUID ( (*pInstanceList)->guidResourceId, ResourceId ) )
  87. {
  88. return (*pInstanceList)->ReleaseResource ( pResource ) ;
  89. }
  90. }
  91. return ULONG ( -1 ) ;
  92. }
  93. BOOL CResourceManager :: AddInstanceCreator ( GUID ResourceId, PFN_RESOURCE_INSTANCE_CREATOR pfnResourceInstanceCreator )
  94. {
  95. CAutoLock cs ( m_csResourceManager ) ;
  96. //create a node & add it
  97. CResourceList *stResourceInstances = new CResourceList ;
  98. if ( stResourceInstances == NULL )
  99. {
  100. throw CHeap_Exception( CHeap_Exception::E_ALLOCATION_ERROR ) ;
  101. }
  102. stResourceInstances->guidResourceId = ResourceId ;
  103. stResourceInstances->m_pfnInstanceCreator = pfnResourceInstanceCreator ;
  104. m_Resources.push_back ( stResourceInstances ) ;
  105. return TRUE ;
  106. }
  107. CResourceList :: CResourceList ()
  108. {
  109. m_bShutDown = FALSE ;
  110. }
  111. CResourceList :: ~CResourceList ()
  112. {
  113. m_bShutDown = TRUE ;
  114. ShutDown () ;
  115. }
  116. CResource* CResourceList :: GetResource ( LPVOID pData )
  117. {
  118. CResource* pTmpInstance = NULL ;
  119. tagInstances::iterator ppInstance ;
  120. BOOL bRet ;
  121. //check if we're shutting down
  122. if ( m_bShutDown )
  123. {
  124. return NULL ;
  125. }
  126. //Lock the list
  127. CResourceListAutoLock cs ( this ) ;
  128. //check if we're shutting down
  129. if ( m_bShutDown )
  130. {
  131. return NULL ;
  132. }
  133. try
  134. {
  135. //go thru all the instances of this resource & hand out the first valid one
  136. for ( ppInstance = m_Instances.begin(); ppInstance != m_Instances.end (); ppInstance++ )
  137. {
  138. //Check out if we've cached a similar instance
  139. if ( ( *ppInstance )->IsOneOfMe ( pData ) )
  140. {
  141. //try to acquire the resource...this will up the refcount.
  142. bRet = ( *ppInstance )->Acquire () ;
  143. if ( bRet )
  144. {
  145. pTmpInstance = *ppInstance ;
  146. break ; //got the instance so break
  147. }
  148. }
  149. }
  150. //if we haven't got a cached instance to hand out, create a new instance
  151. if ( !pTmpInstance )
  152. {
  153. //this will create a new instance but the ref-count is still zero
  154. pTmpInstance = m_pfnInstanceCreator ( pData ) ;
  155. //Try to acquire the instance for the client ..which will up the ref-count
  156. if ( pTmpInstance )
  157. {
  158. if ( pTmpInstance->IsValid () )
  159. {
  160. pTmpInstance->SetParent ( this ) ;
  161. bRet = pTmpInstance->Acquire () ;
  162. //if the acquire succeeded on the instance, add it to our list of cached instances
  163. if ( bRet )
  164. {
  165. m_Instances.insert ( m_Instances.begin (), pTmpInstance ) ;
  166. }
  167. else
  168. {
  169. delete pTmpInstance ;
  170. pTmpInstance = NULL ;
  171. }
  172. }
  173. else
  174. {
  175. // set creation error as they can look for it
  176. ::SetLastError ( pTmpInstance->GetCreationError () );
  177. delete pTmpInstance ;
  178. pTmpInstance = NULL ;
  179. }
  180. }
  181. }
  182. }
  183. catch ( ... )
  184. {
  185. if ( pTmpInstance )
  186. {
  187. delete pTmpInstance ;
  188. pTmpInstance = NULL ;
  189. }
  190. throw ;
  191. }
  192. return pTmpInstance ;
  193. }
  194. ULONG CResourceList :: ReleaseResource ( CResource* pResource )
  195. {
  196. CResource* pTmpInstance = NULL ;
  197. tagInstances::iterator ppInstance ;
  198. LONG lCount = -1 ;
  199. //check if we're shutting down
  200. if ( m_bShutDown )
  201. {
  202. return NULL ;
  203. }
  204. //Lock the list
  205. CResourceListAutoLock cs ( this ) ;
  206. //check if we're shutting down
  207. if ( m_bShutDown )
  208. {
  209. return lCount ;
  210. }
  211. //Go thru the list & release the resource
  212. for ( ppInstance = m_Instances.begin(); ppInstance != m_Instances.end (); ppInstance++ )
  213. {
  214. if ( *ppInstance == pResource )
  215. {
  216. lCount = pResource->Release () ;
  217. break ;
  218. }
  219. }
  220. return lCount ;
  221. }
  222. //This function will be called by the CResource to remove it's entry from the list of instances. The resource should have a
  223. //lock on the list before it attempts to do this
  224. void CResourceList :: RemoveFromList ( CResource* pResource )
  225. {
  226. tagInstances::iterator ppInstance ;
  227. //Go thru the list & remove the link to the resource
  228. for ( ppInstance = m_Instances.begin(); ppInstance != m_Instances.end (); ppInstance++ )
  229. {
  230. if ( *ppInstance == pResource )
  231. {
  232. m_Instances.erase ( ppInstance ) ;
  233. break ;
  234. }
  235. }
  236. }
  237. void CResourceList :: ShutDown ()
  238. {
  239. CResourceListAutoLock cs ( this ) ;
  240. LPOLESTR t_pOleStr = NULL ;
  241. CHString t_chsListGuid ;
  242. if ( StringFromCLSID ( guidResourceId , &t_pOleStr ) == S_OK )
  243. {
  244. t_chsListGuid = t_pOleStr ;
  245. CoTaskMemFree ( t_pOleStr ) ;
  246. }
  247. tagInstances::iterator ppInstance ;
  248. //Go thru the list & remove the link to the resource
  249. while ( !m_Instances.empty () )
  250. {
  251. #if (defined DEBUG || defined _DEBUG)
  252. // Note that this COULD be because there is a timer rule, and the time hasn't expired
  253. // before the DllCanUnloadNow function is called by com (that's who calls this function).
  254. LogErrorMessage3 ( L"%s%s" , L"Resource not released before shutdown = " , t_chsListGuid ) ;
  255. #endif
  256. m_Instances.pop_front() ;
  257. }
  258. }
  259. CResource :: CResource () :
  260. m_bValid ( TRUE ),
  261. m_dwCreationError ( ERROR_SUCCESS )
  262. {
  263. m_pRules = NULL ;
  264. m_lRef = 0 ;
  265. m_pResources = NULL ;
  266. }
  267. CResource :: ~CResource ()
  268. {
  269. }
  270. //This function increments ref-count of the object & calls into the virtual overridables OnAcquire or OnInitialAcquire
  271. //The derived class should override these functions if it wants to & decrement the ref-count if it wants the Acquire
  272. //operation to fail
  273. BOOL CResource::Acquire ()
  274. {
  275. BOOL bRet ;
  276. ++m_lRef ;
  277. if ( m_lRef == 1 )
  278. {
  279. bRet = OnInitialAcquire () ;
  280. }
  281. else
  282. {
  283. bRet = OnAcquire () ;
  284. }
  285. if ( m_lRef == 0 )
  286. {
  287. m_pResources->RemoveFromList ( this ) ;
  288. if ( m_pRules )
  289. {
  290. //since we're going away, we detach ourselves from the rule so that the rules don't call into us
  291. m_pRules->Detach () ;
  292. m_pRules->Release () ;
  293. m_pRules = NULL ;
  294. }
  295. delete this ;
  296. //we do not want to use instance which got deleted
  297. bRet = FALSE;
  298. }
  299. return bRet ;
  300. }
  301. ULONG CResource::Release ()
  302. {
  303. BOOL bRet ;
  304. ULONG lCount = 0 ;
  305. --m_lRef ;
  306. if ( m_lRef == 0 )
  307. {
  308. bRet = OnFinalRelease () ;
  309. }
  310. else
  311. {
  312. bRet = OnRelease () ;
  313. }
  314. if ( bRet )
  315. {
  316. if ( m_lRef == 0 )
  317. {
  318. m_pResources->RemoveFromList ( this ) ;
  319. if ( m_pRules )
  320. {
  321. //since we're going away, we detach ourselves from the rule so that the rules don't call into us
  322. m_pRules->Detach () ;
  323. m_pRules->Release () ;
  324. m_pRules = NULL ;
  325. }
  326. delete this ;
  327. return lCount ;
  328. }
  329. }
  330. return m_lRef ;
  331. }
  332. /*
  333. void CResource :: RuleEvaluated ( const CRule *a_RuleEvaluated )
  334. {
  335. if ( m_pRules )
  336. {
  337. return m_pRules->CheckRule () ;
  338. }
  339. else
  340. {
  341. return FALSE ;
  342. }
  343. }
  344. */