Skip to content

Commit 0a7c915

Browse files
committed
[GC] When using free, make sure we leave space int he thread bin to accomodate it.
1 parent d08de37 commit 0a7c915

File tree

2 files changed

+57
-3
lines changed

2 files changed

+57
-3
lines changed

sdlib/d/gc/tbin.d

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public:
7575

7676
void refill(ref CachedExtentMap emap, shared(Arena)* arena,
7777
ref ThreadBinState state, ubyte sizeClass, size_t slotSize) {
78-
auto nfill = nmax >> state.fillShift;
78+
auto nfill = state.getFill(nmax);
7979
assert(nfill > 0);
8080

8181
/**
@@ -99,7 +99,14 @@ public:
9999
return true;
100100
}
101101

102-
void flushToFree(ref CachedExtentMap emap) {
102+
void flushToFree(ref CachedExtentMap emap, ref ThreadBinState state) {
103+
/**
104+
* When we use free explicitely, we want to make sure we have room
105+
* left in the bin to accomodate further freed elements, even in case
106+
* where we refill.
107+
*/
108+
state.onFlush();
109+
103110
/**
104111
* We do not have enough space in the bin, so start flushing.
105112
* However, we do not want to flush all of it, as it would leave
@@ -298,7 +305,25 @@ private:
298305

299306
struct ThreadBinState {
300307
bool refilled;
308+
bool flushed;
301309
ubyte fillShift;
310+
311+
uint getFill(ushort nmax) const {
312+
return nmax >> fillShift;
313+
}
314+
315+
bool onFlush() {
316+
if (flushed) {
317+
return false;
318+
}
319+
320+
flushed = true;
321+
if (fillShift == 0) {
322+
fillShift++;
323+
}
324+
325+
return true;
326+
}
302327
}
303328

304329
bool isValidThreadBinCapacity(uint capacity) {
@@ -521,3 +546,32 @@ unittest refill {
521546
"Invalid cached element count!");
522547
}
523548
}
549+
550+
unittest flushed {
551+
enum BinSize = 200;
552+
553+
// Setup the state.
554+
ThreadBinState state;
555+
assert(!state.flushed, "Thread bin flushed!");
556+
assert(state.getFill(BinSize) == BinSize, "Unexpected fill!");
557+
558+
// When we flush, we reduce the max fill.
559+
state.onFlush();
560+
561+
assert(state.flushed, "Thread bin not flushed!");
562+
assert(state.getFill(BinSize) == BinSize / 2, "Unexpected fill!");
563+
564+
// On repeat, nothing happens.
565+
state.onFlush();
566+
567+
assert(state.flushed, "Thread bin not flushed!");
568+
assert(state.getFill(BinSize) == BinSize / 2, "Unexpected fill!");
569+
570+
// When flushed is cleared, we redo, but never
571+
// reduce fill to less than half the bin.
572+
state.flushed = false;
573+
state.onFlush();
574+
575+
assert(state.flushed, "Thread bin not flushed!");
576+
assert(state.getFill(BinSize) == BinSize / 2, "Unexpected fill!");
577+
}

sdlib/d/gc/tcache.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ private:
320320
return;
321321
}
322322

323-
bin.flushToFree(emap);
323+
bin.flushToFree(emap, binStates[index]);
324324

325325
auto success = bin.free(ptr);
326326
assert(success, "Unable to free!");

0 commit comments

Comments
 (0)