aboutsummaryrefslogtreecommitdiffstats
path: root/mps/code/pool.c
diff options
context:
space:
mode:
authorNick Barnes2001-10-31 14:40:56 +0000
committerNick Barnes2001-10-31 14:40:56 +0000
commit7acfca905d76140f4cc0b09c9a12de237de364cd (patch)
tree3ed8babfa3a73d30f29e08ca5d5adcda4ca4e826 /mps/code/pool.c
parentb7ce4893f9902d57cd67ac9a92fa6c3d5a8fc833 (diff)
downloademacs-7acfca905d76140f4cc0b09c9a12de237de364cd.tar.gz
emacs-7acfca905d76140f4cc0b09c9a12de237de364cd.zip
Branch imports for masters.
Copied from Perforce Change: 23678 ServerID: perforce.ravenbrook.com
Diffstat (limited to 'mps/code/pool.c')
-rw-r--r--mps/code/pool.c576
1 files changed, 576 insertions, 0 deletions
diff --git a/mps/code/pool.c b/mps/code/pool.c
new file mode 100644
index 00000000000..b02f41f638b
--- /dev/null
+++ b/mps/code/pool.c
@@ -0,0 +1,576 @@
1/* impl.c.pool: POOL IMPLEMENTATION
2 *
3 * $HopeName: MMsrc!pool.c(trunk.75) $
4 * Copyright (C) 2001 Harlequin Limited. All rights reserved.
5 *
6 * DESIGN
7 *
8 * .design: See design.mps.class-interface and design.mps.pool.
9 *
10 * PURPOSE
11 *
12 * .purpose: This is the implementation of the generic pool interface.
13 * There are three sorts of functions provided:
14 * .purpose.support: Support functions for manipulating and accessing
15 * Pool and PoolClass objects (create, destroy, check, various
16 * accessors, and other miscellaneous functions).
17 * .purpose.dispatch: Dispatch functions that implement the generic
18 * function dispatch mechanism for Pool Classes (PoolAlloc, PoolFix,
19 * etc.).
20 * .purpose.core: A selection of default, trivial, or useful methods
21 * that Pool Classes can use as the implementations for some of their
22 * methods (such as PoolTrivWhiten, PoolNoFix, etc.).
23 *
24 * SOURCES
25 *
26 * .source: See .design also. PoolStruct and PoolClassStruct, the
27 * central types for this module, are defined in impl.h.mpmst, the
28 * corresponding abstract types in impl.h.mpmtypes. Declarations and
29 * prototypes are in impl.h.mpm. Several functions have macro versions
30 * defined in impl.h.mpm. */
31
32#include "mpm.h"
33
34SRCID(pool, "$HopeName: MMsrc!pool.c(trunk.75) $");
35
36
37/* PoolClassCheck -- check a pool class */
38
39Bool PoolClassCheck(PoolClass class)
40{
41 CHECKL(ProtocolClassCheck(&class->protocol));
42 CHECKL(class->name != NULL); /* Should be <=6 char C identifier */
43 CHECKL(class->size >= sizeof(PoolStruct));
44 /* Offset of generic Pool within class-specific instance cannot be */
45 /* greater than the size of the class-specific portion of the instance */
46 CHECKL(class->offset <= (size_t)(class->size - sizeof(PoolStruct)));
47 CHECKL(AttrCheck(class->attr));
48 CHECKL(FUNCHECK(class->init));
49 CHECKL(FUNCHECK(class->finish));
50 CHECKL(FUNCHECK(class->alloc));
51 CHECKL(FUNCHECK(class->free));
52 CHECKL(FUNCHECK(class->bufferFill));
53 CHECKL(FUNCHECK(class->bufferEmpty));
54 CHECKL(FUNCHECK(class->whiten));
55 CHECKL(FUNCHECK(class->grey));
56 CHECKL(FUNCHECK(class->scan));
57 CHECKL(FUNCHECK(class->fix));
58 CHECKL(FUNCHECK(class->reclaim));
59 CHECKL(FUNCHECK(class->rampBegin));
60 CHECKL(FUNCHECK(class->rampEnd));
61 CHECKL(FUNCHECK(class->framePush));
62 CHECKL(FUNCHECK(class->framePop));
63 CHECKL(FUNCHECK(class->framePopPending));
64 CHECKL(FUNCHECK(class->walk));
65 CHECKL(FUNCHECK(class->describe));
66 CHECKS(PoolClass, class);
67 return TRUE;
68}
69
70
71/* PoolCheck -- check the generic part of a pool */
72
73Bool PoolCheck(Pool pool)
74{
75 /* Checks ordered as per struct decl in impl.h.mpmst.pool */
76 CHECKS(Pool, pool);
77 /* Break modularity for checking efficiency */
78 CHECKL(pool->serial < ArenaGlobals(pool->arena)->poolSerial);
79 CHECKD(PoolClass, pool->class);
80 CHECKU(Arena, pool->arena);
81 CHECKL(RingCheck(&pool->arenaRing));
82 CHECKL(RingCheck(&pool->bufferRing));
83 /* Cannot check pool->bufferSerial */
84 CHECKL(RingCheck(&pool->segRing));
85 CHECKL(AlignCheck(pool->alignment));
86 /* normally pool->format iff pool->class->attr&AttrFMT, but not */
87 /* during pool initialization */
88 if (pool->format != NULL) {
89 CHECKL((pool->class->attr & AttrFMT) != 0);
90 }
91 CHECKL(pool->fillMutatorSize >= 0.0);
92 CHECKL(pool->emptyMutatorSize >= 0.0);
93 CHECKL(pool->fillInternalSize >= 0.0);
94 CHECKL(pool->emptyInternalSize >= 0.0);
95 return TRUE;
96}
97
98
99/* PoolInit, PoolInitV -- initialize a pool
100 *
101 * Initialize the generic fields of the pool and calls class-specific
102 * init. See design.mps.pool.align. */
103
104Res PoolInit(Pool pool, Arena arena, PoolClass class, ...)
105{
106 Res res;
107 va_list args;
108 va_start(args, class);
109 res = PoolInitV(pool, arena, class, args);
110 va_end(args);
111 return res;
112}
113
114Res PoolInitV(Pool pool, Arena arena, PoolClass class, va_list args)
115{
116 Res res;
117 Word classId;
118 Globals globals;
119
120 AVER(pool != NULL);
121 AVERT(Arena, arena);
122 AVERT(PoolClass, class);
123 globals = ArenaGlobals(arena);
124
125 pool->class = class;
126 /* label the pool class with its name */
127 if (!class->labelled) {
128 /* We could still get multiple labelling if multiple instances of */
129 /* the pool class get created simultaneously, but it's not worth */
130 /* putting another lock in the code. */
131 class->labelled = TRUE;
132 classId = EventInternString(class->name);
133 /* @@@@ this breaks design.mps.type.addr.use */
134 EventLabelAddr((Addr)class, classId);
135 }
136
137 pool->arena = arena;
138 RingInit(&pool->arenaRing);
139 RingInit(&pool->bufferRing);
140 RingInit(&pool->segRing);
141 pool->bufferSerial = (Serial)0;
142 pool->alignment = MPS_PF_ALIGN;
143 pool->format = NULL;
144 pool->fix = class->fix;
145 pool->fillMutatorSize = 0.0;
146 pool->emptyMutatorSize = 0.0;
147 pool->fillInternalSize = 0.0;
148 pool->emptyInternalSize = 0.0;
149
150 /* Initialise signature last; see design.mps.sig */
151 pool->sig = PoolSig;
152 pool->serial = globals->poolSerial;
153 ++(globals->poolSerial);
154
155 AVERT(Pool, pool);
156
157 /* Do class-specific initialization. */
158 res = (*class->init)(pool, args);
159 if (res != ResOK)
160 goto failInit;
161
162 /* Add initialized pool to list of pools in arena. */
163 RingAppend(&globals->poolRing, &pool->arenaRing);
164
165 return ResOK;
166
167failInit:
168 pool->sig = SigInvalid; /* Leave arena->poolSerial incremented */
169 RingFinish(&pool->segRing);
170 RingFinish(&pool->bufferRing);
171 RingFinish(&pool->arenaRing);
172 return res;
173}
174
175
176/* PoolCreate, PoolCreateV: Allocate and initialise pool */
177
178Res PoolCreate(Pool *poolReturn, Arena arena,
179 PoolClass class, ...)
180{
181 Res res;
182 va_list args;
183 va_start(args, class);
184 res = PoolCreateV(poolReturn, arena, class, args);
185 va_end(args);
186 return res;
187}
188
189Res PoolCreateV(Pool *poolReturn, Arena arena,
190 PoolClass class, va_list args)
191{
192 Res res;
193 Pool pool;
194 void *base;
195
196 AVER(poolReturn != NULL);
197 AVERT(Arena, arena);
198 AVERT(PoolClass, class);
199
200 /* .space.alloc: Allocate the pool instance structure with the size */
201 /* requested in the pool class. See .space.free */
202 res = ControlAlloc(&base, arena, class->size,
203 /* withReservoirPermit */ FALSE);
204 if (res != ResOK)
205 goto failControlAlloc;
206
207 /* base is the address of the class-specific pool structure. */
208 /* We calculate the address of the generic pool structure within the */
209 /* instance by using the offset information from the class. */
210 pool = (Pool)PointerAdd(base, class->offset);
211
212 /* Initialize the pool. */
213 res = PoolInitV(pool, arena, class, args);
214 if (res != ResOK)
215 goto failPoolInit;
216
217 *poolReturn = pool;
218 return ResOK;
219
220failPoolInit:
221 ControlFree(arena, base, class->size);
222failControlAlloc:
223 return res;
224}
225
226
227/* PoolFinish -- Finish pool including class-specific and generic fields. */
228
229void PoolFinish(Pool pool)
230{
231 AVERT(Pool, pool);
232
233 /* Do any class-specific finishing. */
234 (*pool->class->finish)(pool);
235
236 /* Detach the pool from the arena, and unsig it. */
237 RingRemove(&pool->arenaRing);
238 pool->sig = SigInvalid;
239
240 RingFinish(&pool->segRing);
241 RingFinish(&pool->bufferRing);
242 RingFinish(&pool->arenaRing);
243
244 EVENT_P(PoolFinish, pool);
245}
246
247
248/* PoolDestroy -- Finish and free pool. */
249
250void PoolDestroy(Pool pool)
251{
252 PoolClass class;
253 Arena arena;
254 Addr base;
255
256 AVERT(Pool, pool);
257
258 class = pool->class; /* } In case PoolFinish changes these */
259 arena = pool->arena; /* } */
260
261 /* Finish the pool instance structure. */
262 PoolFinish(pool);
263
264 /* .space.free: Free the pool instance structure. See .space.alloc */
265 base = AddrSub((Addr)pool, (Size)(class->offset));
266 ControlFree(arena, base, (Size)(class->size));
267}
268
269
270/* PoolDefaultBufferClass -- return the buffer class used by the pool */
271
272BufferClass PoolDefaultBufferClass(Pool pool)
273{
274 AVERT(Pool, pool);
275 return (*pool->class->bufferClass)();
276}
277
278
279/* PoolAlloc -- allocate a block of memory from a pool */
280
281Res PoolAlloc(Addr *pReturn, Pool pool, Size size,
282 Bool withReservoirPermit)
283{
284 Res res;
285
286 AVER(pReturn != NULL);
287 AVERT(Pool, pool);
288 AVER((pool->class->attr & AttrALLOC) != 0);
289 AVER(size > 0);
290 AVER(BoolCheck(withReservoirPermit));
291
292 res = (*pool->class->alloc)(pReturn, pool, size, withReservoirPermit);
293 if (res != ResOK)
294 return res;
295 /* Make sure that the allocated address was in the pool's memory. */
296 /* .hasaddr.critical: The PoolHasAddr check is expensive, and in */
297 /* allocation-bound programs this is on the critical path. */
298 AVER_CRITICAL(PoolHasAddr(pool, *pReturn));
299
300 /* All PoolAllocs should advance the allocation clock, so we count */
301 /* it all in the fillMutatorSize field. */
302 pool->fillMutatorSize += size;
303 ArenaGlobals(PoolArena(pool))->fillMutatorSize += size;
304
305 EVENT_PAW(PoolAlloc, pool, *pReturn, size);
306
307 return ResOK;
308}
309
310
311/* PoolFree -- deallocate a block of memory allocated from the pool */
312
313void PoolFree(Pool pool, Addr old, Size size)
314{
315 AVERT(Pool, pool);
316 AVER((pool->class->attr & AttrFREE) != 0);
317 AVER(old != NULL);
318 /* The pool methods should check that old is in pool. */
319 AVER(size > 0);
320 (*pool->class->free)(pool, old, size);
321
322 EVENT_PAW(PoolFree, pool, old, size);
323}
324
325
326Res PoolAccess(Pool pool, Seg seg, Addr addr,
327 AccessSet mode, MutatorFaultContext context)
328{
329 AVERT(Pool, pool);
330 AVERT(Seg, seg);
331 AVER(SegBase(seg) <= addr);
332 AVER(addr < SegLimit(seg));
333 /* Can't check mode as there is no check method */
334 /* Can't check MutatorFaultContext as there is no check method */
335
336 return (*pool->class->access)(pool, seg, addr, mode, context);
337}
338
339
340/* PoolWhiten, PoolGrey, PoolBlacken -- change color of a segment in the pool */
341
342Res PoolWhiten(Pool pool, Trace trace, Seg seg)
343{
344 AVERT(Pool, pool);
345 AVERT(Trace, trace);
346 AVERT(Seg, seg);
347 AVER(PoolArena(pool) == trace->arena);
348 AVER(SegPool(seg) == pool);
349 return (*pool->class->whiten)(pool, trace, seg);
350}
351
352void PoolGrey(Pool pool, Trace trace, Seg seg)
353{
354 AVERT(Pool, pool);
355 AVERT(Trace, trace);
356 AVERT(Seg, seg);
357 AVER(pool->arena == trace->arena);
358 AVER(SegPool(seg) == pool);
359 (*pool->class->grey)(pool, trace, seg);
360}
361
362void PoolBlacken(Pool pool, TraceSet traceSet, Seg seg)
363{
364 AVERT(Pool, pool);
365 AVERT(TraceSet, traceSet);
366 AVERT(Seg, seg);
367 AVER(SegPool(seg) == pool);
368 (*pool->class->blacken)(pool, traceSet, seg);
369}
370
371
372/* PoolScan -- scan a segment in the pool */
373
374Res PoolScan(Bool *totalReturn, ScanState ss, Pool pool, Seg seg)
375{
376 AVER(totalReturn != NULL);
377 AVERT(ScanState, ss);
378 AVERT(Pool, pool);
379 AVERT(Seg, seg);
380 AVER(ss->arena == pool->arena);
381
382 /* The segment must belong to the pool. */
383 AVER(pool == SegPool(seg));
384
385 /* We actually want to check that the rank we are scanning at */
386 /* (ss->rank) is at least as big as all the ranks in */
387 /* the segment (SegRankSet(seg)). It is tricky to check that, */
388 /* so we only check that either ss->rank is in the segment's */
389 /* ranks, or that ss->rank is exact. */
390 /* See impl.c.trace.scan.conservative */
391 AVER(ss->rank == RankEXACT || RankSetIsMember(SegRankSet(seg), ss->rank));
392
393 /* Should only scan segments which contain grey objects. */
394 AVER(TraceSetInter(SegGrey(seg), ss->traces) != TraceSetEMPTY);
395
396 return (*pool->class->scan)(totalReturn, ss, pool, seg);
397}
398
399
400/* PoolFix* -- fix a reference to an object in this pool
401 *
402 * See impl.h.mpm for macro version; see design.mps.pool.req.fix. */
403
404Res (PoolFix)(Pool pool, ScanState ss, Seg seg, Addr *refIO)
405{
406 AVERT(Pool, pool);
407 AVERT(ScanState, ss);
408 AVERT(Seg, seg);
409 AVER(pool == SegPool(seg));
410 AVER(refIO != NULL);
411
412 /* Should only be fixing references to white segments. */
413 AVER(TraceSetInter(SegWhite(seg), ss->traces) != TraceSetEMPTY);
414
415 return PoolFix(pool, ss, seg, refIO);
416}
417
418void PoolFixEmergency(Pool pool, ScanState ss, Seg seg, Addr *refIO)
419{
420 Res res;
421
422 AVERT(Pool, pool);
423 AVERT(ScanState, ss);
424 AVERT(Seg, seg);
425 AVER(pool == SegPool(seg));
426 AVER(refIO != NULL);
427
428 /* Should only be fixing references to white segments. */
429 AVER(TraceSetInter(SegWhite(seg), ss->traces) != TraceSetEMPTY);
430
431 res = (pool->class->fixEmergency)(pool, ss, seg, refIO);
432 AVER(res == ResOK);
433}
434
435
436/* PoolReclaim -- reclaim a segment in the pool */
437
438void PoolReclaim(Pool pool, Trace trace, Seg seg)
439{
440 AVERT_CRITICAL(Pool, pool);
441 AVERT_CRITICAL(Trace, trace);
442 AVERT_CRITICAL(Seg, seg);
443 AVER_CRITICAL(pool->arena == trace->arena);
444 AVER_CRITICAL(SegPool(seg) == pool);
445
446 /* There shouldn't be any grey things left for this trace. */
447 AVER_CRITICAL(!TraceSetIsMember(SegGrey(seg), trace));
448 /* Should only be reclaiming segments which are still white. */
449 AVER_CRITICAL(TraceSetIsMember(SegWhite(seg), trace));
450
451 (*pool->class->reclaim)(pool, trace, seg);
452}
453
454
455/* PoolWalk -- walk objects in this pool */
456
457void PoolWalk(Pool pool, Seg seg, FormattedObjectsStepMethod f,
458 void *p, Size s)
459{
460 AVERT(Pool, pool);
461 AVERT(Seg, seg);
462 AVER(FUNCHECK(f));
463 /* p and s are arbitrary values, hence can't be checked. */
464
465 (*pool->class->walk)(pool, seg, f, p, s);
466}
467
468
469/* PoolDescribe -- describe a pool */
470
471Res PoolDescribe(Pool pool, mps_lib_FILE *stream)
472{
473 Res res;
474 Ring node, nextNode;
475
476 if (!CHECKT(Pool, pool)) return ResFAIL;
477 if (stream == NULL) return ResFAIL;
478
479 res = WriteF(stream,
480 "Pool $P ($U) {\n", (WriteFP)pool, (WriteFU)pool->serial,
481 " class $P (\"$S\")\n",
482 (WriteFP)pool->class, pool->class->name,
483 " arena $P ($U)\n",
484 (WriteFP)pool->arena, (WriteFU)pool->arena->serial,
485 " alignment $W\n", (WriteFW)pool->alignment,
486 NULL);
487 if (res != ResOK) return res;
488 if (NULL != pool->format) {
489 res = FormatDescribe(pool->format, stream);
490 if (res != ResOK) return res;
491 }
492 res = WriteF(stream,
493 " fillMutatorSize $UKb\n",
494 (WriteFU)(pool->fillMutatorSize / 1024),
495 " emptyMutatorSize $UKb\n",
496 (WriteFU)(pool->emptyMutatorSize / 1024),
497 " fillInternalSize $UKb\n",
498 (WriteFU)(pool->fillInternalSize / 1024),
499 " emptyInternalSize $UKb\n",
500 (WriteFU)(pool->emptyInternalSize / 1024),
501 NULL);
502 if (res != ResOK) return res;
503
504 res = (*pool->class->describe)(pool, stream);
505 if (res != ResOK) return res;
506
507 RING_FOR(node, &pool->bufferRing, nextNode) {
508 Buffer buffer = RING_ELT(Buffer, poolRing, node);
509 res = BufferDescribe(buffer, stream);
510 if (res != ResOK) return res;
511 }
512
513 res = WriteF(stream,
514 "} Pool $P ($U)\n", (WriteFP)pool, (WriteFU)pool->serial,
515 NULL);
516 if (res != ResOK) return res;
517
518 return ResOK;
519}
520
521
522/* PoolFormat
523 *
524 * Returns the format of the pool (the format of objects in the pool).
525 * If the pool is unformatted or doesn't declare a format then this
526 * function returns FALSE and does not update *formatReturn. Otherwise
527 * this function returns TRUE and *formatReturn is updated to be the
528 * pool's format. */
529
530Bool PoolFormat(Format *formatReturn, Pool pool)
531{
532 AVER(formatReturn != NULL);
533 AVERT(Pool, pool);
534
535 if (pool->format) {
536 *formatReturn = pool->format;
537 return TRUE;
538 }
539 return FALSE;
540}
541
542
543/* PoolOfAddr -- return the pool containing the given address
544 *
545 * If the address points to a page assigned to a pool, this returns TRUE
546 * and sets *poolReturn to that pool. Otherwise, it returns FALSE, and
547 * *poolReturn is unchanged. */
548
549Bool PoolOfAddr(Pool *poolReturn, Arena arena, Addr addr)
550{
551 Tract tract;
552
553 AVER(poolReturn != NULL);
554 AVERT(Arena, arena);
555
556 if (TractOfAddr(&tract, arena, addr)) {
557 *poolReturn = TractPool(tract);
558 return TRUE;
559 }
560
561 return FALSE;
562}
563
564
565Bool PoolHasAddr(Pool pool, Addr addr)
566{
567 Pool addrPool;
568 Arena arena;
569 Bool managed;
570
571 AVERT(Pool, pool);
572
573 arena = PoolArena(pool);
574 managed = PoolOfAddr(&addrPool, arena, addr);
575 return (managed && addrPool == pool);
576}