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 // -------------------------------------------------------------------------*/
11 #include "sjme/alloc.h"
15 /** The number of links to allocate. */
18 /** The number of which sequences. */
19 #define NUM_WHICH (NUM_LINKS + 3)
21 /** Identifier for the front link. */
22 #define FRONT (NUM_LINKS + 1)
24 /** Identifier for the back link. */
25 #define BACK (NUM_LINKS + 2)
27 /** Identifier of the end of link list. */
33 /** The mask for removing free. */
36 /** The scenarios available. */
37 typedef enum testScenarioId
40 sjme_attrUnusedEnum(SCENARIO_LMR
),
42 /** Left, Right, then middle. */
43 sjme_attrUnusedEnum(SCENARIO_LRM
),
45 /** Middle, then left to right. */
46 sjme_attrUnusedEnum(SCENARIO_MLR
),
48 /** Middle, then right to left. */
49 sjme_attrUnusedEnum(SCENARIO_MRL
),
52 sjme_attrUnusedEnum(SCENARIO_RML
),
54 /** Right, left, then middle. */
55 sjme_attrUnusedEnum(SCENARIO_RLM
),
57 /** The number of scenarios. */
61 /** The sequence of links. */
62 typedef struct testSequenceType
64 /** The number of used links. */
67 /** The number of free links. */
70 /** Which links are on the entire chain? */
71 sjme_jint which
[NUM_WHICH
];
74 /** The order of the links. */
75 typedef struct testOrderType
77 /** The order used. */
78 sjme_jint order
[NUM_LINKS
];
80 /** How many there should be after being freed. */
81 testSequenceType sequence
[NUM_LINKS
];
84 /** The actual order to use. */
85 const testOrderType testLinkOrder
[NUM_SCENARIO
] =
91 {FRONT
, 0 | FREE
, 1, 2, BACK
,
94 {FRONT
, 0 | FREE
, 2, BACK
,
97 {FRONT
, 0 | FREE
, BACK
,
105 {FRONT
, 0 | FREE
, 1, 2, BACK
,
108 {FRONT
, 0 | FREE
, 1, 2 | FREE
, BACK
,
111 {FRONT
, 0 | FREE
, BACK
,
119 {FRONT
, 0, 1 | FREE
, 2, BACK
,
122 {FRONT
, 0 | FREE
, 2, BACK
,
125 {FRONT
, 0 | FREE
, BACK
,
133 {FRONT
, 0, 1 | FREE
, 2, BACK
,
136 {FRONT
, 0, 1 | FREE
, BACK
,
139 {FRONT
, 0 | FREE
, BACK
,
147 {FRONT
, 0, 1, 2 | FREE
, BACK
,
150 {FRONT
, 0, 1 | FREE
, BACK
,
153 {FRONT
, 0 | FREE
, BACK
,
161 {FRONT
, 0, 1, 2 | FREE
, BACK
,
164 {FRONT
, 0 | FREE
, 1, 2 | FREE
, BACK
,
167 {FRONT
, 0 | FREE
, BACK
,
174 * Tests merging of allocation blocks when freeing them accordingly.
178 SJME_TEST_DECLARE(testAllocFreeMerge
)
181 sjme_jboolean isLast
, isFree
, wantFree
;
182 sjme_jint chunkLen
, linkNum
, scenario
, numUsed
, numFree
, x
, atId
;
184 sjme_alloc_link
* link
;
185 sjme_alloc_pool
* pool
;
186 sjme_alloc_link
* rover
;
188 void* blocks
[NUM_LINKS
];
189 sjme_alloc_link
* links
[NUM_WHICH
];
190 const testOrderType
* order
;
191 const testSequenceType
* sequence
;
193 /* Allocate data on the stack so it gets cleared. */
195 chunk
= sjme_alloca(chunkLen
);
197 return sjme_unit_skip(test
, "Could not alloca(%d).",
200 /* Use multiple scenarios regarding the order of blocks to free. */
201 for (scenario
= 0; scenario
< NUM_SCENARIO
; scenario
++)
203 /* Get the order data. */
204 order
= &testLinkOrder
[scenario
];
206 /* Initialize the pool. */
208 if (sjme_error_is(sjme_alloc_poolInitStatic(&pool
,
209 chunk
, chunkLen
)) || pool
== NULL
)
210 return sjme_unit_fail(test
, "Could not initialize static pool?");
212 /* Allocate each of the links. */
213 for (linkNum
= 0; linkNum
< NUM_LINKS
; linkNum
++)
215 /* Is this the last link? */
216 isLast
= linkNum
>= (NUM_LINKS
- 1);
219 sjme_message("Link %d of %d (last? %d)",
220 (linkNum
+ 1), NUM_LINKS
, isLast
);
222 /* Allocate block. */
223 blocks
[linkNum
] = NULL
;
224 if (sjme_error_is(sjme_alloc(pool
,
225 pool
->space
[SJME_ALLOC_POOL_SPACE_FREE
].usable
/
227 &blocks
[linkNum
])) || blocks
[linkNum
] == NULL
)
228 return sjme_unit_fail(test
, "Could not allocate link?");
231 links
[linkNum
] = NULL
;
232 if (sjme_error_is(sjme_alloc_getLink(blocks
[linkNum
],
233 &links
[linkNum
])) || links
[linkNum
] == NULL
)
234 return sjme_unit_fail(test
, "Could not get link?");
236 /* The last block should claim all the free space. */
238 sjme_unit_equalI(test
,
239 0, pool
->space
[SJME_ALLOC_POOL_SPACE_FREE
].usable
,
240 "All of the free space was not taken?");
243 /* Seed front and back links which are constant. */
244 links
[FRONT
] = pool
->frontLink
;
245 links
[BACK
] = pool
->backLink
;
247 /* Free the links in the specified order and test the result. */
248 for (linkNum
= 0; linkNum
< NUM_LINKS
; linkNum
++)
250 /* Get the sequence from the order. */
251 sequence
= &order
->sequence
[linkNum
];
253 /* Which link is this? */
254 block
= blocks
[order
->order
[linkNum
]];
255 link
= links
[order
->order
[linkNum
]];
258 if (sjme_error_is(sjme_alloc_free(block
)))
259 return sjme_unit_fail(test
, "Could not free link.");
261 /* Go through the entire chain. */
262 numUsed
= numFree
= 0;
263 rover
= pool
->frontLink
;
264 for (x
= 0; x
< NUM_WHICH
; x
++)
266 /* End of list? Stop. */
267 if (sequence
->which
[x
] == END
)
270 /* Get the link this is. */
271 atId
= x
& FREE_MASK
;
272 at
= links
[sequence
->which
[atId
]];
274 /* Must be this one. */
275 sjme_unit_equalP(test
, rover
, at
,
276 "Incorrect sequence %d.%d.%d?", scenario
, linkNum
, x
);
278 /* Is the block free or not? */
279 if (atId
!= FRONT
&& atId
!= BACK
)
281 /* Is this block free? */
282 isFree
= (rover
->space
== SJME_ALLOC_POOL_SPACE_FREE
);
284 /* The freeness should match. */
285 wantFree
= !!(sequence
->which
[atId
] & FREE
);
286 sjme_unit_equalI(test
,
288 "Incorrect freeness %d.%d.%d?", scenario
, linkNum
, x
);
297 /* Go the next link. */
301 /* Free and used counts should match. */
302 sjme_unit_equalI(test
, numFree
, sequence
->numFree
,
303 "Free match incorrect %d.%d?", scenario
, linkNum
);
304 sjme_unit_equalI(test
, numUsed
, sequence
->numUsed
,
305 "Free match incorrect %d.%d?", scenario
, linkNum
);
310 return SJME_TEST_RESULT_PASS
;