1 /* -*- Mode: C; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the Mozilla Public License Version 2.0.
7 // See license.mkd for licensing and copyright information.
8 // -------------------------------------------------------------------------*/
13 #include "sjme/alloc.h"
17 /** The number of links to allocate. */
20 /** The number of which sequences. */
21 #define NUM_WHICH (NUM_LINKS + 3)
23 /** Identifier for the front link. */
24 #define FRONT (NUM_LINKS + 1)
26 /** Identifier for the back link. */
27 #define BACK (NUM_LINKS + 2)
29 /** Identifier of the end of link list. */
35 /** The mask for removing free. */
38 /** The scenarios available. */
39 typedef enum testScenarioId
42 sjme_attrUnusedEnum(SCENARIO_LMR
),
44 /** Left, Right, then middle. */
45 sjme_attrUnusedEnum(SCENARIO_LRM
),
47 /** Middle, then left to right. */
48 sjme_attrUnusedEnum(SCENARIO_MLR
),
50 /** Middle, then right to left. */
51 sjme_attrUnusedEnum(SCENARIO_MRL
),
54 sjme_attrUnusedEnum(SCENARIO_RML
),
56 /** Right, left, then middle. */
57 sjme_attrUnusedEnum(SCENARIO_RLM
),
59 /** The number of scenarios. */
63 /** The sequence of links. */
64 typedef struct testSequenceType
66 /** The number of used links. */
69 /** The number of free links. */
72 /** Which links are on the entire chain? */
73 sjme_jint which
[NUM_WHICH
];
76 /** The order of the links. */
77 typedef struct testOrderType
79 /** The order used. */
80 sjme_jint order
[NUM_LINKS
];
82 /** How many there should be after being freed. */
83 testSequenceType sequence
[NUM_LINKS
];
86 /** The actual order to use. */
87 const testOrderType testLinkOrder
[NUM_SCENARIO
] =
93 {FRONT
, 0 | FREE
, 1, 2, BACK
,
96 {FRONT
, 0 | FREE
, 2, BACK
,
99 {FRONT
, 0 | FREE
, BACK
,
107 {FRONT
, 0 | FREE
, 1, 2, BACK
,
110 {FRONT
, 0 | FREE
, 1, 2 | FREE
, BACK
,
113 {FRONT
, 0 | FREE
, BACK
,
121 {FRONT
, 0, 1 | FREE
, 2, BACK
,
124 {FRONT
, 0 | FREE
, 2, BACK
,
127 {FRONT
, 0 | FREE
, BACK
,
135 {FRONT
, 0, 1 | FREE
, 2, BACK
,
138 {FRONT
, 0, 1 | FREE
, BACK
,
141 {FRONT
, 0 | FREE
, BACK
,
149 {FRONT
, 0, 1, 2 | FREE
, BACK
,
152 {FRONT
, 0, 1 | FREE
, BACK
,
155 {FRONT
, 0 | FREE
, BACK
,
163 {FRONT
, 0, 1, 2 | FREE
, BACK
,
166 {FRONT
, 0 | FREE
, 1, 2 | FREE
, BACK
,
169 {FRONT
, 0 | FREE
, BACK
,
175 static void dumpPool(sjme_alloc_pool
* pool
, sjme_lpcstr what
)
177 sjme_alloc_link
* rover
;
181 sjme_message("---------------------------------------------");
182 for (rover
= pool
->frontLink
,
183 x
= 0; rover
!= NULL
; rover
= rover
->next
, x
++)
185 sjme_message("%s %d: @%p %s %d/%d bytes",
186 what
, x
, rover
, (rover
->space
== SJME_ALLOC_POOL_SPACE_FREE
?
187 "FREE" : (rover
->space
== SJME_ALLOC_POOL_SPACE_USED
?
189 rover
->allocSize
, rover
->blockSize
);
191 sjme_message("---------------------------------------------");
195 * Tests merging of allocation blocks when freeing them accordingly.
199 SJME_TEST_DECLARE(testAllocFreeMerge
)
202 sjme_jboolean isLast
, isFree
, wantFree
;
203 sjme_jint chunkLen
, linkNum
, scenario
, numUsed
, numFree
, x
, atId
;
205 sjme_alloc_link
* link
;
206 sjme_alloc_pool
* pool
;
207 sjme_alloc_link
* rover
;
209 sjme_pointer blocks
[NUM_WHICH
];
210 sjme_alloc_link
* links
[NUM_WHICH
];
211 const testOrderType
* order
;
212 const testSequenceType
* sequence
;
214 /* Allocate data on the stack so it gets cleared. */
216 chunk
= sjme_alloca(chunkLen
);
218 return sjme_unit_skip(test
, "Could not alloca(%d).",
221 /* Use multiple scenarios regarding the order of blocks to free. */
222 for (scenario
= 0; scenario
< NUM_SCENARIO
; scenario
++)
224 /* Get the order data. */
225 order
= &testLinkOrder
[scenario
];
227 /* Initialize the pool. */
229 if (sjme_error_is(sjme_alloc_poolInitStatic(&pool
,
230 chunk
, chunkLen
)) || pool
== NULL
)
231 return sjme_unit_fail(test
, "Could not initialize static pool?");
233 /* Cleanup for run. */
234 memset(&blocks
, 0, sizeof(blocks
));
235 memset(&links
, 0, sizeof(links
));
237 /* Allocate each of the links. */
238 for (linkNum
= 0; linkNum
< NUM_LINKS
; linkNum
++)
240 /* Is this the last link? */
241 isLast
= linkNum
>= (NUM_LINKS
- 1);
244 sjme_message("Link %d of %d (last? %d)",
245 (linkNum
+ 1), NUM_LINKS
, isLast
);
247 /* Allocate block. */
248 blocks
[linkNum
] = NULL
;
249 if (sjme_error_is(sjme_alloc(pool
,
250 pool
->space
[SJME_ALLOC_POOL_SPACE_FREE
].usable
/
252 &blocks
[linkNum
])) || blocks
[linkNum
] == NULL
)
253 return sjme_unit_fail(test
, "Could not allocate link?");
256 links
[linkNum
] = NULL
;
257 if (sjme_error_is(sjme_alloc_getLink(blocks
[linkNum
],
258 &links
[linkNum
])) || links
[linkNum
] == NULL
)
259 return sjme_unit_fail(test
, "Could not get link?");
261 /* The last block should claim all the free space. */
263 sjme_unit_equalI(test
,
264 0, pool
->space
[SJME_ALLOC_POOL_SPACE_FREE
].usable
,
265 "All of the free space was not taken?");
268 /* Seed front and back links which are constant. */
269 links
[FRONT
] = pool
->frontLink
;
270 links
[BACK
] = pool
->backLink
;
272 /* Free the links in the specified order and test the result. */
273 for (linkNum
= 0; linkNum
< NUM_LINKS
; linkNum
++)
275 /* Get the sequence from the order. */
276 sequence
= &order
->sequence
[linkNum
];
278 /* Which link is this? */
279 block
= blocks
[order
->order
[linkNum
]];
280 link
= links
[order
->order
[linkNum
]];
283 dumpPool(pool
, "BEFORE FREE");
286 if (sjme_error_is(sjme_alloc_free(block
)))
287 return sjme_unit_fail(test
, "Could not free link.");
290 dumpPool(pool
, "AFTER FREE");
292 /* Go through the entire chain. */
293 numUsed
= numFree
= 0;
294 rover
= pool
->frontLink
;
295 for (x
= 0; x
< NUM_WHICH
; x
++)
297 /* End of list? Stop. */
298 if (sequence
->which
[x
] == END
)
301 /* Get the link this is. */
302 atId
= sequence
->which
[x
] & FREE_MASK
;
305 /* Must be this one. */
306 sjme_unit_equalP(test
, rover
, at
,
307 "Incorrect pointer %p != %p... %d.%d.%d?",
308 rover
, at
, scenario
, linkNum
, x
);
310 /* Is the block free or not? */
311 if (atId
!= FRONT
&& atId
!= BACK
)
313 /* Is this block free? */
314 isFree
= (rover
->space
== SJME_ALLOC_POOL_SPACE_FREE
);
316 /* The freeness should match. */
317 wantFree
= ((sequence
->which
[x
] & FREE
) != 0);
318 sjme_unit_equalI(test
,
320 "Incorrect freeness %d.%d.%d?", scenario
, linkNum
, x
);
329 /* Go the next link. */
333 /* Free and used counts should match. */
334 sjme_unit_equalI(test
, numFree
, sequence
->numFree
,
335 "Free match incorrect %d.%d?", scenario
, linkNum
);
336 sjme_unit_equalI(test
, numUsed
, sequence
->numUsed
,
337 "Free match incorrect %d.%d?", scenario
, linkNum
);
342 return SJME_TEST_RESULT_PASS
;