1 #define COLLECTOR_C
2 #include "Collector.h"
3 #undef COLLECTOR_C
4 
5 #include <assert.h>
6 #include <time.h>
7 
8 #ifdef COLLECTOR_TIMER_ON
9 #define BEGIN_TIMER  self->clocksUsed -= clock();
10 #define END_TIMER    self->clocksUsed += clock();
11 #else
12 #define BEGIN_TIMER
13 #define END_TIMER
14 #endif
15 
Collector_new(void)16 Collector *Collector_new(void)
17 {
18 	Collector *self = (Collector *)io_calloc(1, sizeof(Collector));
19 
20 	self->retainedValues = List_new();
21 
22 	self->whites = CollectorMarker_new();
23 	self->grays  = CollectorMarker_new();
24 	self->blacks = CollectorMarker_new();
25 	self->freed = CollectorMarker_new();
26 
27 	CollectorMarker_loop(self->whites);
28 	CollectorMarker_removeIfNeededAndInsertAfter_(self->grays, self->whites);
29 	CollectorMarker_removeIfNeededAndInsertAfter_(self->blacks, self->grays);
30 	CollectorMarker_removeIfNeededAndInsertAfter_(self->freed, self->blacks);
31 
32 	// important to set colors *after* inserts, since inserts set colors
33 	CollectorMarker_setColor_(self->whites, COLLECTOR_INITIAL_WHITE);
34 	CollectorMarker_setColor_(self->blacks, COLLECTOR_INITIAL_BLACK);
35 	CollectorMarker_setColor_(self->grays,  COLLECTOR_GRAY);
36 	CollectorMarker_setColor_(self->freed,  COLLECTOR_FREE);
37 
38 	Collector_setSafeModeOn_(self, 1);
39 	self->allocated = 0;
40 
41 	self->allocatedSweepLevel = 3000;
42 	self->allocatedStep = 1.1f;
43 	self->marksPerAlloc = 2;
44 
45 #ifdef COLLECTOR_USE_NONINCREMENTAL_MARK_SWEEP
46 	self->allocsPerSweep = 10000;
47 #endif
48 
49 	self->clocksUsed = 0;
50 
51 	Collector_check(self);
52 
53 	return self;
54 }
55 
Collector_check(Collector * self)56 void Collector_check(Collector *self)
57 {
58 	CollectorMarker *w = self->whites;
59 	CollectorMarker *g = self->grays;
60 	CollectorMarker *b = self->blacks;
61 
62 	// colors are different
63 	assert(w->color != g->color);
64 	assert(w->color != b->color);
65 	assert(g->color != b->color);
66 
67 	// prev color is different
68 	assert(w->prev->color != w->color);
69 	assert(g->prev->color != g->color);
70 	assert(b->prev->color != b->color);
71 
72 	CollectorMarker_check(w);
73 }
74 
CollectorMarker_checkObjectPointer(CollectorMarker * marker)75 size_t CollectorMarker_checkObjectPointer(CollectorMarker *marker)
76 {
77 	if (marker->object == NULL)
78 	{
79 		printf("WARNING: Collector found a null object pointer on marker %p! Memory is likely hosed.\n", (void *)marker);
80 		exit(-1);
81 		return 1;
82 	}
83 	else
84 	{
85 		// read a word of memory to check for bad pointers
86 		uintptr_t p = *(uintptr_t *)(marker->object);
87 		return p-p; // so compiler doesn't complain about unused variable
88 	}
89 
90 	return 0;
91 }
92 
Collector_checkObjectPointers(Collector * self)93 void Collector_checkObjectPointers(Collector *self)
94 {
95 	COLLECTMARKER_FOREACH(self->blacks, v, CollectorMarker_checkObjectPointer(v); );
96 	COLLECTMARKER_FOREACH(self->grays,  v, CollectorMarker_checkObjectPointer(v); );
97 	COLLECTMARKER_FOREACH(self->whites, v, CollectorMarker_checkObjectPointer(v); );
98 }
99 
Collector_checkObjectsWith_(Collector * self,CollectorCheckFunc * func)100 void Collector_checkObjectsWith_(Collector *self, CollectorCheckFunc *func)
101 {
102 	COLLECTMARKER_FOREACH(self->blacks, v, func(v); );
103 	COLLECTMARKER_FOREACH(self->grays,  v, func(v); );
104 	COLLECTMARKER_FOREACH(self->whites, v, func(v); );
105 }
106 
Collector_free(Collector * self)107 void Collector_free(Collector *self)
108 {
109 	List_free(self->retainedValues);
110 	CollectorMarker_free(self->whites);
111 	CollectorMarker_free(self->grays);
112 	CollectorMarker_free(self->blacks);
113 	CollectorMarker_free(self->freed);
114 	io_free(self);
115 }
116 
Collector_setMarkBeforeSweepValue_(Collector * self,void * v)117 void Collector_setMarkBeforeSweepValue_(Collector *self, void *v)
118 {
119 	self->markBeforeSweepValue = v;
120 }
121 
122 // callbacks
123 
Collector_setFreeFunc_(Collector * self,CollectorFreeFunc * func)124 void Collector_setFreeFunc_(Collector *self, CollectorFreeFunc *func)
125 {
126 	self->freeFunc = func;
127 }
128 
Collector_setWillFreeFunc_(Collector * self,CollectorWillFreeFunc * func)129 void Collector_setWillFreeFunc_(Collector *self, CollectorWillFreeFunc *func)
130 {
131 	self->willFreeFunc = func;
132 }
133 
Collector_setMarkFunc_(Collector * self,CollectorMarkFunc * func)134 void Collector_setMarkFunc_(Collector *self, CollectorMarkFunc *func)
135 {
136 	self->markFunc = func;
137 }
138 
139 // marks per alloc
140 
Collector_setMarksPerAlloc_(Collector * self,float n)141 void Collector_setMarksPerAlloc_(Collector *self, float n)
142 {
143 	self->marksPerAlloc = n;
144 }
145 
Collector_marksPerAlloc(Collector * self)146 float Collector_marksPerAlloc(Collector *self)
147 {
148 	return self->marksPerAlloc;
149 }
150 
151 // allocated step
152 
Collector_setAllocatedStep_(Collector * self,float n)153 void Collector_setAllocatedStep_(Collector *self, float n)
154 {
155 	self->allocatedStep = n;
156 }
157 
Collector_allocatedStep(Collector * self)158 float Collector_allocatedStep(Collector *self)
159 {
160 	return self->allocatedStep;
161 }
162 
Collector_setDebug_(Collector * self,int b)163 void Collector_setDebug_(Collector *self, int b)
164 {
165 	self->debugOn = b ? 1 : 0;
166 }
167 
Collector_setSafeModeOn_(Collector * self,int b)168 void Collector_setSafeModeOn_(Collector *self, int b)
169 {
170 	self->safeMode = b ? 1 : 0;
171 }
172 
173 
174 // retain/release --------------------------------------------
175 
Collector_retain_(Collector * self,void * v)176 void *Collector_retain_(Collector *self, void *v)
177 {
178 	List_append_(self->retainedValues, v);
179 	CollectorMarker_removeIfNeededAndInsertAfter_(v, self->grays);
180 	return v;
181 }
182 
Collector_stopRetaining_(Collector * self,void * v)183 void Collector_stopRetaining_(Collector *self, void *v)
184 {
185 	List_removeLast_(self->retainedValues, v);
186 }
187 
Collector_removeAllRetainedValues(Collector * self)188 void Collector_removeAllRetainedValues(Collector *self)
189 {
190 	List_removeAll(self->retainedValues);
191 }
192 
193 // pausing -------------------------------------------------------------------
194 
Collector_isPaused(Collector * self)195 int Collector_isPaused(Collector *self)
196 {
197 	return (self->pauseCount != 0);
198 }
199 
Collector_pushPause(Collector * self)200 void Collector_pushPause(Collector *self)
201 {
202 	self->pauseCount ++;
203 }
204 
Collector_popPause(Collector * self)205 void Collector_popPause(Collector *self)
206 {
207 	assert(self->pauseCount > 0);
208 
209 	self->pauseCount --;
210 
211 	//printf("collect newMarkerCount %i\n", self->newMarkerCount);
212 #ifdef COLLECTOR_USE_NONINCREMENTAL_MARK_SWEEP
213 	if (self->pauseCount == 0 && self->newMarkerCount > self->allocsPerSweep)
214 	{
215 		//printf("collect newMarkerCount %i\n", self->newMarkerCount);
216 		if(self->debugOn)
217 		{
218 			printf("\n  newMarkerCount %i\n", (int)self->newMarkerCount);
219 		}
220 
221 		self->newMarkerCount = 0;
222 		Collector_collect(self);
223 	}
224 #else
225 	if (self->pauseCount == 0 && self->queuedMarks > 1.0)
226 	{
227 		Collector_markPhase(self);
228 	}
229 #endif
230 }
231 
232 #ifdef COLLECTOR_USE_NONINCREMENTAL_MARK_SWEEP
233 
Collector_setAllocsPerSweep_(Collector * self,int n)234 void Collector_setAllocsPerSweep_(Collector *self, int n)
235 {
236 	self->allocsPerSweep = n;
237 }
238 
Collector_allocsPerSweep(Collector * self)239 float Collector_allocsPerSweep(Collector *self)
240 {
241 	return self->allocsPerSweep;
242 }
243 
244 #endif
245 
246 // adding ------------------------------------------------
247 
Collector_newMarker(Collector * self)248 CollectorMarker *Collector_newMarker(Collector *self)
249 {
250 	CollectorMarker *m;
251 	BEGIN_TIMER
252 	m = self->freed->next;
253 
254 	if (m->color != self->freed->color)
255 	{
256 		m = CollectorMarker_new();
257 		//printf("new marker\n");
258 	}
259 	else
260 	{
261 		//printf("using recycled marker\n");
262 	}
263 
264 	self->allocated ++;
265 
266 	Collector_addValue_(self, m);
267 	END_TIMER
268 	return m;
269 }
270 
Collector_addValue_(Collector * self,void * v)271 void Collector_addValue_(Collector *self, void *v)
272 {
273 	CollectorMarker_removeIfNeededAndInsertAfter_(v, self->whites);
274 
275 	self->queuedMarks += self->marksPerAlloc;
276 	#ifdef COLLECTOR_USE_NONINCREMENTAL_MARK_SWEEP
277 	self->newMarkerCount ++;
278 	#endif
279 	// pauseCount is never zero here...
280 	/*
281 	if (self->pauseCount == 0)
282 	{
283 		if(self->allocated > self->allocatedSweepLevel)
284 		{
285 			Collector_sweep(self);
286 		}
287 		else if (self->queuedMarks > 1.0)
288 		{
289 			Collector_markPhase(self);
290 		}
291 	}
292 	*/
293 }
294 
295 // collection ------------------------------------------------
296 
Collector_markGrays(Collector * self)297 void Collector_markGrays(Collector *self)
298 {
299 	CollectorMarkFunc *markFunc = self->markFunc;
300 
301 	COLLECTMARKER_FOREACH(self->grays, v,
302 					  //(*markFunc)(v); Collector_makeBlack_(self, v);
303 					  if ((*markFunc)(v)) Collector_makeBlack_(self, v);
304 					  //count ++;
305 					  );
306 	self->queuedMarks = 0;
307 }
308 
Collector_markGraysMax_(Collector * self,size_t max)309 void Collector_markGraysMax_(Collector *self, size_t max)
310 {
311 	CollectorMarkFunc *markFunc = self->markFunc;
312 
313 	if (!max) return;
314 
315 	COLLECTMARKER_FOREACH(self->grays, v,
316 					  //(*markFunc)(v); Collector_makeBlack_(self, v);
317 					  if ((*markFunc)(v)) Collector_makeBlack_(self, v);
318 					  max --;
319 					  if(0 == max) break;
320 					  );
321 
322 	self->queuedMarks = 0;
323 }
324 
Collector_sendWillFreeCallbacks(Collector * self)325 void Collector_sendWillFreeCallbacks(Collector *self)
326 {
327 	CollectorWillFreeFunc *willFreeFunc = self->willFreeFunc;
328 
329 	if (willFreeFunc)
330 	{
331 		Collector_pushPause(self); // since the callback may create new objects
332 		COLLECTMARKER_FOREACH(self->whites, v, (*willFreeFunc)(v));
333 		Collector_popPause(self);
334 	}
335 }
336 
Collector_freeWhites(Collector * self)337 size_t Collector_freeWhites(Collector *self)
338 {
339 	size_t count = 0;
340 	CollectorFreeFunc *freeFunc = self->freeFunc;
341 
342 	COLLECTMARKER_FOREACH(self->whites, v,
343 					  (*freeFunc)(v);
344 					  //v->object = 0x0;
345 					  Collector_makeFree_(self, v);
346 					  count ++;
347 					  );
348 
349 	self->allocated -= count;
350 
351 	return count;
352 }
353 
354 // ---------------------
355 
Collector_initPhase(Collector * self)356 void Collector_initPhase(Collector *self)
357 {
358 	LIST_FOREACH(self->retainedValues, i, v, Collector_makeGray_(self, v));
359 }
360 
Collector_markForTimePeriod_(Collector * self,double seconds)361 void Collector_markForTimePeriod_(Collector *self, double seconds)
362 {
363 	clock_t until = clock() + seconds * CLOCKS_PER_SEC;
364 
365 	for (;;)
366 	{
367 		if (until < clock()) return;
368 
369 		if (CollectorMarker_colorSetIsEmpty(self->grays))
370 		{
371 			Collector_sweep(self);
372 			return;
373 		}
374 
375 		Collector_markGrays(self);
376 	}
377 }
378 
Collector_markPhase(Collector * self)379 void Collector_markPhase(Collector *self)
380 {
381 	if(self->allocated > self->allocatedSweepLevel)
382 	{
383 		Collector_sweep(self);
384 	}
385 	else
386 	{
387 		Collector_markGraysMax_(self, self->queuedMarks);
388 	}
389 
390 	if (CollectorMarker_isEmpty(self->grays))
391 	{
392 		Collector_freeWhites(self);
393 		//Collector_sweepPhase(self);
394 	}
395 }
396 
Collector_sweep(Collector * self)397 size_t Collector_sweep(Collector *self)
398 {
399 	size_t freedCount = Collector_sweepPhase(self);
400 
401 	/*
402 	if (self->debugOn)
403 	{
404 		size_t freedCount2 = Collector_sweepPhase(self);
405 		return freedCount + freedCount2;
406 	}
407 	*/
408 
409 	return freedCount;
410 }
411 
Collector_sweepPhase(Collector * self)412 size_t Collector_sweepPhase(Collector *self)
413 {
414 	size_t freedCount = 0;
415 
416 	self->newMarkerCount = 0;
417 
418 	if (self->debugOn)
419 	{
420 		printf("Collector_sweepPhase()\n");
421 		//printf("  newMarkerCount %i\n", (int)self->newMarkerCount);
422 		printf("  allocsPerSweep %i\n", (int)self->allocsPerSweep);
423 		printf("  allocated %i\n", (int)self->allocated);
424 		printf("  allocatedSweepLevel %i\n", (int)self->allocatedSweepLevel);
425 	}
426 
427 	if (self->markBeforeSweepValue)
428 	{
429 		Collector_makeGray_(self, self->markBeforeSweepValue);
430 	}
431 
432 	while (!CollectorMarker_isEmpty(self->grays))
433 	{
434 		do
435 		{
436 			Collector_markGrays(self);
437 		} while (!CollectorMarker_isEmpty(self->grays));
438 
439 		Collector_sendWillFreeCallbacks(self);
440 	}
441 
442 	freedCount = Collector_freeWhites(self);
443 	self->sweepCount ++;
444 	//printf("whites freed %i\n", (int)freedCount);
445 
446 	{
447 	CollectorMarker *b = self->blacks;
448 	self->blacks = self->whites;
449 	self->whites = b;
450 	}
451 
452 	Collector_initPhase(self);
453 
454 	self->allocatedSweepLevel = self->allocated * self->allocatedStep;
455 	//printf("allocatedSweepLevel = %i\n", self->allocatedSweepLevel);
456 
457 	return freedCount;
458 }
459 
Collector_collect(Collector * self)460 size_t Collector_collect(Collector *self)
461 {
462 	size_t result;
463 
464 	BEGIN_TIMER
465 	if (self->pauseCount)
466 	{
467 		printf("Collector warning: attempt to force collection while pause count = %i\n", self->pauseCount);
468 		result = 0;
469 	}
470 	else
471 	{
472 		// collect twice to ensure that any now unreachable blacks get collected
473 		result = Collector_sweepPhase(self) + Collector_sweepPhase(self);
474 	}
475 	END_TIMER
476 	return result;
477 }
478 
Collector_freeAllValues(Collector * self)479 size_t Collector_freeAllValues(Collector *self)
480 {
481 	size_t count = 0;
482 	CollectorFreeFunc *freeFunc = self->freeFunc;
483 	COLLECTOR_FOREACH(self, v, (*freeFunc)(v); CollectorMarker_free(v); count ++;);
484 	self->allocated -= count;
485 	COLLECTMARKER_FOREACH(self->freed, v,  CollectorMarker_free(v); count ++;);
486 	return count;
487 }
488 
489 // helpers ----------------------------------------------------------------------------
490 
Collector_show(Collector * self)491 void Collector_show(Collector *self)
492 {
493 	printf("black: %i\n", (int)CollectorMarker_count(self->blacks));
494 	printf("gray:  %i\n", (int)CollectorMarker_count(self->grays));
495 	printf("white: %i\n", (int)CollectorMarker_count(self->whites));
496 }
497 
Collector_colorNameFor_(Collector * self,void * v)498 char *Collector_colorNameFor_(Collector *self, void *v)
499 {
500 	if (self->whites->color == MARKER(v)->color) return "white";
501 	if (self->grays->color  == MARKER(v)->color) return "gray";
502 	if (self->blacks->color == MARKER(v)->color) return "black";
503 	return "off-white";
504 }
505 
Collector_timeUsed(Collector * self)506 double Collector_timeUsed(Collector *self)
507 {
508 	return (double)self->clocksUsed / (double)CLOCKS_PER_SEC;
509 }
510 
511