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.

499 lines
13 KiB

  1. #include "TsunamiP.Hxx"
  2. #pragma hdrstop
  3. BOOL
  4. TsAllocate(
  5. IN const TSVC_CACHE &TSvcCache,
  6. IN ULONG cbSize,
  7. IN OUT PVOID * ppvNewBlock
  8. )
  9. {
  10. return( TsAllocateEx( TSvcCache,
  11. cbSize,
  12. ppvNewBlock,
  13. NULL ) );
  14. } // TsAllocate
  15. BOOL
  16. TsAllocateEx(
  17. IN const TSVC_CACHE &TSvcCache,
  18. IN ULONG cbSize,
  19. IN OUT PVOID * ppvNewBlock,
  20. OPTIONAL PUSER_FREE_ROUTINE pfnFreeRoutine
  21. )
  22. /*++
  23. Routine Description:
  24. This function allocates a memory block for the calling server.
  25. The returned block is suitable for use as a parameter to
  26. TsCacheDirectoryBlob(). Blocks allocated by this function
  27. must either be cached or freed with TsFree(). Freeing of
  28. cached blocks will be handled by the cache manager.
  29. Arguments:
  30. pServiceInfo - An initialized SERVICE_INFO structure.
  31. cbSize - Number of bytes to allocate. (Must be strictly
  32. greater than zero.)
  33. ppvNewBlock - Address of a pointer to store the new block's
  34. address in.
  35. Return Value:
  36. TRUE - The allocation succeeded, and *ppvNewBlock points to
  37. at least cbSize accessable bytes.
  38. FALSE - The allocation failed.
  39. --*/
  40. {
  41. PBLOB_HEADER pbhNewBlock;
  42. ASSERT( cbSize > 0 );
  43. ASSERT( ppvNewBlock != NULL );
  44. //
  45. // Set pbhNewBlock to NULL so that the exception-cleanup code
  46. // can test against it to see if an allocation occurred before
  47. // the exception.
  48. //
  49. pbhNewBlock = NULL;
  50. __try
  51. {
  52. //
  53. // If asked to allocate zero bytes, we return FALSE and NULL,
  54. // as if allocation failure had occurred.
  55. //
  56. if ( cbSize != 0 )
  57. {
  58. pbhNewBlock = ( PBLOB_HEADER )
  59. ALLOC( cbSize + sizeof( BLOB_HEADER ) );
  60. }
  61. if ( pbhNewBlock != NULL )
  62. {
  63. //
  64. // If the allocation succeeded, we return a pointer to the
  65. // memory just following the BLOB_HEADER.
  66. //
  67. *ppvNewBlock = ( PVOID )( pbhNewBlock + 1 );
  68. //
  69. // Set up the BLOB_HEADER: Normal flags and stored allocation
  70. // size.
  71. //
  72. pbhNewBlock->IsCached = FALSE;
  73. pbhNewBlock->pfnFreeRoutine = pfnFreeRoutine;
  74. InitializeListHead( &pbhNewBlock->PFList );
  75. }
  76. else
  77. {
  78. //
  79. // The allocation failed, and we need to return NULL
  80. //
  81. *ppvNewBlock = NULL;
  82. }
  83. }
  84. __except( EXCEPTION_EXECUTE_HANDLER )
  85. {
  86. //
  87. // An exception transpired. The most likely causes are bogus input
  88. // pointers for pServiceInfo and pbhNewBlock. Whatever the case, we
  89. // free up any memory that may have been allocated and return failure.
  90. //
  91. if ( pbhNewBlock != NULL )
  92. {
  93. FREE( pbhNewBlock );
  94. pbhNewBlock = NULL;
  95. }
  96. }
  97. //
  98. // Return TRUE or FALSE, according to the result of the allocation.
  99. //
  100. if ( pbhNewBlock == NULL )
  101. {
  102. SetLastError( ERROR_NOT_ENOUGH_MEMORY);
  103. return( FALSE );
  104. }
  105. INC_COUNTER( TSvcCache.GetServiceId(),
  106. CurrentObjects );
  107. return( TRUE );
  108. } // TsAllocate
  109. BOOL
  110. TsReallocate(
  111. IN const TSVC_CACHE &TSvcCache,
  112. IN ULONG cbSize,
  113. IN PVOID pvOldBlock,
  114. IN OUT PVOID * ppvNewBlock
  115. )
  116. /*++
  117. Routine Description:
  118. This function will resize a previously allocated memory Blob
  119. for the calling server, possibly moving it in the process.
  120. Arguments:
  121. pServiceInfo - An initialized SERVICE_INFO structure.
  122. cbSize - Number of bytes to resize the block to.
  123. (Must be strictly greater than zero.)
  124. pvOldBlock - Address of a pointer to a previously-allocated
  125. block.
  126. ppvNewBlock - Address of a pointer to store the new block's
  127. address in. If the allocation fails, NULL is
  128. stored here. Note that in many cases,
  129. pvOldBlock will be stored here.
  130. Return Value:
  131. TRUE - The reallocation succeeded, and *ppvNewBlock points to
  132. at least cbSize accessable bytes. pvOldBlock is no
  133. longer a valid pointer, if *ppvNewBlock!=pvOldBlock.
  134. FALSE - The allocation failed. *ppvNewBlock = NULL.
  135. pvOldBlock is still a valid pointer to the block that
  136. we wished to resize.
  137. --*/
  138. {
  139. PBLOB_HEADER pbhNewBlock;
  140. PBLOB_HEADER pbhOldBlock;
  141. ASSERT( pvOldBlock != NULL );
  142. //
  143. // Set pbhNewBlock to NULL so that the exception-cleanup code
  144. // can test against it to see if an allocation occurred before
  145. // the exception.
  146. //
  147. pbhNewBlock = NULL;
  148. __try
  149. {
  150. //
  151. // Adjust the input pointer to refer to the BLOB_HEADER.
  152. //
  153. pbhOldBlock = (( PBLOB_HEADER )pvOldBlock ) - 1;
  154. //
  155. // If the Blob is currently cached, we can't move it
  156. // or change its size. Check for this in the Blob's
  157. // flags, and fail if it occurs.
  158. //
  159. if ( pbhOldBlock->IsCached )
  160. {
  161. DBGPRINTF(( DBG_CONTEXT,
  162. "A service (%d) has attempted to TsRealloc a BLOB that is cached.",
  163. TSvcCache.GetServiceId() ));
  164. BREAKPOINT();
  165. SetLastError( ERROR_INVALID_PARAMETER );
  166. }
  167. else
  168. {
  169. //
  170. // The following assignment probes ppvNewBlock for writeability.
  171. // Hopefully, this ensures that we get an AV from writing to it
  172. // before we call REALLOC and potentially free the old block.
  173. //
  174. *ppvNewBlock = NULL;
  175. pbhNewBlock = ( PBLOB_HEADER )REALLOC( pbhOldBlock, cbSize );
  176. if ( pbhNewBlock != NULL )
  177. {
  178. //
  179. // Store a pointer to the caller-usable part of the new Blob in
  180. // the output parameter.
  181. //
  182. *ppvNewBlock = ( PVOID )( pbhNewBlock + 1 );
  183. }
  184. }
  185. }
  186. __except( EXCEPTION_EXECUTE_HANDLER )
  187. {
  188. //
  189. // An exception occured. If this was caught after a block was
  190. // allocated, we must free the new block. Unfortunately, this
  191. // means that we may end up returning FALSE in a case where
  192. // pbhOldBlock is no longer valid.
  193. //
  194. // if ( pbhOldBlock == pbhNewBlock ), which implies the old
  195. // pointer is still valid, we do not free the new block, but
  196. // hope that the caller will. In any other case, we must
  197. // free the new block to avoid a memory leak, and assume that
  198. // TCPSVCs are going down soon...
  199. //
  200. // ISSUE: It might be best to reflect the exception up to the
  201. // caller, so they can handle it and bail out of the current
  202. // operation.
  203. //
  204. if ( pbhNewBlock != NULL && pbhOldBlock != pbhNewBlock )
  205. {
  206. FREE( pbhNewBlock );
  207. pbhNewBlock = NULL;
  208. SetLastError( ERROR_INVALID_PARAMETER );
  209. }
  210. }
  211. //
  212. // Return TRUE or FALSE, according to the result of the allocation.
  213. //
  214. if ( pbhNewBlock == NULL )
  215. {
  216. return( FALSE );
  217. }
  218. return( TRUE );
  219. } // TsReallocate
  220. BOOL
  221. TsFree(
  222. IN const TSVC_CACHE &TSvcCache,
  223. IN PVOID pvOldBlock
  224. )
  225. /*++
  226. Routine Description:
  227. This function frees a memory block allocated with TsAllocate().
  228. Blocks that are currently cached cannot be freed with this
  229. function.
  230. Arguments:
  231. pServiceInfo - An initialized SERVICE_INFO structure.
  232. pvOldBlock - The address of the block to free. (Must be
  233. non-NULL.)
  234. Return Value:
  235. TRUE - The block was freed. The pointer pvOldBlock is no longer
  236. valid.
  237. FALSE - The block was not freed. Possible reasons include:
  238. - pvOldBlock does not point to a block allocated with
  239. TsAllocate().
  240. - pvOldBlock points to a block that has been cached
  241. with CacheDirectoryBlob().
  242. - pServiceInfo does not point to a valid SERVICE_INFO
  243. structure.
  244. --*/
  245. {
  246. BOOLEAN bSuccess;
  247. PBLOB_HEADER pbhOldBlock;
  248. ASSERT( pvOldBlock != NULL );
  249. __try
  250. {
  251. //
  252. // Adjust the input pointer to refer to the BLOB_HEADER.
  253. //
  254. pbhOldBlock = (( PBLOB_HEADER )pvOldBlock ) - 1;
  255. if (!DisableSPUD) {
  256. EnterCriticalSection( &CacheTable.CriticalSection );
  257. if ( !IsListEmpty( &pbhOldBlock->PFList ) ) {
  258. RemoveEntryList( &pbhOldBlock->PFList );
  259. }
  260. LeaveCriticalSection( &CacheTable.CriticalSection );
  261. }
  262. //
  263. // If the Blob is currently in the cache, we can't free it.
  264. // Check for this in the Blob's flags, and fail if it
  265. // occurs.
  266. //
  267. if ( pbhOldBlock->IsCached )
  268. {
  269. DBGPRINTF(( DBG_CONTEXT,
  270. "A service (%d) has attempted to TsFree a BLOB that it put in the cache.",
  271. TSvcCache.GetServiceId() ));
  272. BREAKPOINT();
  273. bSuccess = FALSE;
  274. }
  275. else
  276. {
  277. if ( pbhOldBlock->pfnFreeRoutine )
  278. {
  279. bSuccess = pbhOldBlock->pfnFreeRoutine( pvOldBlock );
  280. }
  281. else
  282. {
  283. bSuccess = TRUE;
  284. }
  285. if ( bSuccess )
  286. {
  287. //
  288. // Free the memory used by the Blob.
  289. //
  290. bSuccess = !!FREE( pbhOldBlock );
  291. DEC_COUNTER( TSvcCache.GetServiceId(),
  292. CurrentObjects );
  293. }
  294. }
  295. }
  296. __except( EXCEPTION_EXECUTE_HANDLER )
  297. {
  298. //
  299. // Handle exception. Obviously, it's time to return failure.
  300. // It's hardly possible to get here after succefully freeing
  301. // the block, so it's likely that an app will either:
  302. // - not check the return value and leak some memory.
  303. // - check the return value and try again, probably
  304. // only to fail forever.
  305. //
  306. // So, it is not advisable for callers to keep trying this
  307. // call until it succeeds.
  308. //
  309. bSuccess = FALSE;
  310. }
  311. return( bSuccess );
  312. } // TsFree
  313. BOOL
  314. TsCheckInOrFree(
  315. IN PVOID pvOldBlock
  316. )
  317. /*++
  318. Routine Description:
  319. This function checks in a cached memory block or
  320. frees a non-cached memory block allocated with TsAllocate().
  321. Arguments:
  322. pServiceInfo - An initialized SERVICE_INFO structure.
  323. pvOldBlock - The address of the block to free. (Must be
  324. non-NULL.)
  325. Return Value:
  326. TRUE - The block was freed. The pointer pvOldBlock is no longer
  327. valid.
  328. FALSE - The block was not freed. Possible reasons include:
  329. - pvOldBlock does not point to a block allocated with
  330. TsAllocate().
  331. --*/
  332. {
  333. BOOLEAN bSuccess;
  334. PBLOB_HEADER pbhOldBlock;
  335. ASSERT( pvOldBlock != NULL );
  336. __try
  337. {
  338. //
  339. // Adjust the input pointer to refer to the BLOB_HEADER.
  340. //
  341. pbhOldBlock = (( PBLOB_HEADER )pvOldBlock ) - 1;
  342. if (!DisableSPUD) {
  343. EnterCriticalSection( &CacheTable.CriticalSection );
  344. if (!IsListEmpty( &pbhOldBlock->PFList ) ) {
  345. RemoveEntryList( &pbhOldBlock->PFList );
  346. }
  347. LeaveCriticalSection( &CacheTable.CriticalSection );
  348. }
  349. if (BLOB_IS_OR_WAS_CACHED(pvOldBlock)) {
  350. bSuccess = TsCheckInCachedBlob( pvOldBlock );
  351. } else {
  352. if ( pbhOldBlock->pfnFreeRoutine )
  353. {
  354. bSuccess = pbhOldBlock->pfnFreeRoutine( pvOldBlock );
  355. }
  356. else
  357. {
  358. bSuccess = TRUE;
  359. }
  360. if ( bSuccess )
  361. {
  362. //
  363. // Free the memory used by the Blob.
  364. //
  365. bSuccess = !!FREE( pbhOldBlock );
  366. }
  367. }
  368. }
  369. __except( EXCEPTION_EXECUTE_HANDLER )
  370. {
  371. //
  372. // Handle exception. Obviously, it's time to return failure.
  373. // It's hardly possible to get here after succefully freeing
  374. // the block, so it's likely that an app will either:
  375. // - not check the return value and leak some memory.
  376. // - check the return value and try again, probably
  377. // only to fail forever.
  378. //
  379. // So, it is not advisable for callers to keep trying this
  380. // call until it succeeds.
  381. //
  382. ASSERT(FALSE);
  383. bSuccess = FALSE;
  384. }
  385. return( bSuccess );
  386. } // TsCheckInOrFree
  387.