mheap.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. // Copyright 2009 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Page heap.
  5. //
  6. // See malloc.h for overview.
  7. //
  8. // When a MSpan is in the heap free list, state == MSpanFree
  9. // and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span.
  10. //
  11. // When a MSpan is allocated, state == MSpanInUse
  12. // and heapmap(i) == span for all s->start <= i < s->start+s->npages.
  13. #include "runtime.h"
  14. #include "arch.h"
  15. #include "malloc.h"
  16. static MSpan *MHeap_AllocLocked(MHeap*, uintptr, int32);
  17. static bool MHeap_Grow(MHeap*, uintptr);
  18. static void MHeap_FreeLocked(MHeap*, MSpan*);
  19. static MSpan *MHeap_AllocLarge(MHeap*, uintptr);
  20. static MSpan *BestFit(MSpan*, uintptr, MSpan*);
  21. static void
  22. RecordSpan(void *vh, byte *p)
  23. {
  24. MHeap *h;
  25. MSpan *s;
  26. MSpan **all;
  27. uint32 cap;
  28. h = vh;
  29. s = (MSpan*)p;
  30. if(h->nspan >= h->nspancap) {
  31. cap = 64*1024/sizeof(all[0]);
  32. if(cap < h->nspancap*3/2)
  33. cap = h->nspancap*3/2;
  34. all = (MSpan**)runtime_SysAlloc(cap*sizeof(all[0]), &mstats.other_sys);
  35. if(all == nil)
  36. runtime_throw("runtime: cannot allocate memory");
  37. if(h->allspans) {
  38. runtime_memmove(all, h->allspans, h->nspancap*sizeof(all[0]));
  39. // Don't free the old array if it's referenced by sweep.
  40. // See the comment in mgc0.c.
  41. if(h->allspans != runtime_mheap.sweepspans)
  42. runtime_SysFree(h->allspans, h->nspancap*sizeof(all[0]), &mstats.other_sys);
  43. }
  44. h->allspans = all;
  45. h->nspancap = cap;
  46. }
  47. h->allspans[h->nspan++] = s;
  48. }
  49. // Initialize the heap; fetch memory using alloc.
  50. void
  51. runtime_MHeap_Init(MHeap *h)
  52. {
  53. uint32 i;
  54. runtime_FixAlloc_Init(&h->spanalloc, sizeof(MSpan), RecordSpan, h, &mstats.mspan_sys);
  55. runtime_FixAlloc_Init(&h->cachealloc, sizeof(MCache), nil, nil, &mstats.mcache_sys);
  56. runtime_FixAlloc_Init(&h->specialfinalizeralloc, sizeof(SpecialFinalizer), nil, nil, &mstats.other_sys);
  57. runtime_FixAlloc_Init(&h->specialprofilealloc, sizeof(SpecialProfile), nil, nil, &mstats.other_sys);
  58. // h->mapcache needs no init
  59. for(i=0; i<nelem(h->free); i++) {
  60. runtime_MSpanList_Init(&h->free[i]);
  61. runtime_MSpanList_Init(&h->busy[i]);
  62. }
  63. runtime_MSpanList_Init(&h->freelarge);
  64. runtime_MSpanList_Init(&h->busylarge);
  65. for(i=0; i<nelem(h->central); i++)
  66. runtime_MCentral_Init(&h->central[i], i);
  67. }
  68. void
  69. runtime_MHeap_MapSpans(MHeap *h)
  70. {
  71. uintptr pagesize;
  72. uintptr n;
  73. // Map spans array, PageSize at a time.
  74. n = (uintptr)h->arena_used;
  75. n -= (uintptr)h->arena_start;
  76. n = n / PageSize * sizeof(h->spans[0]);
  77. n = ROUND(n, PageSize);
  78. pagesize = getpagesize();
  79. n = ROUND(n, pagesize);
  80. if(h->spans_mapped >= n)
  81. return;
  82. runtime_SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, h->arena_reserved, &mstats.other_sys);
  83. h->spans_mapped = n;
  84. }
  85. // Sweeps spans in list until reclaims at least npages into heap.
  86. // Returns the actual number of pages reclaimed.
  87. static uintptr
  88. MHeap_ReclaimList(MHeap *h, MSpan *list, uintptr npages)
  89. {
  90. MSpan *s;
  91. uintptr n;
  92. uint32 sg;
  93. n = 0;
  94. sg = runtime_mheap.sweepgen;
  95. retry:
  96. for(s = list->next; s != list; s = s->next) {
  97. if(s->sweepgen == sg-2 && runtime_cas(&s->sweepgen, sg-2, sg-1)) {
  98. runtime_MSpanList_Remove(s);
  99. // swept spans are at the end of the list
  100. runtime_MSpanList_InsertBack(list, s);
  101. runtime_unlock(h);
  102. n += runtime_MSpan_Sweep(s);
  103. runtime_lock(h);
  104. if(n >= npages)
  105. return n;
  106. // the span could have been moved elsewhere
  107. goto retry;
  108. }
  109. if(s->sweepgen == sg-1) {
  110. // the span is being sweept by background sweeper, skip
  111. continue;
  112. }
  113. // already swept empty span,
  114. // all subsequent ones must also be either swept or in process of sweeping
  115. break;
  116. }
  117. return n;
  118. }
  119. // Sweeps and reclaims at least npage pages into heap.
  120. // Called before allocating npage pages.
  121. static void
  122. MHeap_Reclaim(MHeap *h, uintptr npage)
  123. {
  124. uintptr reclaimed, n;
  125. // First try to sweep busy spans with large objects of size >= npage,
  126. // this has good chances of reclaiming the necessary space.
  127. for(n=npage; n < nelem(h->busy); n++) {
  128. if(MHeap_ReclaimList(h, &h->busy[n], npage))
  129. return; // Bingo!
  130. }
  131. // Then -- even larger objects.
  132. if(MHeap_ReclaimList(h, &h->busylarge, npage))
  133. return; // Bingo!
  134. // Now try smaller objects.
  135. // One such object is not enough, so we need to reclaim several of them.
  136. reclaimed = 0;
  137. for(n=0; n < npage && n < nelem(h->busy); n++) {
  138. reclaimed += MHeap_ReclaimList(h, &h->busy[n], npage-reclaimed);
  139. if(reclaimed >= npage)
  140. return;
  141. }
  142. // Now sweep everything that is not yet swept.
  143. runtime_unlock(h);
  144. for(;;) {
  145. n = runtime_sweepone();
  146. if(n == (uintptr)-1) // all spans are swept
  147. break;
  148. reclaimed += n;
  149. if(reclaimed >= npage)
  150. break;
  151. }
  152. runtime_lock(h);
  153. }
  154. // Allocate a new span of npage pages from the heap
  155. // and record its size class in the HeapMap and HeapMapCache.
  156. MSpan*
  157. runtime_MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero)
  158. {
  159. MSpan *s;
  160. runtime_lock(h);
  161. mstats.heap_alloc += runtime_m()->mcache->local_cachealloc;
  162. runtime_m()->mcache->local_cachealloc = 0;
  163. s = MHeap_AllocLocked(h, npage, sizeclass);
  164. if(s != nil) {
  165. mstats.heap_inuse += npage<<PageShift;
  166. if(large) {
  167. mstats.heap_objects++;
  168. mstats.heap_alloc += npage<<PageShift;
  169. // Swept spans are at the end of lists.
  170. if(s->npages < nelem(h->free))
  171. runtime_MSpanList_InsertBack(&h->busy[s->npages], s);
  172. else
  173. runtime_MSpanList_InsertBack(&h->busylarge, s);
  174. }
  175. }
  176. runtime_unlock(h);
  177. if(s != nil) {
  178. if(needzero && s->needzero)
  179. runtime_memclr((byte*)(s->start<<PageShift), s->npages<<PageShift);
  180. s->needzero = 0;
  181. }
  182. return s;
  183. }
  184. static MSpan*
  185. MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass)
  186. {
  187. uintptr n;
  188. MSpan *s, *t;
  189. PageID p;
  190. // To prevent excessive heap growth, before allocating n pages
  191. // we need to sweep and reclaim at least n pages.
  192. if(!h->sweepdone)
  193. MHeap_Reclaim(h, npage);
  194. // Try in fixed-size lists up to max.
  195. for(n=npage; n < nelem(h->free); n++) {
  196. if(!runtime_MSpanList_IsEmpty(&h->free[n])) {
  197. s = h->free[n].next;
  198. goto HaveSpan;
  199. }
  200. }
  201. // Best fit in list of large spans.
  202. if((s = MHeap_AllocLarge(h, npage)) == nil) {
  203. if(!MHeap_Grow(h, npage))
  204. return nil;
  205. if((s = MHeap_AllocLarge(h, npage)) == nil)
  206. return nil;
  207. }
  208. HaveSpan:
  209. // Mark span in use.
  210. if(s->state != MSpanFree)
  211. runtime_throw("MHeap_AllocLocked - MSpan not free");
  212. if(s->npages < npage)
  213. runtime_throw("MHeap_AllocLocked - bad npages");
  214. runtime_MSpanList_Remove(s);
  215. runtime_atomicstore(&s->sweepgen, h->sweepgen);
  216. s->state = MSpanInUse;
  217. mstats.heap_idle -= s->npages<<PageShift;
  218. mstats.heap_released -= s->npreleased<<PageShift;
  219. if(s->npreleased > 0)
  220. runtime_SysUsed((void*)(s->start<<PageShift), s->npages<<PageShift);
  221. s->npreleased = 0;
  222. if(s->npages > npage) {
  223. // Trim extra and put it back in the heap.
  224. t = runtime_FixAlloc_Alloc(&h->spanalloc);
  225. runtime_MSpan_Init(t, s->start + npage, s->npages - npage);
  226. s->npages = npage;
  227. p = t->start;
  228. p -= ((uintptr)h->arena_start>>PageShift);
  229. if(p > 0)
  230. h->spans[p-1] = s;
  231. h->spans[p] = t;
  232. h->spans[p+t->npages-1] = t;
  233. t->needzero = s->needzero;
  234. runtime_atomicstore(&t->sweepgen, h->sweepgen);
  235. t->state = MSpanInUse;
  236. MHeap_FreeLocked(h, t);
  237. t->unusedsince = s->unusedsince; // preserve age
  238. }
  239. s->unusedsince = 0;
  240. // Record span info, because gc needs to be
  241. // able to map interior pointer to containing span.
  242. s->sizeclass = sizeclass;
  243. s->elemsize = (sizeclass==0 ? s->npages<<PageShift : (uintptr)runtime_class_to_size[sizeclass]);
  244. s->types.compression = MTypes_Empty;
  245. p = s->start;
  246. p -= ((uintptr)h->arena_start>>PageShift);
  247. for(n=0; n<npage; n++)
  248. h->spans[p+n] = s;
  249. return s;
  250. }
  251. // Allocate a span of exactly npage pages from the list of large spans.
  252. static MSpan*
  253. MHeap_AllocLarge(MHeap *h, uintptr npage)
  254. {
  255. return BestFit(&h->freelarge, npage, nil);
  256. }
  257. // Search list for smallest span with >= npage pages.
  258. // If there are multiple smallest spans, take the one
  259. // with the earliest starting address.
  260. static MSpan*
  261. BestFit(MSpan *list, uintptr npage, MSpan *best)
  262. {
  263. MSpan *s;
  264. for(s=list->next; s != list; s=s->next) {
  265. if(s->npages < npage)
  266. continue;
  267. if(best == nil
  268. || s->npages < best->npages
  269. || (s->npages == best->npages && s->start < best->start))
  270. best = s;
  271. }
  272. return best;
  273. }
  274. // Try to add at least npage pages of memory to the heap,
  275. // returning whether it worked.
  276. static bool
  277. MHeap_Grow(MHeap *h, uintptr npage)
  278. {
  279. uintptr ask;
  280. void *v;
  281. MSpan *s;
  282. PageID p;
  283. // Ask for a big chunk, to reduce the number of mappings
  284. // the operating system needs to track; also amortizes
  285. // the overhead of an operating system mapping.
  286. // Allocate a multiple of 64kB (16 pages).
  287. npage = (npage+15)&~15;
  288. ask = npage<<PageShift;
  289. if(ask < HeapAllocChunk)
  290. ask = HeapAllocChunk;
  291. v = runtime_MHeap_SysAlloc(h, ask);
  292. if(v == nil) {
  293. if(ask > (npage<<PageShift)) {
  294. ask = npage<<PageShift;
  295. v = runtime_MHeap_SysAlloc(h, ask);
  296. }
  297. if(v == nil) {
  298. runtime_printf("runtime: out of memory: cannot allocate %D-byte block (%D in use)\n", (uint64)ask, mstats.heap_sys);
  299. return false;
  300. }
  301. }
  302. // Create a fake "in use" span and free it, so that the
  303. // right coalescing happens.
  304. s = runtime_FixAlloc_Alloc(&h->spanalloc);
  305. runtime_MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
  306. p = s->start;
  307. p -= ((uintptr)h->arena_start>>PageShift);
  308. h->spans[p] = s;
  309. h->spans[p + s->npages - 1] = s;
  310. runtime_atomicstore(&s->sweepgen, h->sweepgen);
  311. s->state = MSpanInUse;
  312. MHeap_FreeLocked(h, s);
  313. return true;
  314. }
  315. // Look up the span at the given address.
  316. // Address is guaranteed to be in map
  317. // and is guaranteed to be start or end of span.
  318. MSpan*
  319. runtime_MHeap_Lookup(MHeap *h, void *v)
  320. {
  321. uintptr p;
  322. p = (uintptr)v;
  323. p -= (uintptr)h->arena_start;
  324. return h->spans[p >> PageShift];
  325. }
  326. // Look up the span at the given address.
  327. // Address is *not* guaranteed to be in map
  328. // and may be anywhere in the span.
  329. // Map entries for the middle of a span are only
  330. // valid for allocated spans. Free spans may have
  331. // other garbage in their middles, so we have to
  332. // check for that.
  333. MSpan*
  334. runtime_MHeap_LookupMaybe(MHeap *h, void *v)
  335. {
  336. MSpan *s;
  337. PageID p, q;
  338. if((byte*)v < h->arena_start || (byte*)v >= h->arena_used)
  339. return nil;
  340. p = (uintptr)v>>PageShift;
  341. q = p;
  342. q -= (uintptr)h->arena_start >> PageShift;
  343. s = h->spans[q];
  344. if(s == nil || p < s->start || (byte*)v >= s->limit || s->state != MSpanInUse)
  345. return nil;
  346. return s;
  347. }
  348. // Free the span back into the heap.
  349. void
  350. runtime_MHeap_Free(MHeap *h, MSpan *s, int32 acct)
  351. {
  352. runtime_lock(h);
  353. mstats.heap_alloc += runtime_m()->mcache->local_cachealloc;
  354. runtime_m()->mcache->local_cachealloc = 0;
  355. mstats.heap_inuse -= s->npages<<PageShift;
  356. if(acct) {
  357. mstats.heap_alloc -= s->npages<<PageShift;
  358. mstats.heap_objects--;
  359. }
  360. MHeap_FreeLocked(h, s);
  361. runtime_unlock(h);
  362. }
  363. static void
  364. MHeap_FreeLocked(MHeap *h, MSpan *s)
  365. {
  366. MSpan *t;
  367. PageID p;
  368. s->types.compression = MTypes_Empty;
  369. if(s->state != MSpanInUse || s->ref != 0 || s->sweepgen != h->sweepgen) {
  370. runtime_printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d sweepgen %d/%d\n",
  371. s, s->start<<PageShift, s->state, s->ref, s->sweepgen, h->sweepgen);
  372. runtime_throw("MHeap_FreeLocked - invalid free");
  373. }
  374. mstats.heap_idle += s->npages<<PageShift;
  375. s->state = MSpanFree;
  376. runtime_MSpanList_Remove(s);
  377. // Stamp newly unused spans. The scavenger will use that
  378. // info to potentially give back some pages to the OS.
  379. s->unusedsince = runtime_nanotime();
  380. s->npreleased = 0;
  381. // Coalesce with earlier, later spans.
  382. p = s->start;
  383. p -= (uintptr)h->arena_start >> PageShift;
  384. if(p > 0 && (t = h->spans[p-1]) != nil && t->state != MSpanInUse) {
  385. s->start = t->start;
  386. s->npages += t->npages;
  387. s->npreleased = t->npreleased; // absorb released pages
  388. s->needzero |= t->needzero;
  389. p -= t->npages;
  390. h->spans[p] = s;
  391. runtime_MSpanList_Remove(t);
  392. t->state = MSpanDead;
  393. runtime_FixAlloc_Free(&h->spanalloc, t);
  394. }
  395. if((p+s->npages)*sizeof(h->spans[0]) < h->spans_mapped && (t = h->spans[p+s->npages]) != nil && t->state != MSpanInUse) {
  396. s->npages += t->npages;
  397. s->npreleased += t->npreleased;
  398. s->needzero |= t->needzero;
  399. h->spans[p + s->npages - 1] = s;
  400. runtime_MSpanList_Remove(t);
  401. t->state = MSpanDead;
  402. runtime_FixAlloc_Free(&h->spanalloc, t);
  403. }
  404. // Insert s into appropriate list.
  405. if(s->npages < nelem(h->free))
  406. runtime_MSpanList_Insert(&h->free[s->npages], s);
  407. else
  408. runtime_MSpanList_Insert(&h->freelarge, s);
  409. }
  410. static void
  411. forcegchelper(void *vnote)
  412. {
  413. Note *note = (Note*)vnote;
  414. runtime_gc(1);
  415. runtime_notewakeup(note);
  416. }
  417. static uintptr
  418. scavengelist(MSpan *list, uint64 now, uint64 limit)
  419. {
  420. uintptr released, sumreleased, start, end, pagesize;
  421. MSpan *s;
  422. if(runtime_MSpanList_IsEmpty(list))
  423. return 0;
  424. sumreleased = 0;
  425. for(s=list->next; s != list; s=s->next) {
  426. if((now - s->unusedsince) > limit && s->npreleased != s->npages) {
  427. released = (s->npages - s->npreleased) << PageShift;
  428. mstats.heap_released += released;
  429. sumreleased += released;
  430. s->npreleased = s->npages;
  431. start = s->start << PageShift;
  432. end = start + (s->npages << PageShift);
  433. // Round start up and end down to ensure we
  434. // are acting on entire pages.
  435. pagesize = getpagesize();
  436. start = ROUND(start, pagesize);
  437. end &= ~(pagesize - 1);
  438. if(end > start)
  439. runtime_SysUnused((void*)start, end - start);
  440. }
  441. }
  442. return sumreleased;
  443. }
  444. static void
  445. scavenge(int32 k, uint64 now, uint64 limit)
  446. {
  447. uint32 i;
  448. uintptr sumreleased;
  449. MHeap *h;
  450. h = &runtime_mheap;
  451. sumreleased = 0;
  452. for(i=0; i < nelem(h->free); i++)
  453. sumreleased += scavengelist(&h->free[i], now, limit);
  454. sumreleased += scavengelist(&h->freelarge, now, limit);
  455. if(runtime_debug.gctrace > 0) {
  456. if(sumreleased > 0)
  457. runtime_printf("scvg%d: %D MB released\n", k, (uint64)sumreleased>>20);
  458. runtime_printf("scvg%d: inuse: %D, idle: %D, sys: %D, released: %D, consumed: %D (MB)\n",
  459. k, mstats.heap_inuse>>20, mstats.heap_idle>>20, mstats.heap_sys>>20,
  460. mstats.heap_released>>20, (mstats.heap_sys - mstats.heap_released)>>20);
  461. }
  462. }
  463. // Release (part of) unused memory to OS.
  464. // Goroutine created at startup.
  465. // Loop forever.
  466. void
  467. runtime_MHeap_Scavenger(void* dummy)
  468. {
  469. G *g;
  470. MHeap *h;
  471. uint64 tick, now, forcegc, limit;
  472. int64 unixnow;
  473. uint32 k;
  474. Note note, *notep;
  475. USED(dummy);
  476. g = runtime_g();
  477. g->issystem = true;
  478. g->isbackground = true;
  479. // If we go two minutes without a garbage collection, force one to run.
  480. forcegc = 2*60*1e9;
  481. // If a span goes unused for 5 minutes after a garbage collection,
  482. // we hand it back to the operating system.
  483. limit = 5*60*1e9;
  484. // Make wake-up period small enough for the sampling to be correct.
  485. if(forcegc < limit)
  486. tick = forcegc/2;
  487. else
  488. tick = limit/2;
  489. h = &runtime_mheap;
  490. for(k=0;; k++) {
  491. runtime_noteclear(&note);
  492. runtime_notetsleepg(&note, tick);
  493. runtime_lock(h);
  494. unixnow = runtime_unixnanotime();
  495. if(unixnow - mstats.last_gc > forcegc) {
  496. runtime_unlock(h);
  497. // The scavenger can not block other goroutines,
  498. // otherwise deadlock detector can fire spuriously.
  499. // GC blocks other goroutines via the runtime_worldsema.
  500. runtime_noteclear(&note);
  501. notep = &note;
  502. __go_go(forcegchelper, (void*)notep);
  503. runtime_notetsleepg(&note, -1);
  504. if(runtime_debug.gctrace > 0)
  505. runtime_printf("scvg%d: GC forced\n", k);
  506. runtime_lock(h);
  507. }
  508. now = runtime_nanotime();
  509. scavenge(k, now, limit);
  510. runtime_unlock(h);
  511. }
  512. }
  513. void runtime_debug_freeOSMemory(void) __asm__("runtime_debug.freeOSMemory");
  514. void
  515. runtime_debug_freeOSMemory(void)
  516. {
  517. runtime_gc(2); // force GC and do eager sweep
  518. runtime_lock(&runtime_mheap);
  519. scavenge(-1, ~(uintptr)0, 0);
  520. runtime_unlock(&runtime_mheap);
  521. }
  522. // Initialize a new span with the given start and npages.
  523. void
  524. runtime_MSpan_Init(MSpan *span, PageID start, uintptr npages)
  525. {
  526. span->next = nil;
  527. span->prev = nil;
  528. span->start = start;
  529. span->npages = npages;
  530. span->freelist = nil;
  531. span->ref = 0;
  532. span->sizeclass = 0;
  533. span->incache = false;
  534. span->elemsize = 0;
  535. span->state = MSpanDead;
  536. span->unusedsince = 0;
  537. span->npreleased = 0;
  538. span->types.compression = MTypes_Empty;
  539. span->specialLock.key = 0;
  540. span->specials = nil;
  541. span->needzero = 0;
  542. span->freebuf = nil;
  543. }
  544. // Initialize an empty doubly-linked list.
  545. void
  546. runtime_MSpanList_Init(MSpan *list)
  547. {
  548. list->state = MSpanListHead;
  549. list->next = list;
  550. list->prev = list;
  551. }
  552. void
  553. runtime_MSpanList_Remove(MSpan *span)
  554. {
  555. if(span->prev == nil && span->next == nil)
  556. return;
  557. span->prev->next = span->next;
  558. span->next->prev = span->prev;
  559. span->prev = nil;
  560. span->next = nil;
  561. }
  562. bool
  563. runtime_MSpanList_IsEmpty(MSpan *list)
  564. {
  565. return list->next == list;
  566. }
  567. void
  568. runtime_MSpanList_Insert(MSpan *list, MSpan *span)
  569. {
  570. if(span->next != nil || span->prev != nil) {
  571. runtime_printf("failed MSpanList_Insert %p %p %p\n", span, span->next, span->prev);
  572. runtime_throw("MSpanList_Insert");
  573. }
  574. span->next = list->next;
  575. span->prev = list;
  576. span->next->prev = span;
  577. span->prev->next = span;
  578. }
  579. void
  580. runtime_MSpanList_InsertBack(MSpan *list, MSpan *span)
  581. {
  582. if(span->next != nil || span->prev != nil) {
  583. runtime_printf("failed MSpanList_Insert %p %p %p\n", span, span->next, span->prev);
  584. runtime_throw("MSpanList_Insert");
  585. }
  586. span->next = list;
  587. span->prev = list->prev;
  588. span->next->prev = span;
  589. span->prev->next = span;
  590. }
  591. // Adds the special record s to the list of special records for
  592. // the object p. All fields of s should be filled in except for
  593. // offset & next, which this routine will fill in.
  594. // Returns true if the special was successfully added, false otherwise.
  595. // (The add will fail only if a record with the same p and s->kind
  596. // already exists.)
  597. static bool
  598. addspecial(void *p, Special *s)
  599. {
  600. MSpan *span;
  601. Special **t, *x;
  602. uintptr offset;
  603. byte kind;
  604. span = runtime_MHeap_LookupMaybe(&runtime_mheap, p);
  605. if(span == nil)
  606. runtime_throw("addspecial on invalid pointer");
  607. // Ensure that the span is swept.
  608. // GC accesses specials list w/o locks. And it's just much safer.
  609. runtime_m()->locks++;
  610. runtime_MSpan_EnsureSwept(span);
  611. offset = (uintptr)p - (span->start << PageShift);
  612. kind = s->kind;
  613. runtime_lock(&span->specialLock);
  614. // Find splice point, check for existing record.
  615. t = &span->specials;
  616. while((x = *t) != nil) {
  617. if(offset == x->offset && kind == x->kind) {
  618. runtime_unlock(&span->specialLock);
  619. runtime_m()->locks--;
  620. return false; // already exists
  621. }
  622. if(offset < x->offset || (offset == x->offset && kind < x->kind))
  623. break;
  624. t = &x->next;
  625. }
  626. // Splice in record, fill in offset.
  627. s->offset = offset;
  628. s->next = x;
  629. *t = s;
  630. runtime_unlock(&span->specialLock);
  631. runtime_m()->locks--;
  632. return true;
  633. }
  634. // Removes the Special record of the given kind for the object p.
  635. // Returns the record if the record existed, nil otherwise.
  636. // The caller must FixAlloc_Free the result.
  637. static Special*
  638. removespecial(void *p, byte kind)
  639. {
  640. MSpan *span;
  641. Special *s, **t;
  642. uintptr offset;
  643. span = runtime_MHeap_LookupMaybe(&runtime_mheap, p);
  644. if(span == nil)
  645. runtime_throw("removespecial on invalid pointer");
  646. // Ensure that the span is swept.
  647. // GC accesses specials list w/o locks. And it's just much safer.
  648. runtime_m()->locks++;
  649. runtime_MSpan_EnsureSwept(span);
  650. offset = (uintptr)p - (span->start << PageShift);
  651. runtime_lock(&span->specialLock);
  652. t = &span->specials;
  653. while((s = *t) != nil) {
  654. // This function is used for finalizers only, so we don't check for
  655. // "interior" specials (p must be exactly equal to s->offset).
  656. if(offset == s->offset && kind == s->kind) {
  657. *t = s->next;
  658. runtime_unlock(&span->specialLock);
  659. runtime_m()->locks--;
  660. return s;
  661. }
  662. t = &s->next;
  663. }
  664. runtime_unlock(&span->specialLock);
  665. runtime_m()->locks--;
  666. return nil;
  667. }
  668. // Adds a finalizer to the object p. Returns true if it succeeded.
  669. bool
  670. runtime_addfinalizer(void *p, FuncVal *f, const FuncType *ft, const PtrType *ot)
  671. {
  672. SpecialFinalizer *s;
  673. runtime_lock(&runtime_mheap.speciallock);
  674. s = runtime_FixAlloc_Alloc(&runtime_mheap.specialfinalizeralloc);
  675. runtime_unlock(&runtime_mheap.speciallock);
  676. s->kind = KindSpecialFinalizer;
  677. s->fn = f;
  678. s->ft = ft;
  679. s->ot = ot;
  680. if(addspecial(p, s))
  681. return true;
  682. // There was an old finalizer
  683. runtime_lock(&runtime_mheap.speciallock);
  684. runtime_FixAlloc_Free(&runtime_mheap.specialfinalizeralloc, s);
  685. runtime_unlock(&runtime_mheap.speciallock);
  686. return false;
  687. }
  688. // Removes the finalizer (if any) from the object p.
  689. void
  690. runtime_removefinalizer(void *p)
  691. {
  692. SpecialFinalizer *s;
  693. s = (SpecialFinalizer*)removespecial(p, KindSpecialFinalizer);
  694. if(s == nil)
  695. return; // there wasn't a finalizer to remove
  696. runtime_lock(&runtime_mheap.speciallock);
  697. runtime_FixAlloc_Free(&runtime_mheap.specialfinalizeralloc, s);
  698. runtime_unlock(&runtime_mheap.speciallock);
  699. }
  700. // Set the heap profile bucket associated with addr to b.
  701. void
  702. runtime_setprofilebucket(void *p, Bucket *b)
  703. {
  704. SpecialProfile *s;
  705. runtime_lock(&runtime_mheap.speciallock);
  706. s = runtime_FixAlloc_Alloc(&runtime_mheap.specialprofilealloc);
  707. runtime_unlock(&runtime_mheap.speciallock);
  708. s->kind = KindSpecialProfile;
  709. s->b = b;
  710. if(!addspecial(p, s))
  711. runtime_throw("setprofilebucket: profile already set");
  712. }
  713. // Do whatever cleanup needs to be done to deallocate s. It has
  714. // already been unlinked from the MSpan specials list.
  715. // Returns true if we should keep working on deallocating p.
  716. bool
  717. runtime_freespecial(Special *s, void *p, uintptr size, bool freed)
  718. {
  719. SpecialFinalizer *sf;
  720. SpecialProfile *sp;
  721. switch(s->kind) {
  722. case KindSpecialFinalizer:
  723. sf = (SpecialFinalizer*)s;
  724. runtime_queuefinalizer(p, sf->fn, sf->ft, sf->ot);
  725. runtime_lock(&runtime_mheap.speciallock);
  726. runtime_FixAlloc_Free(&runtime_mheap.specialfinalizeralloc, sf);
  727. runtime_unlock(&runtime_mheap.speciallock);
  728. return false; // don't free p until finalizer is done
  729. case KindSpecialProfile:
  730. sp = (SpecialProfile*)s;
  731. runtime_MProf_Free(sp->b, size, freed);
  732. runtime_lock(&runtime_mheap.speciallock);
  733. runtime_FixAlloc_Free(&runtime_mheap.specialprofilealloc, sp);
  734. runtime_unlock(&runtime_mheap.speciallock);
  735. return true;
  736. default:
  737. runtime_throw("bad special kind");
  738. return true;
  739. }
  740. }
  741. // Free all special records for p.
  742. void
  743. runtime_freeallspecials(MSpan *span, void *p, uintptr size)
  744. {
  745. Special *s, **t, *list;
  746. uintptr offset;
  747. if(span->sweepgen != runtime_mheap.sweepgen)
  748. runtime_throw("runtime: freeallspecials: unswept span");
  749. // first, collect all specials into the list; then, free them
  750. // this is required to not cause deadlock between span->specialLock and proflock
  751. list = nil;
  752. offset = (uintptr)p - (span->start << PageShift);
  753. runtime_lock(&span->specialLock);
  754. t = &span->specials;
  755. while((s = *t) != nil) {
  756. if(offset + size <= s->offset)
  757. break;
  758. if(offset <= s->offset) {
  759. *t = s->next;
  760. s->next = list;
  761. list = s;
  762. } else
  763. t = &s->next;
  764. }
  765. runtime_unlock(&span->specialLock);
  766. while(list != nil) {
  767. s = list;
  768. list = s->next;
  769. if(!runtime_freespecial(s, p, size, true))
  770. runtime_throw("can't explicitly free an object with a finalizer");
  771. }
  772. }
  773. // Split an allocated span into two equal parts.
  774. void
  775. runtime_MHeap_SplitSpan(MHeap *h, MSpan *s)
  776. {
  777. MSpan *t;
  778. MCentral *c;
  779. uintptr i;
  780. uintptr npages;
  781. PageID p;
  782. if(s->state != MSpanInUse)
  783. runtime_throw("MHeap_SplitSpan on a free span");
  784. if(s->sizeclass != 0 && s->ref != 1)
  785. runtime_throw("MHeap_SplitSpan doesn't have an allocated object");
  786. npages = s->npages;
  787. // remove the span from whatever list it is in now
  788. if(s->sizeclass > 0) {
  789. // must be in h->central[x].empty
  790. c = &h->central[s->sizeclass];
  791. runtime_lock(c);
  792. runtime_MSpanList_Remove(s);
  793. runtime_unlock(c);
  794. runtime_lock(h);
  795. } else {
  796. // must be in h->busy/busylarge
  797. runtime_lock(h);
  798. runtime_MSpanList_Remove(s);
  799. }
  800. // heap is locked now
  801. if(npages == 1) {
  802. // convert span of 1 PageSize object to a span of 2 PageSize/2 objects.
  803. s->ref = 2;
  804. s->sizeclass = runtime_SizeToClass(PageSize/2);
  805. s->elemsize = PageSize/2;
  806. } else {
  807. // convert span of n>1 pages into two spans of n/2 pages each.
  808. if((s->npages & 1) != 0)
  809. runtime_throw("MHeap_SplitSpan on an odd size span");
  810. // compute position in h->spans
  811. p = s->start;
  812. p -= (uintptr)h->arena_start >> PageShift;
  813. // Allocate a new span for the first half.
  814. t = runtime_FixAlloc_Alloc(&h->spanalloc);
  815. runtime_MSpan_Init(t, s->start, npages/2);
  816. t->limit = (byte*)((t->start + npages/2) << PageShift);
  817. t->state = MSpanInUse;
  818. t->elemsize = npages << (PageShift - 1);
  819. t->sweepgen = s->sweepgen;
  820. if(t->elemsize <= MaxSmallSize) {
  821. t->sizeclass = runtime_SizeToClass(t->elemsize);
  822. t->ref = 1;
  823. }
  824. // the old span holds the second half.
  825. s->start += npages/2;
  826. s->npages = npages/2;
  827. s->elemsize = npages << (PageShift - 1);
  828. if(s->elemsize <= MaxSmallSize) {
  829. s->sizeclass = runtime_SizeToClass(s->elemsize);
  830. s->ref = 1;
  831. }
  832. // update span lookup table
  833. for(i = p; i < p + npages/2; i++)
  834. h->spans[i] = t;
  835. }
  836. // place the span into a new list
  837. if(s->sizeclass > 0) {
  838. runtime_unlock(h);
  839. c = &h->central[s->sizeclass];
  840. runtime_lock(c);
  841. // swept spans are at the end of the list
  842. runtime_MSpanList_InsertBack(&c->empty, s);
  843. runtime_unlock(c);
  844. } else {
  845. // Swept spans are at the end of lists.
  846. if(s->npages < nelem(h->free))
  847. runtime_MSpanList_InsertBack(&h->busy[s->npages], s);
  848. else
  849. runtime_MSpanList_InsertBack(&h->busylarge, s);
  850. runtime_unlock(h);
  851. }
  852. }