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.

264 lines
8.0 KiB

  1. #include "stdinc.h"
  2. #include "lhport.h"
  3. #include "windows.h"
  4. #include "numberof.h"
  5. #include "positionindependentblob.h"
  6. #include "fusionhandle.h"
  7. #undef ASSERT
  8. #undef ASSERT_NTC /* NTC == no trace context */
  9. #if DBG
  10. void AssertFunction(PCSTR s) { ASSERT2_NTC(FALSE, s); }
  11. #define ASSERT(expr) ((expr) ? TRUE : (AssertFunction(#expr),FALSE))
  12. #define ASSERT_NTC(expr) ((expr) ? TRUE : (AssertFunction(#expr),FALSE))
  13. #else
  14. #define ASSERT_NTC(expr) ((expr) ? TRUE : FALSE)
  15. #endif
  16. void *
  17. CPositionIndependentOperatorNew::operator new(
  18. size_t n,
  19. CPositionIndependentBlob * Container
  20. )
  21. {
  22. return Container->OperatorNew(n);
  23. }
  24. void CPositionIndependentBlob::OutOfMemory()
  25. {
  26. OutputDebugStringA("SXS_PIBLOB: out of memory\n");
  27. F::CErr::ThrowWin32(FUSION_WIN32_ALLOCFAILED_ERROR);
  28. }
  29. CPositionIndependentBlob::CPositionIndependentBlob()
  30. {
  31. ZeroMemory(this, sizeof(*this));
  32. }
  33. CPositionIndependentBlob::~CPositionIndependentBlob()
  34. {
  35. }
  36. void
  37. CPositionIndependentBlob::Alloc(
  38. CPositionIndependentBlob * Container,
  39. ULONG NumberOfBytes,
  40. ULONG * Offset
  41. )
  42. {
  43. if (Container != NULL)
  44. {
  45. return Container->Alloc(NumberOfBytes, Offset);
  46. }
  47. return this->Alloc(NumberOfBytes, Offset);
  48. }
  49. //
  50. // CONSIDER: NtExtendSection for pagefile mappings.
  51. //
  52. BOOL CPositionIndependentBlob::IsPagefileMapping()
  53. {
  54. return (m_FileHandle == INVALID_HANDLE_VALUE);
  55. }
  56. void GetFirstError(DWORD & FirstError)
  57. {
  58. if (FirstError == NO_ERROR)
  59. FirstError = F::GetLastWin32Error();
  60. }
  61. void CPositionIndependentBlob::Free(const BYTE * Pointer)
  62. {
  63. FN_PROLOG_VOID_THROW
  64. CBlock InUseBlock;
  65. InUseBlock.m_Offset = static_cast<ULONG>((Pointer - GetBasePointer()));
  66. InUseBlock.m_Size = 0;
  67. CBlockByOffsetSet::iterator InUseByOffsetIterator = m_InUseBlocksSortedByOffset.lower_bound(InUseBlock);
  68. if (!ASSERT_NTC(InUseByOffsetIterator != m_InUseBlocksSortedByOffset.end()))
  69. {
  70. return;
  71. }
  72. InUseBlock = *InUseByOffsetIterator;
  73. m_InUseBlocksSortedByOffset.erase(InUseByOffsetIterator);
  74. CBlockByOffsetSet::iterator End = m_FreeBlocksSortedByOffset.end();
  75. CBlockByOffsetSet::iterator PrevFreeBlockIterator = m_FreeBlocksSortedByOffset.lower_bound(InUseBlock);
  76. CBlockByOffsetSet::iterator NextFreeBlockIterator = m_FreeBlocksSortedByOffset.upper_bound(InUseBlock);
  77. CBlockByOffsetSet::iterator FreeByOffsetToErase = End;
  78. CBlock BiggerFreeBlock;
  79. BiggerFreeBlock.m_Size = InUseBlock.m_Size;
  80. if (PrevFreeBlockIterator != End && !InUseBlock.Neighbors(*PrevFreeBlockIterator))
  81. PrevFreeBlockIterator = End;
  82. if (NextFreeBlockIterator != End && !InUseBlock.Neighbors(*NextFreeBlockIterator))
  83. NextFreeBlockIterator = End;
  84. switch (
  85. (ULONG(PrevFreeBlockIterator != End) << 1) | ULONG(NextFreeBlockIterator != End)
  86. )
  87. {
  88. case 3:
  89. // freed between two free blocks, merge all three
  90. const_cast<ULONG&>(PrevFreeBlockIterator->m_Size) += InUseBlock.m_Size;
  91. const_cast<ULONG&>(PrevFreeBlockIterator->m_Size) += NextFreeBlockIterator->m_Size;
  92. BiggerFreeBlock = *PrevFreeBlockIterator;
  93. FreeByOffsetToErase = NextFreeBlockIterator;
  94. break;
  95. case 2:
  96. // freed with a free block to the left, merge with left
  97. const_cast<ULONG&>(PrevFreeBlockIterator->m_Size) += InUseBlock.m_Size;
  98. BiggerFreeBlock = *PrevFreeBlockIterator;
  99. FreeByOffsetToErase = NextFreeBlockIterator;
  100. break;
  101. case 1:
  102. // freed with free block to the right, merge with right
  103. const_cast<ULONG&>(NextFreeBlockIterator->m_Offset) -= InUseBlock.m_Size;
  104. const_cast<ULONG&>(NextFreeBlockIterator->m_Size) += InUseBlock.m_Size;
  105. BiggerFreeBlock = *NextFreeBlockIterator;
  106. FreeByOffsetToErase = PrevFreeBlockIterator;
  107. break;
  108. case 0:
  109. // freed between two inuse blocks, no merge
  110. // BUG Free should not allocate memory. This is avoidable by keeping empty blocks at the ends.
  111. m_FreeBlocksSortedByOffset.insert(BiggerFreeBlock);
  112. break;
  113. }
  114. if (PrevFreeBlockIterator != End)
  115. m_FreeBlocksSortedBySize.erase(*PrevFreeBlockIterator);
  116. if (NextFreeBlockIterator != End)
  117. m_FreeBlocksSortedBySize.erase(*NextFreeBlockIterator);
  118. if (FreeByOffsetToErase != End)
  119. m_FreeBlocksSortedByOffset.erase(FreeByOffsetToErase);
  120. m_PendingFreeBySize += 1;
  121. FN_EPILOG_THROW;
  122. }
  123. void CPositionIndependentBlob::RecalculateBlocksBySize()
  124. {
  125. if (m_PendingFreeBySize == 0)
  126. return;
  127. // UNDONE
  128. m_PendingFreeBySize = 0;
  129. }
  130. void
  131. CPositionIndependentBlob::GetBounds(
  132. const BYTE * Bounds[2]
  133. )
  134. {
  135. FN_PROLOG_VOID_THROW
  136. Bounds[0] = GetBasePointer();
  137. Bounds[1] = Bounds[0] + m_AllocatedSize;;
  138. FN_EPILOG_THROW;
  139. }
  140. void
  141. CPositionIndependentBlob::IsInBlob(
  142. const BYTE * Data,
  143. ULONG Size,
  144. BOOL * IsInBlob
  145. )
  146. {
  147. FN_PROLOG_VOID_THROW
  148. const BYTE * Bounds[2];
  149. GetBounds(Bounds);
  150. *IsInBlob = (Data >= Bounds[0] && (Data + Size) < Bounds[1]);
  151. FN_EPILOG_THROW;
  152. }
  153. void Reserve()
  154. {
  155. // UNDONE
  156. }
  157. void CPositionIndependentBlob::Alloc(ULONG NumberOfBytes, ULONG * Offset)
  158. {
  159. FN_PROLOG_VOID_THROW
  160. CBlock Block;
  161. Block.m_Offset = 0;
  162. Block.m_Size = NumberOfBytes;
  163. RecalculateBlocksBySize();
  164. CBlockBySizeSet::iterator i = m_FreeBlocksSortedBySize.lower_bound(Block);
  165. if (i == m_FreeBlocksSortedBySize.end() && m_pmfCompact != NULL)
  166. {
  167. RecalculateBlocksBySize();
  168. i = m_FreeBlocksSortedBySize.lower_bound(Block);
  169. }
  170. if (i == m_FreeBlocksSortedBySize.end() && m_pmfCompact != NULL)
  171. {
  172. (this->*m_pmfCompact)();
  173. i = m_FreeBlocksSortedBySize.lower_bound(Block);
  174. }
  175. if (i == m_FreeBlocksSortedBySize.end())
  176. {
  177. Grow(NumberOfBytes);
  178. i = m_FreeBlocksSortedBySize.lower_bound(Block);
  179. }
  180. if (i == m_FreeBlocksSortedBySize.end())
  181. {
  182. OutOfMemory();
  183. return;
  184. }
  185. CBlock Found = *i;
  186. CBlock FitFound = Found;
  187. ULONG RemainderSize = (Found.m_Size - NumberOfBytes);
  188. FitFound.m_Size = NumberOfBytes;
  189. //
  190. // erase before we mess with the ordering (we would create ties otherwise)
  191. //
  192. m_FreeBlocksSortedByOffset.erase(*i);
  193. m_FreeBlocksSortedBySize.erase(i);
  194. if (RemainderSize != 0)
  195. {
  196. CBlockByOffsetSet::iterator End = m_FreeBlocksSortedByOffset.end();
  197. CBlockByOffsetSet::iterator PrevFreeBlockIterator = m_FreeBlocksSortedByOffset.lower_bound(Found);
  198. CBlockByOffsetSet::iterator NextFreeBlockIterator = m_FreeBlocksSortedByOffset.upper_bound(Found);
  199. if (PrevFreeBlockIterator != End && !Found.Neighbors(*PrevFreeBlockIterator))
  200. PrevFreeBlockIterator = End;
  201. if (NextFreeBlockIterator != End && !Found.Neighbors(*NextFreeBlockIterator))
  202. NextFreeBlockIterator = End;
  203. switch (
  204. (ULONG(PrevFreeBlockIterator != End) << 1) | ULONG(NextFreeBlockIterator != End)
  205. )
  206. {
  207. case 3:
  208. ASSERT_NTC(!"Should not be free on both sides of a free.");
  209. break;
  210. case 2:
  211. m_FreeBlocksSortedBySize.erase(*PrevFreeBlockIterator);
  212. const_cast<ULONG&>(PrevFreeBlockIterator->m_Size) += RemainderSize;
  213. m_FreeBlocksSortedBySize.insert(*PrevFreeBlockIterator);
  214. FitFound.m_Offset += RemainderSize;
  215. break;
  216. case 1:
  217. m_FreeBlocksSortedBySize.erase(*NextFreeBlockIterator);
  218. const_cast<ULONG&>(NextFreeBlockIterator->m_Offset) -= RemainderSize;
  219. const_cast<ULONG&>(NextFreeBlockIterator->m_Size) += RemainderSize;
  220. m_FreeBlocksSortedBySize.insert(*NextFreeBlockIterator);
  221. break;
  222. case 0:
  223. break;
  224. }
  225. }
  226. m_InUseBlocksSortedByOffset.insert(FitFound);
  227. *Offset = FitFound.m_Offset;
  228. FN_EPILOG_THROW;
  229. }