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.

641 lines
19 KiB

  1. /***
  2. *heapinit.c - Initialze the heap
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *
  8. *Revision History:
  9. * 06-28-89 JCR Module created.
  10. * 06-30-89 JCR Added _heap_grow_emptylist
  11. * 11-13-89 GJF Fixed copyright
  12. * 11-15-89 JCR Moved _heap_abort routine to another module
  13. * 12-15-89 GJF Removed DEBUG286 stuff, did some tuning, changed header
  14. * file name to heap.h and made functions explicitly
  15. * _cdecl.
  16. * 12-19-89 GJF Removed plastdesc field from _heap_desc_ struct
  17. * 03-11-90 GJF Replaced _cdecl with _CALLTYPE1, added #include
  18. * <cruntime.h> and removed #include <register.h>.
  19. * 07-24-90 SBM Removed '32' from API names
  20. * 10-03-90 GJF New-style function declarators.
  21. * 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
  22. * 12-06-90 SRW Added _CRUISER_ and _WIN32 conditionals.
  23. * 02-01-91 SRW Changed for new VirtualAlloc interface (_WIN32_)
  24. * 03-05-91 GJF Added definition of _heap_resetsize (conditioned on
  25. * _OLDROVER_ not being #define-d).
  26. * 04-04-91 GJF Reduce _heap_regionsize to 1/2 a meg for Dosx32
  27. * (_WIN32_).
  28. * 04-05-91 GJF Temporary hack for Win32/DOS folks - special version
  29. * of _heap_init which calls HeapCreate. The change
  30. * conditioned on _WIN32DOS_.
  31. * 04-09-91 PNT Added _MAC_ conditional
  32. * 02-23-93 SKS Remove DOSX32 support under WIN32 ifdef
  33. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  34. * 04-26-93 SKS Add variable _heap_maxregsize (was _HEAP_MAXREGIONSIZE)
  35. * Initialize _heap_[max,]reg[,ion]size to Large defaults
  36. * heapinit() tests _osver to detect Small memory case
  37. * 05-06-93 SKS Add _heap_term() to return heap memory to the o.s.
  38. * 01-17-94 SKS Check _osver AND _winmajor to detect Small memory case.
  39. * 03-02-94 GJF Changed _heap_grow_emptylist so that it returns a
  40. * failure code rather than calling _heap_abort.
  41. * 03-30-94 GJF Made definitions/declarations of:
  42. * _heap_desc
  43. * _heap_descpages,
  44. * _heap_growsize (aka, _amblksiz),
  45. * _heap_maxregsize
  46. * _heap_regionsize
  47. * _heap_regions
  48. * conditional on ndef DLL_FOR_WIN32S.
  49. * 02-08-95 GJF Removed obsolete _OLDROVER_ support.
  50. * 02-14-95 GJF Appended Mac version of source file.
  51. * 04-30-95 GJF Spliced on winheap version.
  52. * 03-06-96 GJF Added initialization and termination code for the
  53. * small-block heap.
  54. * 04-22-97 GJF Changed _heap_init to return 1 for success, 0 for
  55. * failure.
  56. * 05-30-96 GJF Minor changes for latest version of small-block heap.
  57. * 05-22-97 RDK New small-block heap scheme implemented.
  58. * 07-23-97 GJF Changed _heap_init() slightly to accomodate optional
  59. * heap running directly on Win32 API (essentially the
  60. * scheme we used in VC++ 4.0 and 4.1).
  61. * 09-26-97 BWT Fix POSIX
  62. * 09-28-98 GJF Don't initialize the small-block heap on NT 5.
  63. * 11-18-98 GJF Merged in VC++ 5.0 small-block heap and a selection
  64. * scheme from James "Triple-Expresso" MacCalman and
  65. * Chairman Dan Spalding.
  66. * 05-01-99 PML Disable small-block heap for Win64.
  67. * 05-13-99 PML Remove Win32s
  68. * 05-17-99 PML Remove all Macintosh support.
  69. * 06-17-99 GJF Removed old small-block heap from static libs.
  70. * 09-28-99 PML Processing heap-select env var must not do anything
  71. * that uses the heap (vs7#44259). Also, check the env
  72. * var before checking for NT5.0 or better.
  73. * 03-28-01 PML Protect against GetModuleFileName overflow (vs7#231284)
  74. * 06-25-01 BWT Alloc heap select strings off the process heap instead of
  75. * the stack (ntbug: 423988)
  76. *
  77. *******************************************************************************/
  78. #ifdef WINHEAP
  79. #include <cruntime.h>
  80. #include <malloc.h>
  81. #include <stdlib.h>
  82. #include <winheap.h>
  83. HANDLE _crtheap;
  84. #if !defined(_NTSDK)
  85. /*
  86. * Dummy definition of _amblksiz. Included primarily so the dll will build
  87. * without having to change crtlib.c (there is an access function for _amblksiz
  88. * defined in crtlib.c).
  89. */
  90. unsigned int _amblksiz = BYTES_PER_PARA;
  91. #endif
  92. #ifndef _WIN64
  93. int __active_heap;
  94. #ifdef CRTDLL
  95. void __cdecl _GetLinkerVersion(LinkerVersion * plv)
  96. {
  97. PIMAGE_DOS_HEADER pidh;
  98. PIMAGE_NT_HEADERS pinh;
  99. plv->dw = 0;
  100. pidh = (PIMAGE_DOS_HEADER) GetModuleHandle(NULL);
  101. if ( pidh->e_magic != IMAGE_DOS_SIGNATURE || pidh->e_lfanew == 0)
  102. return;
  103. pinh = (PIMAGE_NT_HEADERS)(((PBYTE)pidh) + pidh->e_lfanew);
  104. plv->bverMajor = pinh->OptionalHeader.MajorLinkerVersion;
  105. plv->bverMinor = pinh->OptionalHeader.MinorLinkerVersion;
  106. }
  107. #endif /* CRTDLL */
  108. /***
  109. *__heap_select() - Choose from the V6, V5 or system heaps
  110. *
  111. *Purpose:
  112. * Check OS, environment and build bits to determine appropriate
  113. * small-block heap for the app.
  114. *
  115. *Entry:
  116. * <void>
  117. *Exit:
  118. * Returns __V6_HEAP, __V5_HEAP or __SYSTEM_HEAP
  119. *
  120. *Exceptions:
  121. * none
  122. *
  123. *******************************************************************************/
  124. int __cdecl __heap_select(void)
  125. {
  126. char *env_heap_type = NULL;
  127. #ifdef CRTDLL
  128. DWORD HeapStringSize;
  129. char *cp, *env_heap_select_string = NULL;
  130. int heap_choice;
  131. LinkerVersion lv;
  132. #endif /* CRTDLL */
  133. #ifdef CRTDLL
  134. // First, check the environment variable override
  135. if (HeapStringSize = GetEnvironmentVariableA(__HEAP_ENV_STRING, env_heap_select_string, 0))
  136. {
  137. env_heap_select_string = HeapAlloc(GetProcessHeap(), 0, HeapStringSize);
  138. if (env_heap_select_string)
  139. {
  140. if (GetEnvironmentVariableA(__HEAP_ENV_STRING, env_heap_select_string, HeapStringSize))
  141. {
  142. for (cp = env_heap_select_string; *cp; ++cp)
  143. if ('a' <= *cp && *cp <= 'z')
  144. *cp += 'A' - 'a';
  145. if (!strncmp(__GLOBAL_HEAP_SELECTOR,env_heap_select_string,sizeof(__GLOBAL_HEAP_SELECTOR)-1))
  146. env_heap_type = env_heap_select_string;
  147. else
  148. {
  149. char *env_app_name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH+1);
  150. if (env_app_name) {
  151. GetModuleFileName(NULL,env_app_name,sizeof(env_app_name)-1);
  152. for (cp = env_app_name; *cp; ++cp)
  153. if ('a' <= *cp && *cp <= 'z')
  154. *cp += 'A' - 'a';
  155. env_heap_type = strstr(env_heap_select_string,env_app_name);
  156. HeapFree(GetProcessHeap(), 0, env_app_name);
  157. }
  158. }
  159. if (env_heap_type)
  160. {
  161. if (env_heap_type = strchr(env_heap_type,','))
  162. {
  163. // Convert ASCII heap code to integer inline, since
  164. // strtol would try to use the heap (for locale info).
  165. cp = ++env_heap_type;
  166. while (*cp == ' ')
  167. ++cp;
  168. heap_choice = 0;
  169. while (*cp >= '0' && *cp <= '9')
  170. heap_choice = heap_choice * 10 + *cp++ - '0';
  171. if ( (heap_choice == __V5_HEAP) ||
  172. (heap_choice == __V6_HEAP) ||
  173. (heap_choice == __SYSTEM_HEAP) )
  174. {
  175. HeapFree(GetProcessHeap(), 0, env_heap_select_string);
  176. return heap_choice;
  177. }
  178. }
  179. }
  180. }
  181. HeapFree(GetProcessHeap(), 0, env_heap_select_string);
  182. }
  183. }
  184. #endif /* CRTDLL */
  185. // Second, check the OS for NT >= 5.0
  186. if ( (_osplatform == VER_PLATFORM_WIN32_NT) && (_winmajor >= 5) )
  187. return __SYSTEM_HEAP;
  188. #ifdef CRTDLL
  189. // Third, check the build bits in the app; apps built with tools >= VC++ 6.0
  190. // will get the V6 heap, apps built with older tools will get the V5 heap
  191. _GetLinkerVersion(&lv);
  192. if (lv.bverMajor >= 6)
  193. return __V6_HEAP;
  194. else
  195. return __V5_HEAP;
  196. #else /* ndef CRTDLL */
  197. return __V6_HEAP;
  198. #endif /* CRTDLL */
  199. }
  200. #endif /* ndef _WIN64 */
  201. /***
  202. *_heap_init() - Initialize the heap
  203. *
  204. *Purpose:
  205. * Setup the initial C library heap.
  206. *
  207. * NOTES:
  208. * (1) This routine should only be called once!
  209. * (2) This routine must be called before any other heap requests.
  210. *
  211. *Entry:
  212. * <void>
  213. *Exit:
  214. * Returns 1 if successful, 0 otherwise.
  215. *
  216. *Exceptions:
  217. * If heap cannot be initialized, the program will be terminated
  218. * with a fatal runtime error.
  219. *
  220. *******************************************************************************/
  221. int __cdecl _heap_init (
  222. int mtflag
  223. )
  224. {
  225. #ifdef _POSIX_
  226. _crtheap = GetProcessHeap();
  227. #else
  228. // Initialize the "big-block" heap first.
  229. if ( (_crtheap = HeapCreate( mtflag ? 0 : HEAP_NO_SERIALIZE,
  230. BYTES_PER_PAGE, 0 )) == NULL )
  231. return 0;
  232. #ifndef _WIN64
  233. // Pick a heap, any heap
  234. __active_heap = __heap_select();
  235. if ( __active_heap == __V6_HEAP )
  236. {
  237. // Initialize the small-block heap
  238. if (__sbh_heap_init(MAX_ALLOC_DATA_SIZE) == 0)
  239. {
  240. HeapDestroy(_crtheap);
  241. return 0;
  242. }
  243. }
  244. #ifdef CRTDLL
  245. else if ( __active_heap == __V5_HEAP )
  246. {
  247. if ( __old_sbh_new_region() == NULL )
  248. {
  249. HeapDestroy( _crtheap );
  250. return 0;
  251. }
  252. }
  253. #endif /* CRTDLL */
  254. #endif /* _ndef _WIN64 */
  255. #endif /* _POSIX_ */
  256. return 1;
  257. }
  258. /***
  259. *_heap_term() - return the heap to the OS
  260. *
  261. *Purpose:
  262. *
  263. * NOTES:
  264. * (1) This routine should only be called once!
  265. * (2) This routine must be called AFTER any other heap requests.
  266. *
  267. *Entry:
  268. * <void>
  269. *Exit:
  270. * <void>
  271. *
  272. *Exceptions:
  273. *
  274. *******************************************************************************/
  275. void __cdecl _heap_term (void)
  276. {
  277. #ifndef _POSIX_
  278. #ifndef _WIN64
  279. // if it has been initialized, destroy the small-block heap
  280. if ( __active_heap == __V6_HEAP )
  281. {
  282. PHEADER pHeader = __sbh_pHeaderList;
  283. int cntHeader;
  284. // scan through all the headers
  285. for (cntHeader = 0; cntHeader < __sbh_cntHeaderList; cntHeader++)
  286. {
  287. // decommit and release the address space for the region
  288. VirtualFree(pHeader->pHeapData, BYTES_PER_REGION, MEM_DECOMMIT);
  289. VirtualFree(pHeader->pHeapData, 0, MEM_RELEASE);
  290. // free the region data structure
  291. HeapFree(_crtheap, 0, pHeader->pRegion);
  292. pHeader++;
  293. }
  294. // free the header list
  295. HeapFree(_crtheap, 0, __sbh_pHeaderList);
  296. }
  297. #ifdef CRTDLL
  298. else if ( __active_heap == __V5_HEAP )
  299. {
  300. __old_sbh_region_t *preg = &__old_small_block_heap;
  301. // Release the regions of the small-block heap
  302. do
  303. {
  304. if ( preg->p_pages_begin != NULL )
  305. VirtualFree( preg->p_pages_begin, 0, MEM_RELEASE );
  306. }
  307. while ( (preg = preg->p_next_region) != &__old_small_block_heap );
  308. }
  309. #endif /* CRTDLL */
  310. #endif /* ndef _WIN64 */
  311. // destroy the large-block heap
  312. HeapDestroy(_crtheap);
  313. #endif /* _POSIX_ */
  314. }
  315. #else /* ndef WINHEAP */
  316. #include <cruntime.h>
  317. #include <oscalls.h>
  318. #include <dos.h>
  319. #include <heap.h>
  320. #include <stddef.h>
  321. #include <stdio.h>
  322. #include <stdlib.h>
  323. /*
  324. * Heap descriptor
  325. */
  326. struct _heap_desc_ _heap_desc = {
  327. &_heap_desc.sentinel, /* pfirstdesc */
  328. &_heap_desc.sentinel, /* proverdesc */
  329. NULL, /* emptylist */
  330. NULL, /* sentinel.pnextdesc */
  331. NULL /* sentinel.pblock */
  332. };
  333. /*
  334. * Array of region structures
  335. * [Note: We count on the fact that this is always initialized to zero
  336. * by the compiler.]
  337. */
  338. struct _heap_region_ _heap_regions[_HEAP_REGIONMAX];
  339. void ** _heap_descpages; /* linked list of pages used for descriptors */
  340. /*
  341. * Control parameter locations
  342. */
  343. unsigned int _heap_resetsize = 0xffffffff;
  344. /* NOTE: Currenlty, _heap_growsize is a #define to _amblksiz */
  345. unsigned int _heap_growsize = _HEAP_GROWSIZE; /* region inc size */
  346. unsigned int _heap_regionsize = _HEAP_REGIONSIZE_L; /* region size */
  347. unsigned int _heap_maxregsize = _HEAP_MAXREGSIZE_L; /* max region size */
  348. /***
  349. *_heap_init() - Initialize the heap
  350. *
  351. *Purpose:
  352. * Setup the initial C library heap. All necessary memory and
  353. * data bases are init'd appropriately so future requests work
  354. * correctly.
  355. *
  356. * NOTES:
  357. * (1) This routine should only be called once!
  358. * (2) This routine must be called before any other heap requests.
  359. *
  360. *
  361. *Entry:
  362. * <void>
  363. *Exit:
  364. * <void>
  365. *
  366. *Exceptions:
  367. * If heap cannot be initialized, the program will be terminated
  368. * with a fatal runtime error.
  369. *
  370. *******************************************************************************/
  371. void __cdecl _heap_init (
  372. void
  373. )
  374. {
  375. /*
  376. * Test for Win32S or Phar Lap TNT environment
  377. * which cannot allocate uncommitted memory
  378. * without actually allocating physical memory
  379. *
  380. * High bit of _osver is set for both of those environments
  381. * -AND- the Windows version will be less than 4.0.
  382. */
  383. if ( ( _osver & 0x8000 ) && ( _winmajor < 4 ) )
  384. {
  385. _heap_regionsize = _HEAP_REGIONSIZE_S;
  386. _heap_maxregsize = _HEAP_MAXREGSIZE_S;
  387. }
  388. }
  389. /***
  390. *_heap_term() - Clean-up the heap
  391. *
  392. *Purpose:
  393. * This routine will decommit and release ALL of the CRT heap.
  394. * All memory malloc-ed by the CRT will then be invalid.
  395. *
  396. * NOTES:
  397. * (1) This routine should only be called once!
  398. * (2) This routine must be called AFTER any other heap requests.
  399. *
  400. *Entry:
  401. * <void>
  402. *Exit:
  403. * <void>
  404. *
  405. *Exceptions:
  406. *
  407. *******************************************************************************/
  408. void __cdecl _heap_term (
  409. void
  410. )
  411. {
  412. int index;
  413. void **pageptr;
  414. /*
  415. * Loop through the region descriptor table, decommitting
  416. * and releasing (freeing up) each region that is in use.
  417. */
  418. for ( index=0 ; index < _HEAP_REGIONMAX ; index++ ) {
  419. void * regbase ;
  420. if ( (regbase = _heap_regions[index]._regbase)
  421. && VirtualFree(regbase, _heap_regions[index]._currsize, MEM_DECOMMIT)
  422. && VirtualFree(regbase, 0, MEM_RELEASE) )
  423. regbase = _heap_regions[index]._regbase = NULL ;
  424. }
  425. /*
  426. * Now we need to decommit and release the pages used for descriptors
  427. * _heap_descpages points to the head of a singly-linked list of the pages.
  428. */
  429. pageptr = _heap_descpages;
  430. while ( pageptr ) {
  431. void **nextpage;
  432. nextpage = *pageptr;
  433. if(!VirtualFree(pageptr, 0, MEM_RELEASE))
  434. break; /* if the linked list is corrupted, give up */
  435. pageptr = nextpage;
  436. }
  437. }
  438. /***
  439. * _heap_grow_emptylist() - Grow the empty heap descriptor list
  440. *
  441. *Purpose:
  442. * (1) Get memory from OS
  443. * (2) Form it into a linked list of empty heap descriptors
  444. * (3) Attach it to the master empty list
  445. *
  446. * NOTE: This routine assumes that the emptylist is NULL
  447. * when called (i.e., there are no available empty heap descriptors).
  448. *
  449. *Entry:
  450. * (void)
  451. *
  452. *Exit:
  453. * 1, if the empty heap descriptor list was grown
  454. * 0, if the empty heap descriptor list could not be grown.
  455. *
  456. *Exceptions:
  457. *
  458. *******************************************************************************/
  459. static int __cdecl _heap_grow_emptylist (
  460. void
  461. )
  462. {
  463. REG1 _PBLKDESC first;
  464. REG2 _PBLKDESC next;
  465. _PBLKDESC last;
  466. /*
  467. * Get memory for the new empty heap descriptors
  468. *
  469. * Note that last is used to hold the returned pointer because
  470. * first (and next) are register class.
  471. */
  472. if ( !(last = VirtualAlloc(NULL,
  473. _HEAP_EMPTYLIST_SIZE,
  474. MEM_COMMIT,
  475. PAGE_READWRITE)) )
  476. return 0;
  477. /*
  478. * Add this descriptor block to the front of the list
  479. *
  480. * Advance "last" to skip over the
  481. */
  482. *(void **)last = _heap_descpages;
  483. _heap_descpages = (void **)(last++);
  484. /*
  485. * Init the empty heap descriptor list.
  486. */
  487. _heap_desc.emptylist = first = last;
  488. /*
  489. * Carve the memory into an empty list
  490. */
  491. last = (_PBLKDESC) ((char *) first + _HEAP_EMPTYLIST_SIZE - 2 * sizeof(_BLKDESC));
  492. next = (_PBLKDESC) ((char *) first + sizeof(_BLKDESC));
  493. while ( first < last ) {
  494. /* Init this descriptor */
  495. #ifdef DEBUG
  496. first->pblock = NULL;
  497. #endif
  498. first->pnextdesc = next;
  499. /* onto the next block */
  500. first = next++;
  501. }
  502. /*
  503. * Take care of the last descriptor (end of the empty list)
  504. */
  505. last->pnextdesc = NULL;
  506. #ifdef DEBUG
  507. last->pblock = NULL;
  508. #endif
  509. return 1;
  510. }
  511. /***
  512. *__getempty() - get an empty heap descriptor
  513. *
  514. *Purpose:
  515. * Get a descriptor from the list of empty heap descriptors. If the list
  516. * is empty, call _heap_grow_emptylist.
  517. *
  518. *Entry:
  519. * no arguments
  520. *
  521. *Exit:
  522. * If successful, a pointer to the descriptor is returned.
  523. * Otherwise, NULL is returned.
  524. *
  525. *Exceptions:
  526. *
  527. *******************************************************************************/
  528. _PBLKDESC __cdecl __getempty(
  529. void
  530. )
  531. {
  532. _PBLKDESC pdesc;
  533. if ( (_heap_desc.emptylist == NULL) && (_heap_grow_emptylist()
  534. == 0) )
  535. return NULL;
  536. pdesc = _heap_desc.emptylist;
  537. _heap_desc.emptylist = pdesc->pnextdesc;
  538. return pdesc;
  539. }
  540. #endif /* WINHEAP */